mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-26 03:15:19 +00:00
Add documentation and tests for Clangs C++11 extensions in C++03.
As we gear up to drop support for GCC in C++03, we should make clear what our C++03 mode is, the C++11 extensions it provides, and the C++11 extensions it depends on. The section of this document discussing user-facing extensions has been left blank while the community discusses new directions. For now it's just a warning to users. Additionally, the document contains examples of how these extensions should be used and why. For example, using alias templates over class templates. llvm-svn: 363110
This commit is contained in:
parent
6691f1b6cd
commit
4959542657
118
libcxx/docs/DesignDocs/ExtendedCXX03Support.rst
Normal file
118
libcxx/docs/DesignDocs/ExtendedCXX03Support.rst
Normal file
@ -0,0 +1,118 @@
|
||||
=======================
|
||||
Extended C++03 Support
|
||||
=======================
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
libc++ is an implementation of the C++ standard library targeting C++11 or later.
|
||||
|
||||
In C++03, the library implements the C++11 standard using C++11 language extensions provided
|
||||
by Clang.
|
||||
|
||||
This document tracks the C++11 extensions libc++ requires, the C++11 extensions it provides,
|
||||
and how to write minimal C++11 inside libc++.
|
||||
|
||||
Required C++11 Compiler Extensions
|
||||
==================================
|
||||
|
||||
Clang provides a large subset of C++11 in C++03 as an extension. The features
|
||||
libc++ expects Clang to provide are:
|
||||
|
||||
* Variadic templates.
|
||||
* RValue references and perfect forwarding.
|
||||
* Alias templates
|
||||
* defaulted and deleted Functions.
|
||||
* reference qualified Functions
|
||||
|
||||
There are also features that Clang *does not* provide as an extension in C++03
|
||||
mode. These include:
|
||||
|
||||
* ``constexpr`` and ``noexcept``
|
||||
* ``auto``
|
||||
* Trailing return types.
|
||||
* ``>>`` without a space.
|
||||
|
||||
|
||||
Provided C++11 Library Extensions
|
||||
=================================
|
||||
|
||||
.. warning::
|
||||
The C++11 extensions libc++ provides in C++03 are currently undergoing change. Existing extensions
|
||||
may be removed in the future. New users are strongly discouraged depending on these extension
|
||||
in new code.
|
||||
|
||||
This section will be updated once the libc++ developer community has further discussed the
|
||||
future of C++03 with libc++.
|
||||
|
||||
|
||||
Using Minimal C++11 in libc++
|
||||
=============================
|
||||
|
||||
This section is for developers submitting patches to libc++. It describes idioms that should be
|
||||
used in libc++ code, even in C++03, and the reasons behind them.
|
||||
|
||||
|
||||
Use Alias Templates over Class Templates
|
||||
----------------------------------------
|
||||
|
||||
Alias templates should be used instead of class templates in metaprogramming. Unlike class templates,
|
||||
Alias templates do not produce a new instantiation every time they are used. This significantly
|
||||
decreases the amount of memory used by the compiler.
|
||||
|
||||
For example, libc++ should not use ``add_const`` internally. Instead it should use an alias template
|
||||
like
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <class _Tp>
|
||||
using _AddConst = const _Tp;
|
||||
|
||||
Use Default Template Parameters for SFINAE
|
||||
------------------------------------------
|
||||
|
||||
There are three places in a function declaration that SFINAE may occur: In the template parameter list,
|
||||
in the function parameter list, and in the return type. For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <class _Tp, class _ = enable_if_t</*...*/ >
|
||||
void foo(_Tp); // #1
|
||||
|
||||
template <class _Tp>
|
||||
void bar(_Tp, enable_if_t</*...*/>* = nullptr); // # 2
|
||||
|
||||
template <class _Tp>
|
||||
enable_if_t</*...*/> baz(_Tp); // # 3
|
||||
|
||||
Using default template parameters for SFINAE (#1) should always be prefered.
|
||||
|
||||
Option #2 has two problems. First, users can observe and accidentally pass values to the SFINAE
|
||||
function argument. Second, the default arguement creates a live variable, which causes debug
|
||||
information to be emitted containing the text of the SFINAE.
|
||||
|
||||
Option #3 can also cause more debug information to be emitted than is needed, because the function
|
||||
return type will appear in the debug information.
|
||||
|
||||
Use ``unique_ptr`` when allocating memory
|
||||
------------------------------------------
|
||||
|
||||
The standard library often needs to allocate memory and then construct a user type in it.
|
||||
If the users constructor throws, the library needs to deallocate that memory. The idiomatic way to
|
||||
achieve this is with ``unique_ptr``.
|
||||
|
||||
``__builtin_new_allocator`` is an example of this idiom. Example usage would look like:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <class T>
|
||||
T* __create() {
|
||||
using _UniquePtr = unique_ptr<void*, __default_new_allocator::__default_new_deleter>;
|
||||
_UniquePtr __p = __default_new_allocator::__allocate_bytes(sizeof(T), alignof(T));
|
||||
T* __res = ::new(__p.get()) T();
|
||||
(void)__p.release();
|
||||
return __res;
|
||||
}
|
@ -142,6 +142,7 @@ Design Documents
|
||||
DesignDocs/ThreadingSupportAPI
|
||||
DesignDocs/FileTimeType
|
||||
DesignDocs/FeatureTestMacros
|
||||
DesignDocs/ExtendedCXX03Support
|
||||
|
||||
* `<atomic> design <http://libcxx.llvm.org/atomic_design.html>`_
|
||||
* `<type_traits> design <http://libcxx.llvm.org/type_traits_design.html>`_
|
||||
|
135
libcxx/test/libcxx/minimal_cxx11_configuration.pass.cpp
Normal file
135
libcxx/test/libcxx/minimal_cxx11_configuration.pass.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// Test the set of C++11 features that Clang provides as an extension in C++03 mode.
|
||||
// The language features we expect are:
|
||||
//
|
||||
// 1. rvalue references (and perfect forwarding)
|
||||
// 2. variadic templates
|
||||
// 3. alias templates
|
||||
// 4. defaulted and deleted functions.
|
||||
// 5. default values for non-type template parameters.
|
||||
//
|
||||
// Some features we don't get and can't be used in extended C++03 mode:
|
||||
//
|
||||
// 1. noexcept and constexpr
|
||||
// 2. Two closing '>' without a space.
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
// Equals delete and default are allowed in minimal C++03 mode.
|
||||
namespace test_eq_delete_and_default {
|
||||
void t1() = delete;
|
||||
struct T2 {
|
||||
T2() = default;
|
||||
T2(T2 const&) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
namespace alias_templates {
|
||||
template <class T>
|
||||
using X = T;
|
||||
static_assert((std::is_same<X<int>, int>::value), "");
|
||||
}
|
||||
|
||||
namespace variadics_templates {
|
||||
template <class ...Args>
|
||||
int t1(Args...) {
|
||||
return sizeof...(Args);
|
||||
}
|
||||
void test() {
|
||||
assert(t1() == 0);
|
||||
assert(t1(42) == 1);
|
||||
assert(t1(1, 2, 3) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
namespace rvalue_references_move_semantics {
|
||||
struct T {
|
||||
T() : moved(0) {}
|
||||
T(T const& other) : moved(other.moved) {}
|
||||
T(T&& other) : moved(other.moved) { ++moved; other.moved = -1; }
|
||||
int moved;
|
||||
};
|
||||
void f(T o, int expect_moved) { assert(o.moved == expect_moved); }
|
||||
void test() {
|
||||
{
|
||||
T t;
|
||||
assert(t.moved == 0);
|
||||
T t2(static_cast<T&&>(t));
|
||||
assert(t2.moved == 1);
|
||||
assert(t.moved == -1);
|
||||
}
|
||||
{
|
||||
T t;
|
||||
f(t, 0);
|
||||
f(static_cast<T&&>(t), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace rvalue_references_perfect_forwarding {
|
||||
template <class Expect, class T>
|
||||
void f(T&&) {
|
||||
static_assert((std::is_same<Expect, T&&>::value), "");
|
||||
}
|
||||
void test() {
|
||||
int x = 42;
|
||||
f<int&>(x);
|
||||
f<int&&>(42);
|
||||
f<int&&>(static_cast<int&&>(x));
|
||||
}
|
||||
}
|
||||
|
||||
namespace default_values_for_nttp {
|
||||
template <int I = 42>
|
||||
void f() { assert(I == 42); }
|
||||
void test() {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
namespace reference_qualified_functions {
|
||||
struct T {
|
||||
T() : lvalue_called(0), rvalue_called(0) {}
|
||||
void foo() const & { lvalue_called++; }
|
||||
void foo() && { rvalue_called++; }
|
||||
mutable int lvalue_called;
|
||||
int rvalue_called;
|
||||
};
|
||||
|
||||
void test() {
|
||||
{
|
||||
T t;
|
||||
t.foo();
|
||||
assert(t.lvalue_called == 1);
|
||||
assert(t.rvalue_called == 0);
|
||||
}
|
||||
{
|
||||
T t;
|
||||
static_cast<T&&>(t).foo();
|
||||
assert(t.lvalue_called == 0);
|
||||
assert(t.rvalue_called == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
variadics_templates::test();
|
||||
rvalue_references_move_semantics::test();
|
||||
rvalue_references_perfect_forwarding::test();
|
||||
default_values_for_nttp::test();
|
||||
reference_qualified_functions::test();
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user