// 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 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'}} } }