summaryrefslogtreecommitdiffstats
path: root/clang/test/CXX/dcl.decl
diff options
context:
space:
mode:
Diffstat (limited to 'clang/test/CXX/dcl.decl')
-rw-r--r--clang/test/CXX/dcl.decl/dcl.decomp/p2.cpp22
-rw-r--r--clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp203
-rw-r--r--clang/test/CXX/dcl.decl/dcl.decomp/p4.cpp173
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;
+}
OpenPOWER on IntegriCloud