1 // RUN: %clang_cc1 -std=c++1z %s -verify -fcxx-exceptions
2 
3 struct S { int a, b, c; };
4 
5 // A simple-declaration can be a decompsition declaration.
6 namespace SimpleDecl {
7   auto [a_x, b_x, c_x] = S();
8 
9   void f(S s) {
10     auto [a, b, c] = S();
11     {
12       for (auto [a, b, c] = S();;) {}
13       if (auto [a, b, c] = S(); true) {}
14       switch (auto [a, b, c] = S(); 0) { case 0:; }
15     }
16   }
17 }
18 
19 // A for-range-declaration can be a decomposition declaration.
20 namespace ForRangeDecl {
21   extern S arr[10];
22   void h() {
23     for (auto [a, b, c] : arr) {
24     }
25   }
26 }
27 
28 // Other kinds of declaration cannot.
29 namespace OtherDecl {
30   // A parameter-declaration is not a simple-declaration.
31   // This parses as an array declaration.
32   void f(auto [a, b, c]); // expected-error {{'auto' not allowed in function prototype}} expected-error {{'a'}}
33 
34   void g() {
35     // A condition is not a simple-declaration.
36     for (; auto [a, b, c] = S(); ) {} // expected-error {{not permitted in this context}}
37     if (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
38     if (int n; auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
39     switch (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
40     switch (int n; auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
41     while (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
42 
43     // An exception-declaration is not a simple-declaration.
44     try {}
45     catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error {{'a'}}
46   }
47 
48   // A member-declaration is not a simple-declaration.
49   class A {
50     auto [a, b, c] = S(); // expected-error {{not permitted in this context}}
51     static auto [a, b, c] = S(); // expected-error {{not permitted in this context}}
52   };
53 }
54 
55 namespace GoodSpecifiers {
56   void f() {
57     int n[1];
58     const volatile auto &[a] = n;
59   }
60 }
61 
62 namespace BadSpecifiers {
63   typedef int I1[1];
64   I1 n;
65   struct S { int n; } s;
66   void f() {
67     // storage-class-specifiers
68     static auto &[a] = n; // expected-error {{cannot be declared 'static'}}
69     thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}}
70     extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}}
71     struct S {
72       mutable auto &[d] = n; // expected-error {{not permitted in this context}}
73 
74       // function-specifiers
75       virtual auto &[e] = n; // expected-error {{not permitted in this context}}
76       explicit auto &[f] = n; // expected-error {{not permitted in this context}}
77 
78       // misc decl-specifiers
79       friend auto &[g] = n; // expected-error {{'auto' not allowed}} expected-error {{friends can only be classes or functions}}
80     };
81     typedef auto &[h] = n; // expected-error {{cannot be declared 'typedef'}}
82     constexpr auto &[i] = n; // expected-error {{cannot be declared 'constexpr'}}
83 
84     static constexpr thread_local auto &[j] = n; // expected-error {{cannot be declared with 'static thread_local constexpr' specifiers}}
85   }
86   inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}}
87 
88   const int K = 5;
89   void g() {
90     // defining-type-specifiers other than cv-qualifiers and 'auto'
91     S [a] = s; // expected-error {{cannot be declared with type 'BadSpecifiers::S'}}
92     decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}}
93     auto ([c]) = s; // expected-error {{cannot be declared with parentheses}}
94 
95     // FIXME: This error is not very good.
96     auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}}
97     auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}
98 
99     // FIXME: This should fire the 'misplaced array declarator' diagnostic.
100     int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}
101     int [5] arr = {0}; // expected-error {{place the brackets after the name}}
102 
103     auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}
104     auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto BadSpecifiers::S::*'}} expected-error {{incompatible initializer}}
105 
106     // ref-qualifiers are OK.
107     auto &&[ok_1] = S();
108     auto &[ok_2] = s;
109 
110     // attributes are OK.
111     [[]] auto [ok_3] = s;
112     alignas(S) auto [ok_4] = s;
113 
114     // ... but not after the identifier or declarator.
115     // FIXME: These errors are not very good.
116     auto [bad_attr_1 [[]]] = s; // expected-error {{attribute list cannot appear here}} expected-error 2{{}}
117     auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}}
118   }
119 }
120 
121 namespace MultiDeclarator {
122   struct S { int n; };
123   void f(S s) {
124     auto [a] = s, [b] = s; // expected-error {{must be the only declaration}}
125     auto [c] = s,  d = s; // expected-error {{must be the only declaration}}
126     auto  e  = s, [f] = s; // expected-error {{must be the only declaration}}
127     auto g = s, h = s, i = s, [j] = s; // expected-error {{must be the only declaration}}
128   }
129 }
130 
131 namespace Template {
132   int n[3];
133   // FIXME: There's no actual rule against this...
134   template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}}
135 }
136 
137 namespace Init {
138   void f() {
139     int arr[1];
140     struct S { int n; };
141     auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}
142     const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}}
143     const auto &[bad3](); // expected-error {{expected expression}}
144     auto &[good1] = arr;
145     auto &&[good2] = S{};
146     const auto &[good3](S{});
147     S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}
148     S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}
149   }
150 }
151