xref: /llvm-project/clang/test/Parser/cxx1z-decomposition.cpp (revision 70c1764d7a223b14b38bb394e5020e753be9c869)
1 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-unknown-linux-gnu -verify=expected,cxx17,pre2c -fcxx-exceptions
2 // RUN: %clang_cc1 -std=c++2b %s -triple x86_64-unknown-linux-gnu -verify=expected,cxx2b,pre2c,post2b -fcxx-exceptions
3 // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-unknown-linux-gnu -verify=expected,cxx2c,post2b -fcxx-exceptions
4 // RUN: not %clang_cc1 -std=c++17 %s -triple x86_64-unknown-linux-gnu -emit-llvm-only -fcxx-exceptions
5 
6 struct S { int a, b, c; };
7 
8 // A simple-declaration can be a decompsition declaration.
9 namespace SimpleDecl {
10   auto [a_x, b_x, c_x] = S();
11 
12   void f(S s) {
13     auto [a, b, c] = S();
14     {
15       for (auto [a, b, c] = S();;) {}
16       if (auto [a, b, c] = S(); true) {}
17       switch (auto [a, b, c] = S(); 0) { case 0:; }
18     }
19   }
20 }
21 
22 // A for-range-declaration can be a decomposition declaration.
23 namespace ForRangeDecl {
24   extern S arr[10];
25   void h() {
26     for (auto [a, b, c] : arr) {
27     }
28   }
29 }
30 
31 // Other kinds of declaration cannot.
32 namespace OtherDecl {
33   // A parameter-declaration is not a simple-declaration.
34   // This parses as an array declaration.
35   void f(auto [a, b, c]); // cxx17-error {{'auto' not allowed in function prototype}} expected-error {{'a'}}
36 
37   void g() {
38     // A condition is allowed as a Clang extension.
39     // See commentary in test/Parser/decomposed-condition.cpp
40     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'}}
41     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'}}
42     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'}}
43     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)}}
44     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)}}
45     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'}}
46 
47     // An exception-declaration is not a simple-declaration.
48     try {}
49     catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error {{'a'}}
50   }
51 
52   // A member-declaration is not a simple-declaration.
53   class A {
54     auto [a, b, c] = S(); // expected-error {{not permitted in this context}}
55     static auto [a, b, c] = S(); // expected-error {{not permitted in this context}}
56   };
57 }
58 
59 namespace GoodSpecifiers {
60   void f() {
61     int n[1];
62     const volatile auto &[a] = n; // post2b-warning {{volatile qualifier in structured binding declaration is deprecated}}
63   }
64 }
65 
66 namespace BadSpecifiers {
67   typedef int I1[1];
68   I1 n;
69   struct S { int n; } s;
70   void f() {
71     // storage-class-specifiers
72     static auto &[a] = n; // cxx17-warning {{declared 'static' is a C++20 extension}}
73     thread_local auto &[b] = n; // cxx17-warning {{declared 'thread_local' is a C++20 extension}}
74     extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{declaration of block scope identifier with linkage cannot have an initializer}}
75     struct S {
76       mutable auto &[d] = n; // expected-error {{not permitted in this context}}
77 
78       // function-specifiers
79       virtual auto &[e] = n; // expected-error {{not permitted in this context}}
80       explicit auto &[f] = n; // expected-error {{not permitted in this context}}
81 
82       // misc decl-specifiers
83       friend auto &[g] = n; // expected-error {{'auto' not allowed}} expected-error {{friends can only be classes or functions}}
84     };
85     typedef auto &[h] = n; // expected-error {{cannot be declared 'typedef'}}
86     constexpr auto &[i] = n; // expected-error {{cannot be declared 'constexpr'}}
87   }
88 
89   static constexpr inline thread_local auto &[j1] = n; // expected-error {{cannot be declared with 'constexpr inline' specifiers}}
90   static thread_local auto &[j2] = n; // cxx17-warning {{declared with 'static thread_local' specifiers is a C++20 extension}}
91 
92   inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}}
93 
94   const int K = 5;
95   auto ([c]) = s; // expected-error {{decomposition declaration cannot be declared with parentheses}}
96   void g() {
97     // defining-type-specifiers other than cv-qualifiers and 'auto'
98     S [a] = s; // expected-error {{cannot be declared with type 'S'}}
99     decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}}
100     auto ([c2]) = s; // cxx17-error {{decomposition declaration cannot be declared with parenthese}} \
101                      // post2b-error {{use of undeclared identifier 'c2'}} \
102                      // post2b-error {{expected body of lambda expression}} \
103 
104     // FIXME: This error is not very good.
105     auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}}
106     auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}
107 
108     // FIXME: This should fire the 'misplaced array declarator' diagnostic.
109     int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}
110     int [5] arr = {0}; // expected-error {{place the brackets after the name}}
111 
112     auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}
113     auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto S::*'}} expected-error {{incompatible initializer}}
114 
115     // ref-qualifiers are OK.
116     auto &&[ok_1] = S();
117     auto &[ok_2] = s;
118 
119     // attributes are OK.
120     [[]] auto [ok_3] = s;
121     alignas(S) auto [ok_4] = s;
122 
123     auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}}
124   }
125 }
126 
127 namespace MultiDeclarator {
128   struct S { int n; };
129   void f(S s) {
130     auto [a] = s, [b] = s; // expected-error {{must be the only declaration}}
131     auto [c] = s,  d = s; // expected-error {{must be the only declaration}}
132     auto  e  = s, [f] = s; // expected-error {{must be the only declaration}}
133     auto g = s, h = s, i = s, [j] = s; // expected-error {{must be the only declaration}}
134   }
135 }
136 
137 namespace Template {
138   int n[3];
139   // FIXME: There's no actual rule against this...
140   template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}}
141 }
142 
143 namespace Init {
144   void f() {
145     int arr[1];
146     struct S { int n; };
147     auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}
148     const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}}
149     const auto &[bad3](); // expected-error {{expected expression}}
150     auto &[good1] = arr;
151     auto &&[good2] = S{};
152     const auto &[good3](S{});
153     S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}
154     S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}
155   }
156 }
157 
158 
159 namespace attributes {
160 
161 struct S{
162     int a;
163     int b = 0;
164 };
165 
166 void err() {
167     auto [[]] = S{0}; // expected-error {{expected unqualified-id}}
168     auto [ alignas(42) a, foo ] = S{0}; // expected-error {{an attribute list cannot appear here}}
169     auto [ c, [[]] d ] = S{0}; // expected-error {{an attribute list cannot appear here}}
170     auto [ e, alignas(42) f ] = S{0}; // expected-error {{an attribute list cannot appear here}}
171 }
172 
173 void ok() {
174     auto [ a alignas(42) [[]], b alignas(42) [[]]] = S{0}; // expected-error 2{{'alignas' attribute only applies to variables, data members and tag types}} \
175                                                            // pre2c-warning  2{{an attribute specifier sequence attached to a structured binding declaration is a C++2c extension}}
176     auto [ c [[]] alignas(42), d [[]] alignas(42) [[]]] = S{0}; // expected-error 2{{'alignas' attribute only applies to variables, data members and tag types}} \
177                                                                 // pre2c-warning  2{{an attribute specifier sequence attached to a structured binding declaration is a C++2c extension}}
178 }
179 
180 
181 auto [G1 [[deprecated]], G2 [[deprecated]]] = S{42}; // #deprecated-here
182 // pre2c-warning@-1 2{{an attribute specifier sequence attached to a structured binding declaration is a C++2c extension}}
183 
184 int test() {
185   return G1 + G2; // expected-warning {{'G1' is deprecated}} expected-note@#deprecated-here {{here}} \
186                   // expected-warning {{'G2' is deprecated}} expected-note@#deprecated-here {{here}}
187 }
188 
189 void invalid_attributes() {
190   // pre2c-warning@+1 {{an attribute specifier sequence attached to a structured binding declaration is a C++2c extension}}
191   auto [a alignas(42) // expected-error {{'alignas' attribute only applies to variables, data members and tag types}}
192       [[assume(true), // expected-error {{'assume' attribute cannot be applied to a declaration}}
193         carries_dependency, // expected-error {{'carries_dependency' attribute only applies to parameters, Objective-C methods, and functions}}
194         fallthrough,  // expected-error {{'fallthrough' attribute cannot be applied to a declaration}}
195         likely, // expected-error {{'likely' attribute cannot be applied to a declaration}}
196         unlikely, // expected-error {{'unlikely' attribute cannot be applied to a declaration}}
197         nodiscard,  // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}
198         noreturn,  // expected-error {{'noreturn' attribute only applies to functions}}
199         no_unique_address]], // expected-error {{'no_unique_address' attribute only applies to non-bit-field non-static data members}}
200     b] = S{0};
201 }
202 
203 }
204