Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Don't allow structured binding declarations to decompose a
lambda-expression's captures.

The built-in structured binding rules for classes require that all
fields can be accessed by name, and the fields introduced for lambda
captures are unnamed, so decomposing a capturing lambda is ill-formed.
  • Loading branch information
zygoloid committed Oct 23, 2020
1 parent 1b5baa4 commit ccca93b
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -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">;
Expand Down
22 changes: 17 additions & 5 deletions clang/lib/Sema/SemaDeclCXX.cpp
Expand Up @@ -1374,11 +1374,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> 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.
Expand Down
45 changes: 45 additions & 0 deletions clang/test/SemaCXX/cxx1z-decomposition.cpp
Expand Up @@ -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

0 comments on commit ccca93b

Please sign in to comment.