-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang][P1061] Add stuctured binding packs #121417
Changes from 1 commit
3c81c5b
116aff1
66ff7c6
5720bd3
ffefb67
685f947
d957783
91ca5b4
abab5cf
80acb71
360708d
ea249ac
dda9d89
0b83b99
d496c54
d064095
97257d7
39ab76e
765db8a
8cf8205
6d49a3d
5c351d7
5302830
e497a0c
5751d2f
36f8029
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5321,6 +5321,54 @@ class BuiltinBitCastExpr final | |||||
} | ||||||
}; | ||||||
|
||||||
class ResolvedUnexpandedPackExpr final | ||||||
cor3ntin marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
: public Expr, | ||||||
private llvm::TrailingObjects<ResolvedUnexpandedPackExpr, Stmt *> { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only place you're using this as a Stmt is for children, and the cast that way is 'safe' (and Expr isa Stmt). This change likely saves a bunch of casting elsewhere. |
||||||
friend TrailingObjects; | ||||||
|
||||||
SourceLocation BeginLoc; | ||||||
unsigned NumExprs; | ||||||
|
||||||
ResolvedUnexpandedPackExpr(SourceLocation BL, QualType QT, unsigned NumExprs); | ||||||
|
||||||
public: | ||||||
static ResolvedUnexpandedPackExpr *CreateDeserialized(ASTContext &C, | ||||||
unsigned NumExprs); | ||||||
static ResolvedUnexpandedPackExpr * | ||||||
Create(ASTContext &C, SourceLocation BeginLoc, QualType T, unsigned NumExprs); | ||||||
static ResolvedUnexpandedPackExpr *Create(ASTContext &C, | ||||||
SourceLocation BeginLoc, QualType T, | ||||||
llvm::ArrayRef<Expr *> Exprs); | ||||||
|
||||||
unsigned getNumExprs() const { return NumExprs; } | ||||||
|
||||||
Expr **getExprs() { | ||||||
return reinterpret_cast<Expr **>(getTrailingObjects<Stmt *>()); | ||||||
} | ||||||
Expr *const *getExprs() const { | ||||||
return reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>()); | ||||||
} | ||||||
|
||||||
Expr *getExpansion(unsigned Idx) { return getExprs()[Idx]; } | ||||||
Expr *getExpansion(unsigned Idx) const { return getExprs()[Idx]; } | ||||||
|
||||||
// Iterators | ||||||
child_range children() { | ||||||
return child_range(getTrailingObjects<Stmt *>(), | ||||||
getTrailingObjects<Stmt *>() + getNumExprs()); | ||||||
} | ||||||
|
||||||
SourceLocation getBeginLoc() const LLVM_READONLY { return BeginLoc; } | ||||||
SourceLocation getEndLoc() const LLVM_READONLY { return BeginLoc; } | ||||||
|
||||||
// Returns the resolved pack of a decl or nullptr | ||||||
static ResolvedUnexpandedPackExpr *getFromDecl(Decl *); | ||||||
|
||||||
static bool classof(const Stmt *T) { | ||||||
return T->getStmtClass() == ResolvedUnexpandedPackExprClass; | ||||||
} | ||||||
}; | ||||||
|
||||||
} // namespace clang | ||||||
|
||||||
#endif // LLVM_CLANG_AST_EXPRCXX_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12726,11 +12726,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { | |
|
||
// Likewise, variables with tuple-like bindings are required if their | ||
// bindings have side-effects. | ||
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) | ||
for (const auto *BD : DD->bindings()) | ||
if (const auto *BindingVD = BD->getHoldingVar()) | ||
if (DeclMustBeEmitted(BindingVD)) | ||
return true; | ||
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) { | ||
bool BindingResult = false; | ||
DD->VisitHoldingVars([&](VarDecl *BindingVD) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of a 'Visit' here, I wonder if there is value with some sort of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just added a flat_binding_iterator to replace these Visit* functions. I forgot to use it here, but if a custom iterator is what you wanted, please consider it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be a little surprised if there wasn't an existing iterator type that would work. If not though, I'd vastly prefer removing both of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I replaced the Visit functions with |
||
if (DeclMustBeEmitted(BindingVD)) | ||
BindingResult = true; | ||
}); | ||
if (BindingResult) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3395,26 +3395,37 @@ VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() { | |
if (auto *Var = llvm::dyn_cast<VarDecl>(this)) | ||
return Var; | ||
if (auto *BD = llvm::dyn_cast<BindingDecl>(this)) | ||
return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl()); | ||
return llvm::dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl()); | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return nullptr; | ||
} | ||
|
||
void BindingDecl::anchor() {} | ||
|
||
BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation IdLoc, IdentifierInfo *Id) { | ||
return new (C, DC) BindingDecl(DC, IdLoc, Id); | ||
SourceLocation IdLoc, IdentifierInfo *Id, | ||
QualType T) { | ||
return new (C, DC) BindingDecl(DC, IdLoc, Id, T); | ||
} | ||
|
||
BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); | ||
return new (C, ID) | ||
BindingDecl(nullptr, SourceLocation(), nullptr, QualType()); | ||
} | ||
|
||
VarDecl *BindingDecl::getHoldingVar() const { | ||
Expr *B = getBinding(); | ||
if (!B) | ||
return nullptr; | ||
auto *DRE = dyn_cast<DeclRefExpr>(B->IgnoreImplicit()); | ||
return getHoldingVar(B); | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
VarDecl *BindingDecl::getHoldingVar(Expr *E) { | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreImplicit()); | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!DRE) | ||
return nullptr; | ||
if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) { | ||
zyn0217 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
DRE = dyn_cast<DeclRefExpr>(BD->getBinding()); | ||
} | ||
if (!DRE) | ||
return nullptr; | ||
|
||
|
@@ -3423,6 +3434,45 @@ VarDecl *BindingDecl::getHoldingVar() const { | |
return VD; | ||
} | ||
|
||
void DecompositionDecl::VisitHoldingVars( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than both of these functions, I'd prefer we have some sort of iterators that allow standard iteration over these. We have 'filter' iterators already that take a lambda that we could define to allow going through these. The visitation can be nice, but it has the requirement of going through every element even when we only care about 'the first of'. |
||
llvm::function_ref<void(VarDecl *)> F) const { | ||
for (BindingDecl *B : bindings()) { | ||
Expr *BE = B->getBinding(); | ||
// All BindingDecls will contain holding vars or none will | ||
if (!BE) | ||
return; | ||
|
||
llvm::ArrayRef<Expr *> Exprs; | ||
if (auto *RP = dyn_cast<ResolvedUnexpandedPackExpr>(BE)) | ||
Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs()); | ||
else | ||
Exprs = BE; | ||
|
||
for (Expr *E : Exprs) { | ||
VarDecl *VD = BindingDecl::getHoldingVar(E); | ||
if (!VD) | ||
return; | ||
F(VD); | ||
} | ||
} | ||
} | ||
|
||
void DecompositionDecl::VisitBindings( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is a bit more complicated? But I'd be surprised if there isn't an existing llvm iterator that can do this. |
||
llvm::function_ref<void(BindingDecl *)> F) const { | ||
for (BindingDecl *B : bindings()) { | ||
llvm::ArrayRef<Expr *> Exprs; | ||
if (B->isParameterPack()) { | ||
auto *RP = cast<ResolvedUnexpandedPackExpr>(B->getBinding()); | ||
Exprs = llvm::ArrayRef(RP->getExprs(), RP->getNumExprs()); | ||
for (Expr *E : Exprs) { | ||
auto *DRE = cast<DeclRefExpr>(E); | ||
F(cast<BindingDecl>(DRE->getDecl())); | ||
} | ||
} else | ||
F(B); | ||
} | ||
} | ||
|
||
void DecompositionDecl::anchor() {} | ||
|
||
DecompositionDecl *DecompositionDecl::Create(ASTContext &C, DeclContext *DC, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get the comment to move as well? Or at least an updated one?