Skip to content

Commit e5f2dd4

Browse files
committed
[Clang] [C++26] Expansion Statements (Part 1)
1 parent e06c148 commit e5f2dd4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1744
-37
lines changed

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,12 @@ class ASTNodeTraverser
959959
}
960960
}
961961

962+
void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *Node) {
963+
Visit(Node->getExpansionPattern());
964+
if (Traversal != TK_IgnoreUnlessSpelledInSource)
965+
Visit(Node->getInstantiations());
966+
}
967+
962968
void VisitCallExpr(const CallExpr *Node) {
963969
for (const auto *Child :
964970
make_filter_range(Node->children(), [this](const Stmt *Child) {

clang/include/clang/AST/ComputeDependence.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class DesignatedInitExpr;
9494
class ParenListExpr;
9595
class PseudoObjectExpr;
9696
class AtomicExpr;
97+
class CXXExpansionInitListExpr;
9798
class ArraySectionExpr;
9899
class OMPArrayShapingExpr;
99100
class OMPIteratorExpr;
@@ -191,6 +192,8 @@ ExprDependence computeDependence(ParenListExpr *E);
191192
ExprDependence computeDependence(PseudoObjectExpr *E);
192193
ExprDependence computeDependence(AtomicExpr *E);
193194

195+
ExprDependence computeDependence(CXXExpansionInitListExpr *E);
196+
194197
ExprDependence computeDependence(ArraySectionExpr *E);
195198
ExprDependence computeDependence(OMPArrayShapingExpr *E);
196199
ExprDependence computeDependence(OMPIteratorExpr *E);

clang/include/clang/AST/Decl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1254,7 +1254,9 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
12541254
if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
12551255
return false;
12561256
if (const DeclContext *DC = getLexicalDeclContext())
1257-
return DC->getRedeclContext()->isFunctionOrMethod();
1257+
return DC->getEnclosingNonExpansionStatementContext()
1258+
->getRedeclContext()
1259+
->isFunctionOrMethod();
12581260
return false;
12591261
}
12601262

clang/include/clang/AST/DeclBase.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,6 +2195,10 @@ class DeclContext {
21952195
return getDeclKind() == Decl::RequiresExprBody;
21962196
}
21972197

2198+
bool isExpansionStmt() const {
2199+
return getDeclKind() == Decl::CXXExpansionStmt;
2200+
}
2201+
21982202
bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
21992203

22002204
bool isStdNamespace() const;
@@ -2292,6 +2296,15 @@ class DeclContext {
22922296
return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext();
22932297
}
22942298

2299+
/// Retrieve the innermost enclosing context that doesn't belong to an
2300+
/// expansion statement. Returns 'this' if this context is not an expansion
2301+
/// statement.
2302+
DeclContext *getEnclosingNonExpansionStatementContext();
2303+
const DeclContext *getEnclosingNonExpansionStatementContext() const {
2304+
return const_cast<DeclContext *>(this)
2305+
->getEnclosingNonExpansionStatementContext();
2306+
}
2307+
22952308
/// Test if this context is part of the enclosing namespace set of
22962309
/// the context NS, as defined in C++0x [namespace.def]p9. If either context
22972310
/// isn't a namespace, this is equivalent to Equals().

clang/include/clang/AST/DeclTemplate.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
33433343
static bool classofKind(Kind K) { return K == TemplateParamObject; }
33443344
};
33453345

3346+
/// Represents a C++26 expansion statement declaration.
3347+
///
3348+
/// This is a bit of a hack, since expansion statements shouldn't really be
3349+
/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
3350+
/// need them to be declaration *contexts*, because the DeclContext is used to
3351+
/// compute the 'template depth' of entities enclosed therein. In particular,
3352+
/// the 'template depth' is used to find instantiations of parameter variables,
3353+
/// and a lambda enclosed within an expansion statement cannot compute its
3354+
/// template depth without a pointer to the enclosing expansion statement.
3355+
///
3356+
/// For the remainder of this comment, let 'expanding' an expansion statement
3357+
/// refer to the process of performing template substitution on its body N
3358+
/// times, where N is the expansion size (how this size is determined depends on
3359+
/// the kind of expansion statement); by contrast we may sometimes 'instantiate'
3360+
/// an expansion statement (because it happens to be in a template). This is
3361+
/// just regular template instantiation.
3362+
///
3363+
/// Apart from a template parameter list that contains a template parameter used
3364+
/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
3365+
/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
3366+
/// distinct representations of the expansion statement: the former is used
3367+
/// prior to expansion and contains all the parts needed to perform expansion;
3368+
/// the latter holds the expanded/desugared AST nodes that result from the
3369+
/// expansion.
3370+
///
3371+
/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and left
3372+
/// as-is; this also means that, if an already-expanded expansion statement is
3373+
/// inside a template, and that template is then instantiated, the
3374+
/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
3375+
/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
3376+
/// codegen and constant evaluation.
3377+
///
3378+
/// For example, if the user writes the following expansion statement:
3379+
/// \verbatim
3380+
/// std::tuple<int, int, int> a{1, 2, 3};
3381+
/// template for (auto x : a) {
3382+
/// // ...
3383+
/// }
3384+
/// \endverbatim
3385+
///
3386+
/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is a
3387+
/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
3388+
/// the declaration of the variable 'x' as well as the expansion-initializer
3389+
/// 'a'.
3390+
///
3391+
/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
3392+
/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
3393+
///
3394+
/// \verbatim
3395+
/// {
3396+
/// auto [__u0, __u1, __u2] = a;
3397+
/// {
3398+
/// auto x = __u0;
3399+
/// // ...
3400+
/// }
3401+
/// {
3402+
/// auto x = __u1;
3403+
/// // ...
3404+
/// }
3405+
/// {
3406+
/// auto x = __u2;
3407+
/// // ...
3408+
/// }
3409+
/// }
3410+
/// \endverbatim
3411+
///
3412+
/// The outer braces shown above are implicit; we don't actually create another
3413+
/// CompoundStmt wrapping everything.
3414+
///
3415+
/// \see CXXExpansionStmtPattern
3416+
/// \see CXXExpansionStmtInstantiation
3417+
class CXXExpansionStmtDecl : public Decl, public DeclContext {
3418+
CXXExpansionStmtPattern *Expansion = nullptr;
3419+
TemplateParameterList *TParams;
3420+
CXXExpansionStmtInstantiation *Instantiations = nullptr;
3421+
3422+
CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc,
3423+
TemplateParameterList *TParams);
3424+
3425+
public:
3426+
friend class ASTDeclReader;
3427+
3428+
static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC,
3429+
SourceLocation Loc,
3430+
TemplateParameterList *TParams);
3431+
static CXXExpansionStmtDecl *CreateDeserialized(ASTContext &C,
3432+
GlobalDeclID ID);
3433+
3434+
CXXExpansionStmtPattern *getExpansionPattern() { return Expansion; }
3435+
const CXXExpansionStmtPattern *getExpansionPattern() const {
3436+
return Expansion;
3437+
}
3438+
void setExpansionPattern(CXXExpansionStmtPattern *S) { Expansion = S; }
3439+
3440+
CXXExpansionStmtInstantiation *getInstantiations() { return Instantiations; }
3441+
const CXXExpansionStmtInstantiation *getInstantiations() const {
3442+
return Instantiations;
3443+
}
3444+
3445+
void setInstantiations(CXXExpansionStmtInstantiation *S) {
3446+
Instantiations = S;
3447+
}
3448+
3449+
NonTypeTemplateParmDecl *getIndexTemplateParm() const {
3450+
return cast<NonTypeTemplateParmDecl>(TParams->getParam(0));
3451+
}
3452+
TemplateParameterList *getTemplateParameters() const { return TParams; }
3453+
3454+
SourceRange getSourceRange() const override LLVM_READONLY;
3455+
3456+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
3457+
static bool classofKind(Kind K) { return K == CXXExpansionStmt; }
3458+
};
3459+
33463460
inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
33473461
if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>())
33483462
return PD;

clang/include/clang/AST/ExprCXX.h

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final
54995499
}
55005500
};
55015501

5502+
/// Represents an expansion-init-list of an enumerating expansion statement.
5503+
///
5504+
/// \see CXXEnumeratingExpansionStmtPattern
5505+
class CXXExpansionInitListExpr final
5506+
: public Expr,
5507+
llvm::TrailingObjects<CXXExpansionInitListExpr, Expr *> {
5508+
friend class ASTStmtReader;
5509+
friend TrailingObjects;
5510+
5511+
const unsigned NumExprs;
5512+
SourceLocation LBraceLoc;
5513+
SourceLocation RBraceLoc;
5514+
5515+
CXXExpansionInitListExpr(EmptyShell ES, unsigned NumExprs);
5516+
CXXExpansionInitListExpr(ArrayRef<Expr *> Exprs, SourceLocation LBraceLoc,
5517+
SourceLocation RBraceLoc);
5518+
5519+
public:
5520+
static CXXExpansionInitListExpr *Create(const ASTContext &C,
5521+
ArrayRef<Expr *> Exprs,
5522+
SourceLocation LBraceLoc,
5523+
SourceLocation RBraceLoc);
5524+
5525+
static CXXExpansionInitListExpr *
5526+
CreateEmpty(const ASTContext &C, EmptyShell Empty, unsigned NumExprs);
5527+
5528+
ArrayRef<Expr *> getExprs() const { return getTrailingObjects(NumExprs); }
5529+
MutableArrayRef<Expr *> getExprs() { return getTrailingObjects(NumExprs); }
5530+
unsigned getNumExprs() const { return NumExprs; }
5531+
5532+
bool containsPackExpansion() const;
5533+
5534+
SourceLocation getBeginLoc() const { return getLBraceLoc(); }
5535+
SourceLocation getEndLoc() const { return getRBraceLoc(); }
5536+
5537+
SourceLocation getLBraceLoc() const { return LBraceLoc; }
5538+
SourceLocation getRBraceLoc() const { return RBraceLoc; }
5539+
5540+
child_range children() {
5541+
const_child_range CCR =
5542+
const_cast<const CXXExpansionInitListExpr *>(this)->children();
5543+
return child_range(cast_away_const(CCR.begin()),
5544+
cast_away_const(CCR.end()));
5545+
}
5546+
5547+
const_child_range children() const {
5548+
Stmt **Stmts = getTrailingStmts();
5549+
return const_child_range(Stmts, Stmts + NumExprs);
5550+
}
5551+
5552+
static bool classof(const Stmt *T) {
5553+
return T->getStmtClass() == CXXExpansionInitListExprClass;
5554+
}
5555+
5556+
private:
5557+
Stmt **getTrailingStmts() const {
5558+
return reinterpret_cast<Stmt **>(const_cast<Expr **>(getTrailingObjects()));
5559+
}
5560+
};
5561+
5562+
/// Helper that selects an expression from an expansion init list depending
5563+
/// on the current expansion index.
5564+
///
5565+
/// \see CXXEnumeratingExpansionStmtPattern
5566+
class CXXExpansionInitListSelectExpr : public Expr {
5567+
friend class ASTStmtReader;
5568+
5569+
enum SubExpr { RANGE, INDEX, COUNT };
5570+
Expr *SubExprs[COUNT];
5571+
5572+
public:
5573+
CXXExpansionInitListSelectExpr(EmptyShell Empty);
5574+
CXXExpansionInitListSelectExpr(const ASTContext &C,
5575+
CXXExpansionInitListExpr *Range, Expr *Idx);
5576+
5577+
CXXExpansionInitListExpr *getRangeExpr() {
5578+
return cast<CXXExpansionInitListExpr>(SubExprs[RANGE]);
5579+
}
5580+
5581+
const CXXExpansionInitListExpr *getRangeExpr() const {
5582+
return cast<CXXExpansionInitListExpr>(SubExprs[RANGE]);
5583+
}
5584+
5585+
void setRangeExpr(CXXExpansionInitListExpr *E) { SubExprs[RANGE] = E; }
5586+
5587+
Expr *getIndexExpr() { return SubExprs[INDEX]; }
5588+
const Expr *getIndexExpr() const { return SubExprs[INDEX]; }
5589+
void setIndexExpr(Expr *E) { SubExprs[INDEX] = E; }
5590+
5591+
SourceLocation getBeginLoc() const { return getRangeExpr()->getBeginLoc(); }
5592+
SourceLocation getEndLoc() const { return getRangeExpr()->getEndLoc(); }
5593+
5594+
child_range children() {
5595+
return child_range(reinterpret_cast<Stmt **>(SubExprs),
5596+
reinterpret_cast<Stmt **>(SubExprs + COUNT));
5597+
}
5598+
5599+
const_child_range children() const {
5600+
return const_child_range(
5601+
reinterpret_cast<Stmt **>(const_cast<Expr **>(SubExprs)),
5602+
reinterpret_cast<Stmt **>(const_cast<Expr **>(SubExprs + COUNT)));
5603+
}
5604+
5605+
static bool classof(const Stmt *T) {
5606+
return T->getStmtClass() == CXXExpansionInitListSelectExprClass;
5607+
}
5608+
};
5609+
5610+
/// This class serves the same purpose as CXXExpansionInitListSelectExpr, but
5611+
/// for destructuring expansion statements; that is, instead of selecting among
5612+
/// a list of expressions, it selects from a list of 'BindingDecl's.
5613+
///
5614+
/// \see CXXEnumeratingExpansionStmtPattern
5615+
/// \see CXXDestructuringExpansionStmtPattern
5616+
class CXXDestructuringExpansionSelectExpr : public Expr {
5617+
friend class ASTStmtReader;
5618+
5619+
DecompositionDecl *Decomposition;
5620+
Expr *Index;
5621+
5622+
public:
5623+
CXXDestructuringExpansionSelectExpr(EmptyShell Empty);
5624+
CXXDestructuringExpansionSelectExpr(const ASTContext &C,
5625+
DecompositionDecl *Decomposition,
5626+
Expr *Index);
5627+
5628+
DecompositionDecl *getDecompositionDecl() {
5629+
return cast<DecompositionDecl>(Decomposition);
5630+
}
5631+
5632+
const DecompositionDecl *getDecompositionDecl() const {
5633+
return cast<DecompositionDecl>(Decomposition);
5634+
}
5635+
5636+
void setDecompositionDecl(DecompositionDecl *E) { Decomposition = E; }
5637+
5638+
Expr *getIndexExpr() { return Index; }
5639+
const Expr *getIndexExpr() const { return Index; }
5640+
void setIndexExpr(Expr *E) { Index = E; }
5641+
5642+
SourceLocation getBeginLoc() const { return Decomposition->getBeginLoc(); }
5643+
SourceLocation getEndLoc() const { return Decomposition->getEndLoc(); }
5644+
5645+
child_range children() {
5646+
return child_range(reinterpret_cast<Stmt **>(&Index),
5647+
reinterpret_cast<Stmt **>(&Index + 1));
5648+
}
5649+
5650+
const_child_range children() const {
5651+
return const_child_range(
5652+
reinterpret_cast<Stmt **>(const_cast<Expr **>(&Index)),
5653+
reinterpret_cast<Stmt **>(const_cast<Expr **>(&Index + 1)));
5654+
}
5655+
5656+
static bool classof(const Stmt *T) {
5657+
return T->getStmtClass() == CXXDestructuringExpansionSelectExprClass;
5658+
}
5659+
};
5660+
55025661
} // namespace clang
55035662

55045663
#endif // LLVM_CLANG_AST_EXPRCXX_H

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,14 @@ DEF_TRAVERSE_DECL(UsingShadowDecl, {})
18811881

18821882
DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {})
18831883

1884+
DEF_TRAVERSE_DECL(CXXExpansionStmtDecl, {
1885+
if (D->getInstantiations() &&
1886+
getDerived().shouldVisitTemplateInstantiations())
1887+
TRY_TO(TraverseStmt(D->getInstantiations()));
1888+
1889+
TRY_TO(TraverseStmt(D->getExpansionPattern()));
1890+
})
1891+
18841892
DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
18851893
for (auto *I : D->varlist()) {
18861894
TRY_TO(TraverseStmt(I));
@@ -3117,6 +3125,15 @@ DEF_TRAVERSE_STMT(RequiresExpr, {
31173125
TRY_TO(TraverseConceptRequirement(Req));
31183126
})
31193127

3128+
DEF_TRAVERSE_STMT(CXXEnumeratingExpansionStmtPattern, {})
3129+
DEF_TRAVERSE_STMT(CXXIteratingExpansionStmtPattern, {})
3130+
DEF_TRAVERSE_STMT(CXXDestructuringExpansionStmtPattern, {})
3131+
DEF_TRAVERSE_STMT(CXXDependentExpansionStmtPattern, {})
3132+
DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {})
3133+
DEF_TRAVERSE_STMT(CXXExpansionInitListExpr, {})
3134+
DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {})
3135+
DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {})
3136+
31203137
// These literals (all of them) do not need any action.
31213138
DEF_TRAVERSE_STMT(IntegerLiteral, {})
31223139
DEF_TRAVERSE_STMT(FixedPointLiteral, {})

0 commit comments

Comments
 (0)