| // RUN: %clang_cc1 -std=c++17 %s -verify -fcxx-exceptions |
| // RUN: not %clang_cc1 -std=c++17 %s -emit-llvm-only -fcxx-exceptions |
| |
| struct S { int a, b, c; }; |
| |
| // A simple-declaration can be a decompsition declaration. |
| namespace SimpleDecl { |
| auto [a_x, b_x, c_x] = S(); |
| |
| void f(S s) { |
| auto [a, b, c] = S(); |
| { |
| for (auto [a, b, c] = S();;) {} |
| if (auto [a, b, c] = S(); true) {} |
| switch (auto [a, b, c] = S(); 0) { case 0:; } |
| } |
| } |
| } |
| |
| // A for-range-declaration can be a decomposition declaration. |
| namespace ForRangeDecl { |
| extern S arr[10]; |
| void h() { |
| for (auto [a, b, c] : arr) { |
| } |
| } |
| } |
| |
| // Other kinds of declaration cannot. |
| namespace OtherDecl { |
| // A parameter-declaration is not a simple-declaration. |
| // This parses as an array declaration. |
| void f(auto [a, b, c]); // expected-error {{'auto' not allowed in function prototype}} expected-error {{'a'}} |
| |
| void g() { |
| // A condition is allowed as a Clang extension. |
| // See commentary in test/Parser/decomposed-condition.cpp |
| 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'}} |
| 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'}} |
| 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'}} |
| 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)}} |
| 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)}} |
| 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'}} |
| |
| // An exception-declaration is not a simple-declaration. |
| try {} |
| catch (auto [a, b, c]) {} // expected-error {{'auto' not allowed in exception declaration}} expected-error {{'a'}} |
| } |
| |
| // A member-declaration is not a simple-declaration. |
| class A { |
| auto [a, b, c] = S(); // expected-error {{not permitted in this context}} |
| static auto [a, b, c] = S(); // expected-error {{not permitted in this context}} |
| }; |
| } |
| |
| namespace GoodSpecifiers { |
| void f() { |
| int n[1]; |
| const volatile auto &[a] = n; |
| } |
| } |
| |
| namespace BadSpecifiers { |
| typedef int I1[1]; |
| I1 n; |
| struct S { int n; } s; |
| void f() { |
| // storage-class-specifiers |
| static auto &[a] = n; // expected-warning {{declared 'static' is a C++20 extension}} |
| thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++20 extension}} |
| extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}} |
| struct S { |
| mutable auto &[d] = n; // expected-error {{not permitted in this context}} |
| |
| // function-specifiers |
| virtual auto &[e] = n; // expected-error {{not permitted in this context}} |
| explicit auto &[f] = n; // expected-error {{not permitted in this context}} |
| |
| // misc decl-specifiers |
| friend auto &[g] = n; // expected-error {{'auto' not allowed}} expected-error {{friends can only be classes or functions}} |
| }; |
| typedef auto &[h] = n; // expected-error {{cannot be declared 'typedef'}} |
| constexpr auto &[i] = n; // expected-error {{cannot be declared 'constexpr'}} |
| } |
| |
| static constexpr inline thread_local auto &[j1] = n; // expected-error {{cannot be declared with 'constexpr inline' specifiers}} |
| static thread_local auto &[j2] = n; // expected-warning {{declared with 'static thread_local' specifiers is a C++20 extension}} |
| |
| inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}} |
| |
| const int K = 5; |
| void g() { |
| // defining-type-specifiers other than cv-qualifiers and 'auto' |
| S [a] = s; // expected-error {{cannot be declared with type 'BadSpecifiers::S'}} |
| decltype(auto) [b] = s; // expected-error {{cannot be declared with type 'decltype(auto)'}} |
| auto ([c]) = s; // expected-error {{cannot be declared with parentheses}} |
| |
| // FIXME: This error is not very good. |
| auto [d]() = s; // expected-error {{expected ';'}} expected-error {{expected expression}} |
| auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} |
| |
| // FIXME: This should fire the 'misplaced array declarator' diagnostic. |
| int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} |
| int [5] arr = {0}; // expected-error {{place the brackets after the name}} |
| |
| auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} |
| auto S::*[g] = s; // expected-error {{cannot be declared with type 'auto BadSpecifiers::S::*'}} expected-error {{incompatible initializer}} |
| |
| // ref-qualifiers are OK. |
| auto &&[ok_1] = S(); |
| auto &[ok_2] = s; |
| |
| // attributes are OK. |
| [[]] auto [ok_3] = s; |
| alignas(S) auto [ok_4] = s; |
| |
| // ... but not after the identifier or declarator. |
| // FIXME: These errors are not very good. |
| auto [bad_attr_1 [[]]] = s; // expected-error {{attribute list cannot appear here}} expected-error 2{{}} |
| auto [bad_attr_2] [[]] = s; // expected-error {{expected ';'}} expected-error {{}} |
| } |
| } |
| |
| namespace MultiDeclarator { |
| struct S { int n; }; |
| void f(S s) { |
| auto [a] = s, [b] = s; // expected-error {{must be the only declaration}} |
| auto [c] = s, d = s; // expected-error {{must be the only declaration}} |
| auto e = s, [f] = s; // expected-error {{must be the only declaration}} |
| auto g = s, h = s, i = s, [j] = s; // expected-error {{must be the only declaration}} |
| } |
| } |
| |
| namespace Template { |
| int n[3]; |
| // FIXME: There's no actual rule against this... |
| template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}} |
| } |
| |
| namespace Init { |
| void f() { |
| int arr[1]; |
| struct S { int n; }; |
| auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} |
| const auto &[bad2](S{}, S{}); // expected-error {{initializer for variable '[bad2]' with type 'const auto &' contains multiple expressions}} |
| const auto &[bad3](); // expected-error {{expected expression}} |
| auto &[good1] = arr; |
| auto &&[good2] = S{}; |
| const auto &[good3](S{}); |
| S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} |
| S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} |
| } |
| } |