diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 641d3e73905ef..1aa6064d22104 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -486,6 +486,8 @@ def err_decomp_decl_inaccessible_base : Error< def err_decomp_decl_inaccessible_field : Error< "cannot decompose %select{private|protected}0 member %1 of %3">, AccessControl; +def err_decomp_decl_lambda : Error< + "cannot decompose lambda closure type">; def err_decomp_decl_anon_union_member : Error< "cannot decompose class type %0 because it has an anonymous " "%select{struct|union}1 member">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 72dfa37c321e3..6589b37338e95 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1374,11 +1374,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef Bindings, if (FD->isUnnamedBitfield()) continue; - if (FD->isAnonymousStructOrUnion()) { - S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) - << DecompType << FD->getType()->isUnionType(); - S.Diag(FD->getLocation(), diag::note_declared_at); - return true; + // All the non-static data members are required to be nameable, so they + // must all have names. + if (!FD->getDeclName()) { + if (RD->isLambda()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda); + S.Diag(RD->getLocation(), diag::note_lambda_decl); + return true; + } + + if (FD->isAnonymousStructOrUnion()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) + << DecompType << FD->getType()->isUnionType(); + S.Diag(FD->getLocation(), diag::note_declared_at); + return true; + } + + // FIXME: Are there any other ways we could have an anonymous member? } // We have a real field to bind. diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 336c103ef0a4a..45a062a916f37 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -103,4 +103,49 @@ int f2() { } // namespace instantiate_template +namespace lambdas { + void f() { + int n; + auto [a] = // expected-error {{cannot decompose lambda closure type}} + [n] {}; // expected-note {{lambda expression}} + } + + auto [] = []{}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}} + + int g() { + int n = 0; + auto a = [=](auto &self) { // expected-note {{lambda expression}} + auto &[capture] = self; // expected-error {{cannot decompose lambda closure type}} + ++capture; + return n; + }; + return a(a); // expected-note {{in instantiation of}} + } + + int h() { + auto x = [] {}; + struct A : decltype(x) { + int n; + }; + auto &&[r] = A{x, 0}; // OK (presumably), non-capturing lambda has no non-static data members + return r; + } + + int i() { + int n; + auto x = [n] {}; + struct A : decltype(x) { + int n; + }; + auto &&[r] = A{x, 0}; // expected-error-re {{cannot decompose class type 'A': both it and its base class 'decltype(x)' (aka '(lambda {{.*}})') have non-static data members}} + return r; + } + + void j() { + auto x = [] {}; + struct A : decltype(x) {}; + auto &&[] = A{x}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}} + } +} + // FIXME: by-value array copies