diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-22 02:04:18 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-22 02:04:18 +0000 |
| commit | fd555f6b1fd950eff620e74da887dc37d919a276 (patch) | |
| tree | 3c3ce70944db709410b9c1753550d399b57aae6c /clang/test/CXX | |
| parent | 3715c691b3f4e88d05ae92d7b831cfceb5865285 (diff) | |
| download | bcm5719-llvm-fd555f6b1fd950eff620e74da887dc37d919a276.tar.gz bcm5719-llvm-fd555f6b1fd950eff620e74da887dc37d919a276.zip | |
Implement C++11 [expr.call]p11: If the operand to a decltype-specifier is a
function call (or a comma expression with a function call on its right-hand
side), possibly parenthesized, then the return type is not required to be
complete and a temporary is not bound. Other subexpressions inside a decltype
expression do not get this treatment.
This is implemented by deferring the relevant checks for all calls immediately
within a decltype expression, then, when the expression is fully-parsed,
checking the relevant constraints and stripping off any top-level temporary
binding.
Deferring the completion of the return type exposed a bug in overload
resolution where completion of the argument types was not attempted, which
is also fixed by this change.
llvm-svn: 151117
Diffstat (limited to 'clang/test/CXX')
| -rw-r--r-- | clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp new file mode 100644 index 00000000000..2bd5d234ce7 --- /dev/null +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +namespace std_example { + +template<class T> struct A { ~A() = delete; }; // expected-note {{deleted here}} +template<class T> auto h() -> A<T>; +template<class T> auto i(T) -> T; +template<class T> auto f(T) -> decltype(i(h<T>())); // #1 +template<class T> auto f(T) -> void; // #2 +auto g() -> void { + f(42); // ok, calls #2, since #1 is not viable. +} +template<class T> auto q(T) -> decltype((h<T>())); +void r() { + // Deduction against q succeeds, but results in a temporary which can't be + // destroyed. + q(42); // expected-error {{attempt to use a deleted function}} +} + +} + +class PD { + friend struct A; + ~PD(); // expected-note 4{{here}} +public: + typedef int n; +}; +struct DD { + ~DD() = delete; // expected-note 2{{here}} + typedef int n; +}; + +struct A { + decltype(PD()) s; // ok + decltype(PD())::n n; // ok + decltype(DD()) *p = new decltype(DD()); // ok +}; + +// Two errors here: one for the decltype, one for the variable. +decltype(PD(), PD()) pd1; // expected-error 2{{private destructor}} +decltype(DD(), DD()) dd1; // expected-error 2{{deleted function}} + +decltype(((13, ((DD())))))::n dd_parens; // ok +decltype(((((42)), PD())))::n pd_parens_comma; // ok + +// Ensure parens aren't stripped from a decltype node. +extern decltype(PD()) pd_ref; // ok +decltype((pd_ref)) pd_ref3 = pd_ref; // ok, PD & +decltype(pd_ref) pd_ref2 = pd_ref; // expected-error {{private destructor}} + +namespace libcxx_example { + struct nat { + nat() = delete; + nat(const nat&) = delete; + nat &operator=(const nat&) = delete; + ~nat() = delete; + }; + struct any { + any(...); + }; + + template<typename T, typename U> struct is_same { static const bool value = false; }; + template<typename T> struct is_same<T, T> { static const bool value = true; }; + + template<typename T> T declval(); + + void swap(int &a, int &b); + nat swap(any, any); + + template<typename T> struct swappable { + typedef decltype(swap(declval<T&>(), declval<T&>())) type; + static const bool value = !is_same<type, nat>::value; + constexpr operator bool() { return value; } + }; + + static_assert(swappable<int>(), ""); + static_assert(!swappable<const int>(), ""); +} + +namespace RequireCompleteType { + template<int N, bool OK> struct S { + static_assert(OK, "boom!"); // expected-error 2{{boom!}} + }; + + template<typename T> T make(); + template<int N, bool OK> S<N, OK> make(); + void consume(...); + + decltype(make<0, false>()) *p1; // ok + decltype((make<1, false>())) *p2; // ok + + // A complete type is required here in order to detect an overloaded 'operator,'. + decltype(123, make<2, false>()) *p3; // expected-note {{here}} + + decltype(consume(make<3, false>())) *p4; // expected-note {{here}} + + decltype(make<decltype(make<4, false>())>()) *p5; // ok +} + +namespace Overload { + DD operator+(PD &a, PD &b); + decltype(PD()) *pd_ptr; + decltype(*pd_ptr + *pd_ptr) *dd_ptr; // ok + + decltype(0, *pd_ptr) pd_ref2 = pd_ref; // ok + DD operator,(int a, PD b); + decltype(0, *pd_ptr) *dd_ptr2; // expected-error {{private destructor}} +} |

