1 // RUN: %clang_cc1 -std=c++17 %s -verify -fcxx-exceptions
2 // RUN: not %clang_cc1 -std=c++17 %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 
f(S s)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];
h()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 
g()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 {
f()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;
f()68   void f() {
69     // storage-class-specifiers
70     static auto &[a] = n; // expected-warning {{declared 'static' is a C++20 extension}}
71     thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++20 extension}}
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 
87   static constexpr inline thread_local auto &[j1] = n; // expected-error {{cannot be declared with 'constexpr inline' specifiers}}
88   static thread_local auto &[j2] = n; // expected-warning {{declared with 'static thread_local' specifiers is a C++20 extension}}
89 
90   inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}}
91 
92   const int K = 5;
g()93   void g() {
94     // defining-type-specifiers other than cv-qualifiers and 'auto'
95     S [a] = s; // expected-error {{cannot be declared with type 'BadSpecifiers::S'}}
96     decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}}
97     auto ([c]) = s; // expected-error {{cannot be declared with parentheses}}
98 
99     // FIXME: This error is not very good.
100     auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}}
101     auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}
102 
103     // FIXME: This should fire the 'misplaced array declarator' diagnostic.
104     int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}
105     int [5] arr = {0}; // expected-error {{place the brackets after the name}}
106 
107     auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}
108     auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto BadSpecifiers::S::*'}} expected-error {{incompatible initializer}}
109 
110     // ref-qualifiers are OK.
111     auto &&[ok_1] = S();
112     auto &[ok_2] = s;
113 
114     // attributes are OK.
115     [[]] auto [ok_3] = s;
116     alignas(S) auto [ok_4] = s;
117 
118     // ... but not after the identifier or declarator.
119     // FIXME: These errors are not very good.
120     auto [bad_attr_1 [[]]] = s; // expected-error {{attribute list cannot appear here}} expected-error 2{{}}
121     auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}}
122   }
123 }
124 
125 namespace MultiDeclarator {
126   struct S { int n; };
f(S s)127   void f(S s) {
128     auto [a] = s, [b] = s; // expected-error {{must be the only declaration}}
129     auto [c] = s,  d = s; // expected-error {{must be the only declaration}}
130     auto  e  = s, [f] = s; // expected-error {{must be the only declaration}}
131     auto g = s, h = s, i = s, [j] = s; // expected-error {{must be the only declaration}}
132   }
133 }
134 
135 namespace Template {
136   int n[3];
137   // FIXME: There's no actual rule against this...
138   template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}}
139 }
140 
141 namespace Init {
f()142   void f() {
143     int arr[1];
144     struct S { int n; };
145     auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}
146     const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}}
147     const auto &[bad3](); // expected-error {{expected expression}}
148     auto &[good1] = arr;
149     auto &&[good2] = S{};
150     const auto &[good3](S{});
151     S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}
152     S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}
153   }
154 }
155