diff options
Diffstat (limited to 'clang/test/CXX/dcl.decl')
| -rw-r--r-- | clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp | 22 | ||||
| -rw-r--r-- | clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp | 203 | ||||
| -rw-r--r-- | clang/test/CXX/dcl.decl/dcl.decomp/p4.cpp | 173 |
3 files changed, 398 insertions, 0 deletions
diff --git a/clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp b/clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp new file mode 100644 index 00000000000..cd0518bfc59 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +int array() { + int arr[3] = {}; + // FIXME: We are supposed to create an array object here and perform elementwise initialization. + auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}} + + auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}} + auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}} + + auto &[r0, r1, r2] = arr; + const auto &[cr0, cr1, cr2] = arr; + + //static_assert(&arr[0] == &r0); + //static_assert(&arr[0] == &cr0); + using T = int; + using T = decltype(r0); + using U = const int; + using U = decltype(cr0); + + return r1 + cr2; +} diff --git a/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp new file mode 100644 index 00000000000..1acf391c9f3 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +using size_t = decltype(sizeof(0)); + +struct A { int x, y; }; +struct B { int x, y; }; + +void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise + +namespace std { template<typename T> struct tuple_size; } +void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise + +struct Bad1 {}; +template<> struct std::tuple_size<Bad1> {}; +void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad1>::value' is not a valid integral constant expression}} + +struct Bad2 {}; +template<> struct std::tuple_size<Bad2> { const int value = 5; }; +void no_tuple_size_4() { auto [x, y] = Bad2(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad2>::value' is not a valid integral constant expression}} + +template<> struct std::tuple_size<A> { static const int value = 3; }; +template<> struct std::tuple_size<B> { enum { value = 3 }; }; + +void no_get_1() { + { + auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}} + auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}} + } + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +int get(A); + +void no_get_2() { + // FIXME: This diagnostic is not great. + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +template<int> float &get(A); + +void no_tuple_element_1() { + auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}, A>::type' does not name a type}} expected-note {{in implicit}} +} + +namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}} + +void no_tuple_element_2() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<0, A> { typedef float type; }; + +void no_tuple_element_3() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<1, A> { typedef float &type; }; +template<> struct std::tuple_element<2, A> { typedef const float &type; }; + +template<int N> auto get(B) -> int (&)[N + 1]; +template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; }; + +template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {}; +template<size_t N, typename T> struct std::tuple_element<N, const T> { + typedef const typename std::tuple_element<N, T>::type type; +}; + +void referenced_type() { + auto [a0, a1, a2] = A(); + auto [b0, b1, b2] = B(); + + A a; + B b; + auto &[ar0, ar1, ar2] = a; + auto &[br0, br1, br2] = b; + + auto &&[arr0, arr1, arr2] = A(); + auto &&[brr0, brr1, brr2] = B(); + + const auto &[acr0, acr1, acr2] = A(); + const auto &[bcr0, bcr1, bcr2] = B(); + + + using Float = float; + using Float = decltype(a0); + using Float = decltype(ar0); + using Float = decltype(arr0); + + using ConstFloat = const float; + using ConstFloat = decltype(acr0); + + using FloatRef = float&; + using FloatRef = decltype(a1); + using FloatRef = decltype(ar1); + using FloatRef = decltype(arr1); + using FloatRef = decltype(acr1); + + using ConstFloatRef = const float&; + using ConstFloatRef = decltype(a2); + using ConstFloatRef = decltype(ar2); + using ConstFloatRef = decltype(arr2); + using ConstFloatRef = decltype(acr2); + + + using Int1 = int[1]; + using Int1 = decltype(b0); + using Int1 = decltype(br0); + using Int1 = decltype(brr0); + + using ConstInt1 = const int[1]; + using ConstInt1 = decltype(bcr0); + + using Int2 = int[2]; + using Int2 = decltype(b1); + using Int2 = decltype(br1); + using Int2 = decltype(brr1); + + using ConstInt2 = const int[2]; + using ConstInt2 = decltype(bcr1); + + using Int3 = int[3]; + using Int3 = decltype(b2); + using Int3 = decltype(br2); + using Int3 = decltype(brr2); + + using ConstInt3 = const int[3]; + using ConstInt3 = decltype(bcr2); +} + +struct C { template<int> int get(); }; +template<> struct std::tuple_size<C> { static const int value = 1; }; +template<> struct std::tuple_element<0, C> { typedef int type; }; + +int member_get() { + auto [c] = C(); + using T = int; + using T = decltype(c); + return c; +} + +struct D { template<int> struct get {}; }; // expected-note {{declared here}} +template<> struct std::tuple_size<D> { static const int value = 1; }; +template<> struct std::tuple_element<0, D> { typedef D::get<0> type; }; +void member_get_class_template() { + auto [d] = D(); // expected-error {{cannot refer to member 'get' in 'D' with '.'}} expected-note {{in implicit init}} +} + +struct E { int get(); }; +template<> struct std::tuple_size<E> { static const int value = 1; }; +template<> struct std::tuple_element<0, E> { typedef int type; }; +void member_get_non_template() { + // FIXME: This diagnostic is not very good. + auto [e] = E(); // expected-error {{no member named 'get'}} expected-note {{in implicit init}} +} + +namespace ADL { + struct X {}; +}; +template<int> int get(ADL::X); +template<> struct std::tuple_size<ADL::X> { static const int value = 1; }; +template<> struct std::tuple_element<0, ADL::X> { typedef int type; }; +void adl_only_bad() { + auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}} +} + +template<typename ElemType, typename GetTypeLV, typename GetTypeRV> +struct wrap { + template<size_t> GetTypeLV get() &; + template<size_t> GetTypeRV get() &&; +}; +template<typename ET, typename GTL, typename GTR> +struct std::tuple_size<wrap<ET, GTL, GTR>> { + static const int value = 1; +}; +template<typename ET, typename GTL, typename GTR> +struct std::tuple_element<0, wrap<ET, GTL, GTR>> { + using type = ET; +}; + +template<typename T> T &lvalue(); + +void test_value_category() { + // If the declared variable is an lvalue reference, the operand to get is an + // lvalue. Otherwise it's an xvalue. + { auto [a] = wrap<int, void, int>(); } + { auto &[a] = lvalue<wrap<int, int, void>>(); } + { auto &&[a] = wrap<int, void, int>(); } + // If the initializer (call to get) is an lvalue, the binding is an lvalue + // reference to the element type. Otherwise it's an rvalue reference to the + // element type. + { auto [a] = wrap<int, void, int&>(); } + { auto [a] = wrap<int&, void, int&>(); } + { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int& + + { auto [a] = wrap<int, void, int&&>(); } + { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}} + { auto [a] = wrap<const int&, void, int&&>(); } + { auto [a] = wrap<int&&, void, int&&>(); } + + { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}} + { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float + { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float +} diff --git a/clang/test/CXX/dcl.decl/dcl.decomp/p4.cpp b/clang/test/CXX/dcl.decl/dcl.decomp/p4.cpp new file mode 100644 index 00000000000..3a72ae0e33a --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.decomp/p4.cpp @@ -0,0 +1,173 @@ +// RUN: %clang_cc1 -std=c++1z -verify -triple i686-linux-gnu %s + +template<typename T, typename U> struct same; +template<typename T> struct same<T, T> { ~same(); }; + +struct Empty {}; + +struct A { + int a; +}; + +namespace NonPublicMembers { + struct NonPublic1 { + protected: + int a; // expected-note {{declared protected here}} + }; + + struct NonPublic2 { + private: + int a; // expected-note 2{{declared private here}} + }; + + struct NonPublic3 : private A {}; // expected-note {{constrained by private inheritance}} + + struct NonPublic4 : NonPublic2 {}; + + void test() { + auto [a1] = NonPublic1(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic1'}} + auto [a2] = NonPublic2(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic2'}} + auto [a3] = NonPublic3(); // expected-error {{cannot decompose members of non-public base class 'A' of 'NonPublic3'}} + auto [a4] = NonPublic4(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic4'}} + } +} + +namespace MultipleClasses { + struct B : A { + int a; + }; + + struct C { int a; }; + struct D : A, C {}; + + struct E : virtual A {}; + struct F : A, E {}; // expected-warning {{direct base 'A' is inaccessible due to ambiguity}} + + struct G : virtual A {}; + struct H : E, G {}; + + struct I { int i; }; + struct J : I {}; + struct K : I, virtual J {}; // expected-warning {{direct base 'MultipleClasses::I' is inaccessible due to ambiguity}} + + struct L : virtual J {}; + struct M : virtual J, L {}; + + void test() { + auto [b] = B(); // expected-error {{cannot decompose class type 'B': both it and its base class 'A' have non-static data members}} + auto [d] = D(); // expected-error {{cannot decompose class type 'D': its base classes 'A' and 'MultipleClasses::C' have non-static data members}} + auto [e] = E(); + auto [f] = F(); // expected-error-re {{cannot decompose members of ambiguous base class 'A' of 'F':{{.*}}struct MultipleClasses::F -> struct A{{.*}}struct MultipleClasses::F -> struct MultipleClasses::E -> struct A}} + auto [h] = H(); // ok, only one (virtual) base subobject even though there are two paths to it + auto [k] = K(); // expected-error {{cannot decompose members of ambiguous base class 'MultipleClasses::I'}} + auto [m] = M(); // ok, all paths to I are through the same virtual base subobject J + + same<decltype(m), int>(); + } +} + +namespace BindingTypes { + struct A { + int i = 0; + int &r = i; + const float f = i; + mutable volatile int mvi; + }; + void e() { + auto [i,r,f,mvi] = A(); + + same<decltype(i), int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); + + same<decltype((i)), int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); + } + void f() { + auto &&[i,r,f,mvi] = A(); + + same<decltype(i), int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); + + same<decltype((i)), int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); + } + void g() { + const auto [i,r,f,mvi] = A(); + + same<decltype(i), const int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx + + same<decltype((i)), const int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx + } + void h() { + typedef const A CA; + auto &[i,r,f,mvi] = CA(); // type of var is 'const A &' + + same<decltype(i), const int>(); // not 'int', per expected resolution of DRxxx + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx + + same<decltype((i)), const int&>(); // not 'int&', per expected resolution of DRxxx + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx + } + struct B { + mutable int i; + }; + void mut() { + auto [i] = B(); + const auto [ci] = B(); + volatile auto [vi] = B(); + same<decltype(i), int>(); + same<decltype(ci), int>(); + same<decltype(vi), volatile int>(); + } +} + +namespace Bitfield { + struct S { unsigned long long x : 4, y : 32; int z; }; // expected-note 2{{here}} + int f(S s) { + auto [a, b, c] = s; + unsigned long long &ra = a; // expected-error {{bit-field 'x'}} + unsigned long long &rb = b; // expected-error {{bit-field 'y'}} + int &rc = c; + + // the type of the binding is the type of the field + same<decltype(a), unsigned long long>(); + same<decltype(b), unsigned long long>(); + + // the type of the expression is an lvalue of the field type + // (even though a reference can't bind to the field) + same<decltype((a)), unsigned long long&>(); + same<decltype((b)), unsigned long long&>(); + + // the expression promotes to a type large enough to hold the result + same<decltype(+a), int>(); + same<decltype(+b), unsigned int>(); + return rc; + } +} + +namespace std_example { + struct S { int x1 : 2; volatile double y1; }; + S f(); + const auto [x, y] = f(); + + same<decltype((x)), const int&> same1; + same<decltype((y)), const volatile double&> same2; +} |

