Skip to content

Commit ccca93b

Browse files
committed
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.
1 parent 1b5baa4 commit ccca93b

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,8 @@ def err_decomp_decl_inaccessible_base : Error<
486486
def err_decomp_decl_inaccessible_field : Error<
487487
"cannot decompose %select{private|protected}0 member %1 of %3">,
488488
AccessControl;
489+
def err_decomp_decl_lambda : Error<
490+
"cannot decompose lambda closure type">;
489491
def err_decomp_decl_anon_union_member : Error<
490492
"cannot decompose class type %0 because it has an anonymous "
491493
"%select{struct|union}1 member">;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,11 +1374,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
13741374
if (FD->isUnnamedBitfield())
13751375
continue;
13761376

1377-
if (FD->isAnonymousStructOrUnion()) {
1378-
S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
1379-
<< DecompType << FD->getType()->isUnionType();
1380-
S.Diag(FD->getLocation(), diag::note_declared_at);
1381-
return true;
1377+
// All the non-static data members are required to be nameable, so they
1378+
// must all have names.
1379+
if (!FD->getDeclName()) {
1380+
if (RD->isLambda()) {
1381+
S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda);
1382+
S.Diag(RD->getLocation(), diag::note_lambda_decl);
1383+
return true;
1384+
}
1385+
1386+
if (FD->isAnonymousStructOrUnion()) {
1387+
S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
1388+
<< DecompType << FD->getType()->isUnionType();
1389+
S.Diag(FD->getLocation(), diag::note_declared_at);
1390+
return true;
1391+
}
1392+
1393+
// FIXME: Are there any other ways we could have an anonymous member?
13821394
}
13831395

13841396
// We have a real field to bind.

clang/test/SemaCXX/cxx1z-decomposition.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,49 @@ int f2() {
103103

104104
} // namespace instantiate_template
105105

106+
namespace lambdas {
107+
void f() {
108+
int n;
109+
auto [a] = // expected-error {{cannot decompose lambda closure type}}
110+
[n] {}; // expected-note {{lambda expression}}
111+
}
112+
113+
auto [] = []{}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}}
114+
115+
int g() {
116+
int n = 0;
117+
auto a = [=](auto &self) { // expected-note {{lambda expression}}
118+
auto &[capture] = self; // expected-error {{cannot decompose lambda closure type}}
119+
++capture;
120+
return n;
121+
};
122+
return a(a); // expected-note {{in instantiation of}}
123+
}
124+
125+
int h() {
126+
auto x = [] {};
127+
struct A : decltype(x) {
128+
int n;
129+
};
130+
auto &&[r] = A{x, 0}; // OK (presumably), non-capturing lambda has no non-static data members
131+
return r;
132+
}
133+
134+
int i() {
135+
int n;
136+
auto x = [n] {};
137+
struct A : decltype(x) {
138+
int n;
139+
};
140+
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}}
141+
return r;
142+
}
143+
144+
void j() {
145+
auto x = [] {};
146+
struct A : decltype(x) {};
147+
auto &&[] = A{x}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}}
148+
}
149+
}
150+
106151
// FIXME: by-value array copies

0 commit comments

Comments
 (0)