summaryrefslogtreecommitdiffstats
path: root/test/Parser/cxx1z-decomposition.cpp
blob: 9cbe70e3c69bdfa3493c8db67844fb05d6504bf7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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'}}
  }
}