Skip to content

Commit 5302830

Browse files
committed
[Clang][P1061] Remove BindingInitWalker
1 parent 5c351d7 commit 5302830

File tree

4 files changed

+138
-93
lines changed

4 files changed

+138
-93
lines changed

clang/include/clang/AST/Expr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,12 @@ class DeclRefExpr final
14821482
setDependence(computeDependence(this, Context));
14831483
}
14841484

1485+
/// Set type and compute and set dependence bits.
1486+
void setTypeFromBinding(QualType T, const ASTContext &Context) {
1487+
setType(T.getNonReferenceType());
1488+
setDependence(computeDependence(this, Context));
1489+
}
1490+
14851491
static bool classof(const Stmt *T) {
14861492
return T->getStmtClass() == DeclRefExprClass;
14871493
}

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 52 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -959,10 +959,8 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
959959
return New;
960960
}
961961

962-
// CheckBindingsCount
963-
// - Checks the arity of the structured bindings
964-
// - Creates the resolved pack expr if there is
965-
// one
962+
// Check the arity of the structured bindings.
963+
// Create the resolved pack expr if needed.
966964
static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD,
967965
QualType DecompType,
968966
ArrayRef<BindingDecl *> Bindings,
@@ -975,19 +973,31 @@ static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD,
975973
if (!HasPack) {
976974
IsValid = Bindings.size() == MemberCount;
977975
} else {
978-
// there may not be more members than non-pack bindings
976+
// There may not be more members than non-pack bindings.
979977
IsValid = MemberCount >= Bindings.size() - 1;
980978
}
981979

982980
if (IsValid && HasPack) {
983-
// create the pack expr and assign it to the binding
981+
// Create the pack expr and assign it to the binding.
984982
unsigned PackSize = MemberCount - Bindings.size() + 1;
985983
QualType PackType = S.Context.getPackExpansionType(
986984
S.Context.DependentTy, std::nullopt, /*ExpectsPackInType=*/false);
987985
BindingDecl *BD = (*BindingWithPackItr);
988-
BD->setBinding(PackType,
989-
ResolvedUnexpandedPackExpr::Create(
990-
S.Context, DD->getBeginLoc(), DecompType, PackSize));
986+
auto *RP = ResolvedUnexpandedPackExpr::Create(S.Context, DD->getBeginLoc(),
987+
DecompType, PackSize);
988+
BD->setDecomposedDecl(DD);
989+
BD->setBinding(PackType, RP);
990+
991+
BindingDecl *BPack = *BindingWithPackItr;
992+
// Create the nested BindingDecls.
993+
for (Expr *&E : RP->getExprs()) {
994+
auto *NestedBD = BindingDecl::Create(S.Context, BPack->getDeclContext(),
995+
BPack->getLocation(),
996+
BPack->getIdentifier(), QualType());
997+
NestedBD->setDecomposedDecl(DD);
998+
E = S.BuildDeclRefExpr(NestedBD, S.Context.DependentTy, VK_LValue,
999+
BPack->getLocation());
1000+
}
9911001
}
9921002

9931003
if (IsValid)
@@ -999,84 +1009,26 @@ static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD,
9991009
return true;
10001010
}
10011011

1002-
// BindingInitWalker
1003-
// - This implements a forward iterating flattened view
1004-
// of structured bindings that may have a nested pack.
1005-
// It allows the user to set the init expr for either the
1006-
// BindingDecl or its ResolvedUnexpandedPackExpr
1007-
struct BindingInitWalker {
1008-
using BindingItrTy = typename ArrayRef<BindingDecl *>::iterator;
1009-
using PackExprItrTy = typename MutableArrayRef<Expr *>::iterator;
1010-
Sema &SemaRef;
1011-
DecompositionDecl *DecompDecl;
1012-
ArrayRef<BindingDecl *> Bindings;
1013-
ResolvedUnexpandedPackExpr *PackExpr = nullptr;
1014-
MutableArrayRef<Expr *> PackExprNodes;
1015-
BindingItrTy BindingItr;
1016-
PackExprItrTy PackExprItr;
1017-
1018-
BindingInitWalker(Sema &S, DecompositionDecl *DD, ArrayRef<BindingDecl *> Bs)
1019-
: SemaRef(S), DecompDecl(DD), Bindings(Bs), BindingItr(Bindings.begin()) {
1020-
}
1021-
1022-
BindingDecl *get() { return *BindingItr; }
1023-
1024-
void commitAndAdvance(QualType T, Expr *E) {
1025-
BindingDecl *B = *BindingItr;
1026-
bool IsPackExpr =
1027-
isa_and_nonnull<ResolvedUnexpandedPackExpr>(B->getBinding());
1028-
if (IsPackExpr && !PackExpr) {
1029-
PackExpr = cast<ResolvedUnexpandedPackExpr>(B->getBinding());
1030-
PackExprNodes = PackExpr->getExprs();
1031-
PackExprItr = PackExprNodes.begin();
1032-
}
1033-
1034-
if (IsPackExpr) {
1035-
// Build a nested BindingDecl with a DeclRefExpr
1036-
auto *NestedBD =
1037-
BindingDecl::Create(SemaRef.Context, B->getDeclContext(),
1038-
B->getLocation(), B->getIdentifier(), T);
1039-
1040-
NestedBD->setBinding(T, E);
1041-
NestedBD->setDecomposedDecl(DecompDecl);
1042-
auto *DE = SemaRef.BuildDeclRefExpr(NestedBD, T.getNonReferenceType(),
1043-
VK_LValue, B->getLocation());
1044-
*PackExprItr = DE;
1045-
if (++PackExprItr != PackExprNodes.end())
1046-
return;
1047-
// If we hit the end of the pack exprs then
1048-
// continue to advance BindingItr
1049-
} else {
1050-
(*BindingItr)->setBinding(T, E);
1051-
}
1052-
1053-
++BindingItr;
1054-
}
1055-
};
1056-
10571012
static bool checkSimpleDecomposition(
10581013
Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,
10591014
QualType DecompType, const llvm::APSInt &NumElemsAPS, QualType ElemType,
10601015
llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) {
10611016
unsigned NumElems = (unsigned)NumElemsAPS.getLimitedValue(UINT_MAX);
1017+
auto *DD = cast<DecompositionDecl>(Src);
10621018

1063-
if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
1064-
NumElems)) {
1065-
1019+
if (CheckBindingsCount(S, DD, DecompType, Bindings, NumElems))
10661020
return true;
1067-
}
10681021

1069-
auto Walker = BindingInitWalker(S, cast<DecompositionDecl>(Src), Bindings);
1070-
for (unsigned I = 0; I < NumElems; I++) {
1071-
BindingDecl *B = Walker.get();
1022+
unsigned I = 0;
1023+
for (auto *B : DD->flat_bindings()) {
10721024
SourceLocation Loc = B->getLocation();
10731025
ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
10741026
if (E.isInvalid())
10751027
return true;
1076-
E = GetInit(Loc, E.get(), I);
1028+
E = GetInit(Loc, E.get(), I++);
10771029
if (E.isInvalid())
10781030
return true;
1079-
Walker.commitAndAdvance(ElemType, E.get());
1031+
B->setBinding(ElemType, E.get());
10801032
}
10811033

10821034
return false;
@@ -1314,11 +1266,10 @@ static bool checkTupleLikeDecomposition(Sema &S,
13141266
ArrayRef<BindingDecl *> Bindings,
13151267
VarDecl *Src, QualType DecompType,
13161268
const llvm::APSInt &TupleSize) {
1269+
auto *DD = cast<DecompositionDecl>(Src);
13171270
unsigned NumElems = (unsigned)TupleSize.getLimitedValue(UINT_MAX);
1318-
if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
1319-
NumElems)) {
1271+
if (CheckBindingsCount(S, DD, DecompType, Bindings, NumElems))
13201272
return true;
1321-
}
13221273

13231274
if (Bindings.empty())
13241275
return false;
@@ -1351,9 +1302,8 @@ static bool checkTupleLikeDecomposition(Sema &S,
13511302
}
13521303
}
13531304

1354-
auto Walker = BindingInitWalker(S, cast<DecompositionDecl>(Src), Bindings);
1355-
for (unsigned I = 0; I < NumElems; I++) {
1356-
BindingDecl *B = Walker.get();
1305+
unsigned I = 0;
1306+
for (auto *B : DD->flat_bindings()) {
13571307
InitializingBinding InitContext(S, B);
13581308
SourceLocation Loc = B->getLocation();
13591309

@@ -1439,7 +1389,8 @@ static bool checkTupleLikeDecomposition(Sema &S,
14391389
if (E.isInvalid())
14401390
return true;
14411391

1442-
Walker.commitAndAdvance(T, E.get());
1392+
B->setBinding(T, E.get());
1393+
I++;
14431394
}
14441395

14451396
return false;
@@ -1535,18 +1486,18 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15351486
QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD),
15361487
DecompType.getQualifiers());
15371488

1489+
auto *DD = cast<DecompositionDecl>(Src);
15381490
unsigned NumFields = llvm::count_if(
15391491
RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
1540-
if (CheckBindingsCount(S, cast<DecompositionDecl>(Src), DecompType, Bindings,
1541-
NumFields)) {
1492+
if (CheckBindingsCount(S, DD, DecompType, Bindings, NumFields))
15421493
return true;
1543-
}
1544-
1545-
auto Walker = BindingInitWalker(S, cast<DecompositionDecl>(Src), Bindings);
15461494

15471495
// all of E's non-static data members shall be [...] well-formed
15481496
// when named as e.name in the context of the structured binding,
15491497
// E shall not have an anonymous union member, ...
1498+
auto FlatBindings = DD->flat_bindings();
1499+
assert(llvm::range_size(FlatBindings) == NumFields);
1500+
auto FlatBindingsItr = FlatBindings.begin();
15501501
for (auto *FD : RD->fields()) {
15511502
if (FD->isUnnamedBitField())
15521503
continue;
@@ -1571,7 +1522,8 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15711522
}
15721523

15731524
// We have a real field to bind.
1574-
BindingDecl *B = Walker.get();
1525+
assert(FlatBindingsItr != FlatBindings.end());
1526+
BindingDecl *B = *(FlatBindingsItr++);
15751527
SourceLocation Loc = B->getLocation();
15761528

15771529
// The field must be accessible in the context of the structured binding.
@@ -1606,8 +1558,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
16061558
Qualifiers Q = DecompType.getQualifiers();
16071559
if (FD->isMutable())
16081560
Q.removeConst();
1609-
Walker.commitAndAdvance(S.BuildQualifiedType(FD->getType(), Loc, Q),
1610-
E.get());
1561+
B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
16111562
}
16121563

16131564
return false;
@@ -1625,6 +1576,19 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
16251576
B->setType(Context.DependentTy);
16261577
}
16271578
return;
1579+
} else {
1580+
// Set the types of the DeclRefExprs that point to nested pack bindings.
1581+
for (BindingDecl *B : DD->bindings()) {
1582+
if (B->isParameterPack()) {
1583+
for (Expr *E : B->getBindingPackExprs()) {
1584+
auto *DRE = cast<DeclRefExpr>(E);
1585+
auto *NestedB = cast<BindingDecl>(DRE->getDecl());
1586+
QualType T = NestedB->getType();
1587+
DRE->setTypeFromBinding(T, Context);
1588+
}
1589+
break;
1590+
}
1591+
}
16281592
}
16291593

16301594
DecompType = DecompType.getNonReferenceType();

clang/test/Parser/cxx2c-binding-pack.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ void decompose_array() {
66
auto [x, ... // #1
77
rest, ...more_rest] = arr; // expected-error{{multiple packs in structured binding declaration}}
88
// expected-note@#1{{previous binding pack specified here}}
9-
//
9+
1010
auto [y...] = arr; // expected-error{{'...' must immediately precede declared identifier}}
11+
12+
auto [...] = arr; // #2
13+
// expected-error@#2{{expected identifier}}
14+
// expected-error@#2{{{no names were provided}}}
15+
// expected-warning@#2{{{does not allow a decomposition group to be empty}}}
16+
auto [a, ..., b] = arr; // #3
17+
// expected-error@#3{{expected identifier}}
18+
// expected-error@#3{{{only 1 name was provided}}}
19+
auto [a1, ...] = arr; // #4
20+
// expected-error@#4{{expected identifier}}
21+
// expected-error@#4{{{only 1 name was provided}}}
22+
auto [..., b] = arr; // #5
23+
// expected-error@#5{{expected identifier}}
24+
// expected-error@#5{{{no names were provided}}}
1125
}

clang/test/SemaCXX/cxx2c-binding-pack.cpp

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// RUN: %clang_cc1 -fsyntax-only -std=c++26 %s -verify
2-
// expected-no-diagnostics
32

43
template <typename T>
54
struct type_ { };
@@ -8,9 +7,9 @@ template <typename ...T>
87
auto sum(T... t) { return (t + ...); }
98

109
struct my_struct {
11-
int a;
12-
int b;
13-
int c;
10+
int a;
11+
int b;
12+
int c;
1413
int d;
1514
};
1615

@@ -74,6 +73,14 @@ void decompose_array() {
7473
int size = sizeof...(rest);
7574
T arr2[sizeof...(rest)] = {rest...};
7675
auto [...pack] = arr2;
76+
77+
// Array of size 1.
78+
int arr1[1] = {1};
79+
auto [a, ...b] = arr1;
80+
static_assert(sizeof...(b) == 0);
81+
auto [...c] = arr1;
82+
static_assert(sizeof...(c) == 1);
83+
auto [a1, ...b1, c1] = arr1; // expected-error{{decomposes into 1 element, but 3 names were provided}}
7784
}
7885

7986
// Test case by Younan Zhang.
@@ -115,3 +122,57 @@ int main() {
115122
S<1, 2, 3, 4>::N<5, 6>().foo();
116123
decompose_bit_field<bit_fields>();
117124
}
125+
126+
// P1061R10 Stuff
127+
namespace {
128+
struct C { int x, y, z; };
129+
130+
template <class T>
131+
void now_i_know_my() {
132+
auto [a, b, c] = C(); // OK, SB0 is a, SB1 is b, and SB2 is c
133+
auto [d, ...e] = C(); // OK, SB0 is d, the pack e (v1) contains two structured bindings: SB1 and SB2
134+
static_assert(sizeof...(e) == 2);
135+
auto [...f, g] = C(); // OK, the pack f (v0) contains two structured bindings: SB0 and SB1, and SB2 is g
136+
static_assert(sizeof...(e) == 2);
137+
auto [h, i, j, ...k] = C(); // OK, the pack k is empty
138+
static_assert(sizeof...(e) == 0);
139+
auto [l, m, n, o, ...p] = C(); // expected-error{{{decomposes into 3 elements, but 5 names were provided}}}
140+
}
141+
} // namespace
142+
143+
namespace {
144+
auto g() -> int(&)[4];
145+
146+
template <unsigned long N>
147+
void h(int (&arr)[N]) {
148+
auto [a, ...b, c] = arr; // a names the first element of the array,
149+
// b is a pack referring to the second and
150+
// third elements, and c names the fourth element
151+
static_assert(sizeof...(b) == 2);
152+
auto& [...e] = arr; // e is a pack referring to the four elements of the array
153+
static_assert(sizeof...(e) == 4);
154+
}
155+
156+
void call_h() {
157+
h(g());
158+
}
159+
} // namespace
160+
161+
namespace {
162+
struct D { };
163+
164+
int g(...) { return 1; }
165+
166+
template <typename T>
167+
constexpr int f() {
168+
D arr[1];
169+
auto [...e] = arr;
170+
return g(e...);
171+
}
172+
173+
constexpr int g(D) { return 2; }
174+
175+
void other_main() {
176+
static_assert(f<int>() == 2);
177+
}
178+
} // namespace

0 commit comments

Comments
 (0)