151 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
	
// RUN: %clang_cc1 -std=c++1z %s -verify -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 not a simple-declaration.
 | 
						|
    for (; auto [a, b, c] = S(); ) {} // expected-error {{not permitted in this context}}
 | 
						|
    if (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
 | 
						|
    if (int n; auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
 | 
						|
    switch (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
 | 
						|
    switch (int n; auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
 | 
						|
    while (auto [a, b, c] = S()) {} // expected-error {{not permitted in this context}}
 | 
						|
 | 
						|
    // 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-error {{cannot be declared 'static'}}
 | 
						|
    thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}}
 | 
						|
    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 thread_local auto &[j] = n; // expected-error {{cannot be declared with 'static thread_local constexpr' specifiers}}
 | 
						|
  }
 | 
						|
  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'}}
 | 
						|
  }
 | 
						|
}
 |