Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -2001,7 +2001,7 @@ } /// Return true if the context permits a C++17 decomposition declarator. - bool mayHaveDecompositionDeclarator() const { + bool mayHaveDecompositionDeclarator(const LangOptions &Lang) const { switch (Context) { case FileContext: // FIXME: It's not clear that the proposal meant to allow file-scope @@ -2012,6 +2012,7 @@ return true; case ConditionContext: + return Lang.CPlusPlus2a; case MemberContext: case PrototypeContext: case TemplateParamContext: Index: lib/Parse/ParseExprCXX.cpp =================================================================== --- lib/Parse/ParseExprCXX.cpp +++ lib/Parse/ParseExprCXX.cpp @@ -1708,6 +1708,8 @@ /// type-specifier-seq declarator '=' assignment-expression /// [C++11] type-specifier-seq declarator '=' initializer-clause /// [C++11] type-specifier-seq declarator braced-init-list +/// [C++2a] type-specifier-seq ref-qualifier[opt] '[' identifier-list ']' +/// brace-or-equal-initializer /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -692,9 +692,10 @@ assert(D.isDecompositionDeclarator()); const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); - // The syntax only allows a decomposition declarator as a simple-declaration - // or a for-range-declaration, but we parse it in more cases than that. - if (!D.mayHaveDecompositionDeclarator()) { + // The syntax only allows a decomposition declarator as a simple-declaration, + // a for-range-declaration, or a condition in C++2a, but we parse it in more + // cases than that. + if (!D.mayHaveDecompositionDeclarator(getLangOpts())) { Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) << Decomp.getSourceRange(); return nullptr; Index: test/Parser/cxx2a-decomposition.cpp =================================================================== --- /dev/null +++ test/Parser/cxx2a-decomposition.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify + +struct Na { + bool flag; + float data; +}; + +struct Rst { + bool flag; + float data; + explicit operator bool() const { + return flag; + } +}; + +Rst f(); +Na g(); + +namespace CondInIf { +void h() { + if (auto [ok, d] = f()) + ; + if (auto [ok, d] = g()) // expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} + ; +} +} // namespace CondInIf + +namespace CondInWhile { +void h() { + while (auto [ok, d] = f()) + ; + while (auto [ok, d] = g()) // expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} + ; +} +} // namespace CondInWhile + +namespace CondInFor { +void h() { + for (; auto [ok, d] = f();) + ; + for (; auto [ok, d] = g();) // expected-error {{value of type 'Na' is not contextually convertible to 'bool'}} + ; +} +} // namespace CondInFor + +struct IntegerLike { + bool flag; + float data; + operator int() const { + return int(data); + } +}; + +namespace CondInSwitch { +void h(IntegerLike x) { + switch (auto [ok, d] = x) + ; + switch (auto [ok, d] = g()) // expected-error {{statement requires expression of integer type ('Na' invalid)}} + ; +} +} // namespace CondInSwitch Index: test/SemaCXX/cxx2a-decomposition.cpp =================================================================== --- /dev/null +++ test/SemaCXX/cxx2a-decomposition.cpp @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +struct X { + bool flag; + int data; + constexpr explicit operator bool() const { + return flag; + } + constexpr operator int() const { + return data; + } +}; + +namespace CondInIf { +constexpr int f(X x) { + if (auto [ok, d] = x) + return d + int(ok); + else + return d * int(ok); + ok = {}; // expected-error {{use of undeclared identifier 'ok'}} + d = {}; // expected-error {{use of undeclared identifier 'd'}} +} + +static_assert(f({true, 2}) == 3); +static_assert(f({false, 2}) == 0); + +constexpr char g(char const (&x)[2]) { + if (auto &[a, b] = x) + return a; + else + return b; + + if (auto [a, b] = x) // expected-error {{an array type is not allowed here}} + ; +} + +static_assert(g("x") == 'x'); +} // namespace CondInIf + +namespace CondInSwitch { +constexpr int f(int n) { + switch (X s = {true, n}; auto [ok, d] = s) { + s = {}; + case 0: + return int(ok); + case 1: + return d * 10; + case 2: + return d * 40; + default: + return 0; + } + ok = {}; // expected-error {{use of undeclared identifier 'ok'}} + d = {}; // expected-error {{use of undeclared identifier 'd'}} + s = {}; // expected-error {{use of undeclared identifier 's'}} +} + +static_assert(f(0) == 1); +static_assert(f(1) == 10); +static_assert(f(2) == 80); +} // namespace CondInSwitch + +namespace CondInWhile { +constexpr int f(int n) { + int m = 1; + while (auto [ok, d] = X{n > 1, n}) { + m *= d; + --n; + } + return m; + return ok; // expected-error {{use of undeclared identifier 'ok'}} +} + +static_assert(f(0) == 1); +static_assert(f(1) == 1); +static_assert(f(4) == 24); +} // namespace CondInWhile + +namespace CondInFor { +constexpr int f(int n) { + int a = 1, b = 1; + for (X x = {true, n}; auto &[ok, d] = x; --d) { + if (d < 2) + ok = false; + else { + int x = b; + b += a; + a = x; + } + } + return b; + return d; // expected-error {{use of undeclared identifier 'd'}} +} + +static_assert(f(0) == 1); +static_assert(f(1) == 1); +static_assert(f(2) == 2); +static_assert(f(5) == 8); +} // namespace CondInFor