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