From e5f2dd466d5126594a159fc37a96ba6b54978e26 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Tue, 25 Nov 2025 17:18:05 +0100 Subject: [PATCH 1/9] [Clang] [C++26] Expansion Statements (Part 1) --- clang/include/clang/AST/ASTNodeTraverser.h | 6 + clang/include/clang/AST/ComputeDependence.h | 3 + clang/include/clang/AST/Decl.h | 4 +- clang/include/clang/AST/DeclBase.h | 13 + clang/include/clang/AST/DeclTemplate.h | 114 +++++ clang/include/clang/AST/ExprCXX.h | 159 ++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 17 + clang/include/clang/AST/StmtCXX.h | 478 ++++++++++++++++++ clang/include/clang/AST/TextNodeDumper.h | 5 + clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Basic/StmtNodes.td | 14 + .../include/clang/Serialization/ASTBitCodes.h | 41 +- clang/lib/AST/ASTImporter.cpp | 174 +++++++ clang/lib/AST/ComputeDependence.cpp | 7 + clang/lib/AST/DeclBase.cpp | 14 +- clang/lib/AST/DeclPrinter.cpp | 6 + clang/lib/AST/DeclTemplate.cpp | 23 + clang/lib/AST/Expr.cpp | 3 + clang/lib/AST/ExprCXX.cpp | 58 +++ clang/lib/AST/ExprClassification.cpp | 3 + clang/lib/AST/ExprConstant.cpp | 3 + clang/lib/AST/ItaniumMangle.cpp | 10 +- clang/lib/AST/StmtCXX.cpp | 153 ++++++ clang/lib/AST/StmtPrinter.cpp | 62 ++- clang/lib/AST/StmtProfile.cpp | 47 ++ clang/lib/AST/TextNodeDumper.cpp | 23 +- clang/lib/Sema/Sema.cpp | 7 +- clang/lib/Sema/SemaDecl.cpp | 4 +- clang/lib/Sema/SemaExceptionSpec.cpp | 8 + clang/lib/Sema/SemaExpr.cpp | 5 +- clang/lib/Sema/SemaExprCXX.cpp | 1 - clang/lib/Sema/SemaLambda.cpp | 28 +- clang/lib/Sema/SemaLookup.cpp | 4 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 + clang/lib/Sema/TreeTransform.h | 53 ++ clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 12 + clang/lib/Serialization/ASTReaderStmt.cpp | 107 ++++ clang/lib/Serialization/ASTWriterDecl.cpp | 9 + clang/lib/Serialization/ASTWriterStmt.cpp | 79 +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 8 + clang/tools/libclang/CIndex.cpp | 1 + clang/tools/libclang/CXCursor.cpp | 8 + 43 files changed, 1744 insertions(+), 37 deletions(-) diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index e74bb72571d64..fd64d86f83bfd 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -959,6 +959,12 @@ class ASTNodeTraverser } } + void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *Node) { + Visit(Node->getExpansionPattern()); + if (Traversal != TK_IgnoreUnlessSpelledInSource) + Visit(Node->getInstantiations()); + } + void VisitCallExpr(const CallExpr *Node) { for (const auto *Child : make_filter_range(Node->children(), [this](const Stmt *Child) { diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index c298f2620f211..792f45bea5aeb 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -94,6 +94,7 @@ class DesignatedInitExpr; class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; +class CXXExpansionInitListExpr; class ArraySectionExpr; class OMPArrayShapingExpr; class OMPIteratorExpr; @@ -191,6 +192,8 @@ ExprDependence computeDependence(ParenListExpr *E); ExprDependence computeDependence(PseudoObjectExpr *E); ExprDependence computeDependence(AtomicExpr *E); +ExprDependence computeDependence(CXXExpansionInitListExpr *E); + ExprDependence computeDependence(ArraySectionExpr *E); ExprDependence computeDependence(OMPArrayShapingExpr *E); ExprDependence computeDependence(OMPIteratorExpr *E); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index ee2321dd158d4..b8f8e002ebcce 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1254,7 +1254,9 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; if (const DeclContext *DC = getLexicalDeclContext()) - return DC->getRedeclContext()->isFunctionOrMethod(); + return DC->getEnclosingNonExpansionStatementContext() + ->getRedeclContext() + ->isFunctionOrMethod(); return false; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 5519787d71f88..71e6898f4c94d 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -2195,6 +2195,10 @@ class DeclContext { return getDeclKind() == Decl::RequiresExprBody; } + bool isExpansionStmt() const { + return getDeclKind() == Decl::CXXExpansionStmt; + } + bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isStdNamespace() const; @@ -2292,6 +2296,15 @@ class DeclContext { return const_cast(this)->getOuterLexicalRecordContext(); } + /// Retrieve the innermost enclosing context that doesn't belong to an + /// expansion statement. Returns 'this' if this context is not an expansion + /// statement. + DeclContext *getEnclosingNonExpansionStatementContext(); + const DeclContext *getEnclosingNonExpansionStatementContext() const { + return const_cast(this) + ->getEnclosingNonExpansionStatementContext(); + } + /// Test if this context is part of the enclosing namespace set of /// the context NS, as defined in C++0x [namespace.def]p9. If either context /// isn't a namespace, this is equivalent to Equals(). diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index a4a1bb9c13c79..45a58b6589074 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl, static bool classofKind(Kind K) { return K == TemplateParamObject; } }; +/// Represents a C++26 expansion statement declaration. +/// +/// This is a bit of a hack, since expansion statements shouldn't really be +/// 'declarations' per se (they don't declare anything). Nevertheless, we *do* +/// need them to be declaration *contexts*, because the DeclContext is used to +/// compute the 'template depth' of entities enclosed therein. In particular, +/// the 'template depth' is used to find instantiations of parameter variables, +/// and a lambda enclosed within an expansion statement cannot compute its +/// template depth without a pointer to the enclosing expansion statement. +/// +/// For the remainder of this comment, let 'expanding' an expansion statement +/// refer to the process of performing template substitution on its body N +/// times, where N is the expansion size (how this size is determined depends on +/// the kind of expansion statement); by contrast we may sometimes 'instantiate' +/// an expansion statement (because it happens to be in a template). This is +/// just regular template instantiation. +/// +/// Apart from a template parameter list that contains a template parameter used +/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as +/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to +/// distinct representations of the expansion statement: the former is used +/// prior to expansion and contains all the parts needed to perform expansion; +/// the latter holds the expanded/desugared AST nodes that result from the +/// expansion. +/// +/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and left +/// as-is; this also means that, if an already-expanded expansion statement is +/// inside a template, and that template is then instantiated, the +/// 'CXXExpansionStmtPattern' is *not* instantiated; only the +/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for +/// codegen and constant evaluation. +/// +/// For example, if the user writes the following expansion statement: +/// \verbatim +/// std::tuple a{1, 2, 3}; +/// template for (auto x : a) { +/// // ... +/// } +/// \endverbatim +/// +/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is a +/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things, +/// the declaration of the variable 'x' as well as the expansion-initializer +/// 'a'. +/// +/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that +/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion: +/// +/// \verbatim +/// { +/// auto [__u0, __u1, __u2] = a; +/// { +/// auto x = __u0; +/// // ... +/// } +/// { +/// auto x = __u1; +/// // ... +/// } +/// { +/// auto x = __u2; +/// // ... +/// } +/// } +/// \endverbatim +/// +/// The outer braces shown above are implicit; we don't actually create another +/// CompoundStmt wrapping everything. +/// +/// \see CXXExpansionStmtPattern +/// \see CXXExpansionStmtInstantiation +class CXXExpansionStmtDecl : public Decl, public DeclContext { + CXXExpansionStmtPattern *Expansion = nullptr; + TemplateParameterList *TParams; + CXXExpansionStmtInstantiation *Instantiations = nullptr; + + CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, + TemplateParameterList *TParams); + +public: + friend class ASTDeclReader; + + static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, + TemplateParameterList *TParams); + static CXXExpansionStmtDecl *CreateDeserialized(ASTContext &C, + GlobalDeclID ID); + + CXXExpansionStmtPattern *getExpansionPattern() { return Expansion; } + const CXXExpansionStmtPattern *getExpansionPattern() const { + return Expansion; + } + void setExpansionPattern(CXXExpansionStmtPattern *S) { Expansion = S; } + + CXXExpansionStmtInstantiation *getInstantiations() { return Instantiations; } + const CXXExpansionStmtInstantiation *getInstantiations() const { + return Instantiations; + } + + void setInstantiations(CXXExpansionStmtInstantiation *S) { + Instantiations = S; + } + + NonTypeTemplateParmDecl *getIndexTemplateParm() const { + return cast(TParams->getParam(0)); + } + TemplateParameterList *getTemplateParameters() const { return TParams; } + + SourceRange getSourceRange() const override LLVM_READONLY; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == CXXExpansionStmt; } +}; + inline NamedDecl *getAsNamedDecl(TemplateParameter P) { if (auto *PD = P.dyn_cast()) return PD; diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 9435ab069a520..668a51dad0ae9 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final } }; +/// Represents an expansion-init-list of an enumerating expansion statement. +/// +/// \see CXXEnumeratingExpansionStmtPattern +class CXXExpansionInitListExpr final + : public Expr, + llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; + + const unsigned NumExprs; + SourceLocation LBraceLoc; + SourceLocation RBraceLoc; + + CXXExpansionInitListExpr(EmptyShell ES, unsigned NumExprs); + CXXExpansionInitListExpr(ArrayRef Exprs, SourceLocation LBraceLoc, + SourceLocation RBraceLoc); + +public: + static CXXExpansionInitListExpr *Create(const ASTContext &C, + ArrayRef Exprs, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc); + + static CXXExpansionInitListExpr * + CreateEmpty(const ASTContext &C, EmptyShell Empty, unsigned NumExprs); + + ArrayRef getExprs() const { return getTrailingObjects(NumExprs); } + MutableArrayRef getExprs() { return getTrailingObjects(NumExprs); } + unsigned getNumExprs() const { return NumExprs; } + + bool containsPackExpansion() const; + + SourceLocation getBeginLoc() const { return getLBraceLoc(); } + SourceLocation getEndLoc() const { return getRBraceLoc(); } + + SourceLocation getLBraceLoc() const { return LBraceLoc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + + child_range children() { + const_child_range CCR = + const_cast(this)->children(); + return child_range(cast_away_const(CCR.begin()), + cast_away_const(CCR.end())); + } + + const_child_range children() const { + Stmt **Stmts = getTrailingStmts(); + return const_child_range(Stmts, Stmts + NumExprs); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXExpansionInitListExprClass; + } + +private: + Stmt **getTrailingStmts() const { + return reinterpret_cast(const_cast(getTrailingObjects())); + } +}; + +/// Helper that selects an expression from an expansion init list depending +/// on the current expansion index. +/// +/// \see CXXEnumeratingExpansionStmtPattern +class CXXExpansionInitListSelectExpr : public Expr { + friend class ASTStmtReader; + + enum SubExpr { RANGE, INDEX, COUNT }; + Expr *SubExprs[COUNT]; + +public: + CXXExpansionInitListSelectExpr(EmptyShell Empty); + CXXExpansionInitListSelectExpr(const ASTContext &C, + CXXExpansionInitListExpr *Range, Expr *Idx); + + CXXExpansionInitListExpr *getRangeExpr() { + return cast(SubExprs[RANGE]); + } + + const CXXExpansionInitListExpr *getRangeExpr() const { + return cast(SubExprs[RANGE]); + } + + void setRangeExpr(CXXExpansionInitListExpr *E) { SubExprs[RANGE] = E; } + + Expr *getIndexExpr() { return SubExprs[INDEX]; } + const Expr *getIndexExpr() const { return SubExprs[INDEX]; } + void setIndexExpr(Expr *E) { SubExprs[INDEX] = E; } + + SourceLocation getBeginLoc() const { return getRangeExpr()->getBeginLoc(); } + SourceLocation getEndLoc() const { return getRangeExpr()->getEndLoc(); } + + child_range children() { + return child_range(reinterpret_cast(SubExprs), + reinterpret_cast(SubExprs + COUNT)); + } + + const_child_range children() const { + return const_child_range( + reinterpret_cast(const_cast(SubExprs)), + reinterpret_cast(const_cast(SubExprs + COUNT))); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXExpansionInitListSelectExprClass; + } +}; + +/// This class serves the same purpose as CXXExpansionInitListSelectExpr, but +/// for destructuring expansion statements; that is, instead of selecting among +/// a list of expressions, it selects from a list of 'BindingDecl's. +/// +/// \see CXXEnumeratingExpansionStmtPattern +/// \see CXXDestructuringExpansionStmtPattern +class CXXDestructuringExpansionSelectExpr : public Expr { + friend class ASTStmtReader; + + DecompositionDecl *Decomposition; + Expr *Index; + +public: + CXXDestructuringExpansionSelectExpr(EmptyShell Empty); + CXXDestructuringExpansionSelectExpr(const ASTContext &C, + DecompositionDecl *Decomposition, + Expr *Index); + + DecompositionDecl *getDecompositionDecl() { + return cast(Decomposition); + } + + const DecompositionDecl *getDecompositionDecl() const { + return cast(Decomposition); + } + + void setDecompositionDecl(DecompositionDecl *E) { Decomposition = E; } + + Expr *getIndexExpr() { return Index; } + const Expr *getIndexExpr() const { return Index; } + void setIndexExpr(Expr *E) { Index = E; } + + SourceLocation getBeginLoc() const { return Decomposition->getBeginLoc(); } + SourceLocation getEndLoc() const { return Decomposition->getEndLoc(); } + + child_range children() { + return child_range(reinterpret_cast(&Index), + reinterpret_cast(&Index + 1)); + } + + const_child_range children() const { + return const_child_range( + reinterpret_cast(const_cast(&Index)), + reinterpret_cast(const_cast(&Index + 1))); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDestructuringExpansionSelectExprClass; + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 8f427427d71ed..24052df70c7a8 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1881,6 +1881,14 @@ DEF_TRAVERSE_DECL(UsingShadowDecl, {}) DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {}) +DEF_TRAVERSE_DECL(CXXExpansionStmtDecl, { + if (D->getInstantiations() && + getDerived().shouldVisitTemplateInstantiations()) + TRY_TO(TraverseStmt(D->getInstantiations())); + + TRY_TO(TraverseStmt(D->getExpansionPattern())); +}) + DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { for (auto *I : D->varlist()) { TRY_TO(TraverseStmt(I)); @@ -3117,6 +3125,15 @@ DEF_TRAVERSE_STMT(RequiresExpr, { TRY_TO(TraverseConceptRequirement(Req)); }) +DEF_TRAVERSE_STMT(CXXEnumeratingExpansionStmtPattern, {}) +DEF_TRAVERSE_STMT(CXXIteratingExpansionStmtPattern, {}) +DEF_TRAVERSE_STMT(CXXDestructuringExpansionStmtPattern, {}) +DEF_TRAVERSE_STMT(CXXDependentExpansionStmtPattern, {}) +DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {}) +DEF_TRAVERSE_STMT(CXXExpansionInitListExpr, {}) +DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {}) +DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(FixedPointLiteral, {}) diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index 5d68d3ef64a20..96c3f912d6c3e 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -22,6 +22,7 @@ namespace clang { class VarDecl; +class CXXExpansionStmtDecl; /// CXXCatchStmt - This represents a C++ catch block. /// @@ -524,6 +525,483 @@ class CoreturnStmt : public Stmt { } }; +/// CXXExpansionStmtPattern - Base class for an unexpanded C++ expansion +/// statement. +/// +/// The main purpose for this class is to store the AST nodes common to all +/// variants of expansion statements; it also provides storage for additional +/// subexpressions required by its derived classes. This is to simplify the +/// implementation of 'children()' and friends. +/// +/// \see CXXExpansionStmtDecl +/// \see CXXEnumeratingExpansionStmtPattern +/// \see CXXIteratingExpansionStmtPattern +/// \see CXXDestructuringExpansionStmtPattern +/// \see CXXDependentExpansionStmtPattern +class CXXExpansionStmtPattern : public Stmt { + friend class ASTStmtReader; + + CXXExpansionStmtDecl *ParentDecl; + SourceLocation LParenLoc; + SourceLocation ColonLoc; + SourceLocation RParenLoc; + +protected: + enum SubStmt { + INIT, + VAR, + BODY, + FIRST_CHILD_STMT, + + // CXXDependentExpansionStmtPattern + EXPANSION_INITIALIZER = FIRST_CHILD_STMT, + COUNT_CXXDependentExpansionStmtPattern, + + // CXXDestructuringExpansionStmtPattern + DECOMP_DECL = FIRST_CHILD_STMT, + COUNT_CXXDestructuringExpansionStmtPattern, + + // CXXIteratingExpansionStmtPattern + RANGE = FIRST_CHILD_STMT, + BEGIN, + END, + COUNT_CXXIteratingExpansionStmtPattern, + + MAX_COUNT = COUNT_CXXIteratingExpansionStmtPattern, + }; + + // Managing the memory for this properly would be rather complicated, and + // expansion statements are fairly uncommon, so just allocate space for the + // maximum amount of substatements we could possibly have. + Stmt *SubStmts[MAX_COUNT]; + + CXXExpansionStmtPattern(StmtClass SC, EmptyShell Empty); + CXXExpansionStmtPattern(StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc); + +public: + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceLocation getBeginLoc() const; + SourceLocation getEndLoc() const { + return getBody() ? getBody()->getEndLoc() : RParenLoc; + } + + bool hasDependentSize() const; + + CXXExpansionStmtDecl *getDecl() { return ParentDecl; } + const CXXExpansionStmtDecl *getDecl() const { return ParentDecl; } + + Stmt *getInit() { return SubStmts[INIT]; } + const Stmt *getInit() const { return SubStmts[INIT]; } + void setInit(Stmt *S) { SubStmts[INIT] = S; } + + VarDecl *getExpansionVariable(); + const VarDecl *getExpansionVariable() const { + return const_cast(this)->getExpansionVariable(); + } + + DeclStmt *getExpansionVarStmt() { return cast(SubStmts[VAR]); } + const DeclStmt *getExpansionVarStmt() const { + return cast(SubStmts[VAR]); + } + + void setExpansionVarStmt(Stmt *S) { SubStmts[VAR] = S; } + + Stmt *getBody() { return SubStmts[BODY]; } + const Stmt *getBody() const { return SubStmts[BODY]; } + void setBody(Stmt *S) { SubStmts[BODY] = S; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstCXXExpansionStmtPatternConstant && + T->getStmtClass() <= lastCXXExpansionStmtPatternConstant; + } + + child_range children() { + return child_range(SubStmts, SubStmts + FIRST_CHILD_STMT); + } + + const_child_range children() const { + return const_child_range(SubStmts, SubStmts + FIRST_CHILD_STMT); + } +}; + +/// Represents an unexpanded enumerating expansion statement. +/// +/// An 'enumerating' expansion statement is one whose expansion-initializer +/// is a brace-enclosed expression-list; this list is syntactically similar to +/// an initializer list, but it isn't actually an expression in and of itself +/// (in that it is never evaluated or emitted) and instead is just treated as +/// a group of expressions. The expansion initializer of this is always a +/// 'CXXExpansionInitListExpr'. +/// +/// Example: +/// \verbatim +/// template for (auto x : { 1, 2, 3 }) { +/// // ... +/// } +/// \endverbatim +/// +/// Note that the expression-list may also contain pack expansions, e.g. +/// '{ 1, xs... }', in which case the expansion size is dependent. +/// +/// Here, the '{ 1, 2, 3 }' is parsed as a 'CXXExpansionInitListExpr'. This node +/// handles storing (and pack-expanding) the individual expressions. +/// +/// Sema then wraps this with a 'CXXExpansionInitListSelectExpr', which also +/// contains a reference to an integral NTTP that is used as the expansion +/// index; this index is either dependent (if the expansion-size is dependent), +/// or set to a value of I in the I-th expansion during the expansion process. +/// +/// The actual expansion is done by 'BuildCXXExpansionInitListSelectExpr()': for +/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and +/// BuildCXXExpansionInitListSelectExpr(), when called via TreeTransform, +/// 'instantiates' the expression '{ a, b, c }' to just 'b'. +class CXXEnumeratingExpansionStmtPattern : public CXXExpansionStmtPattern { + friend class ASTStmtReader; + +public: + CXXEnumeratingExpansionStmtPattern(EmptyShell Empty); + CXXEnumeratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation RParenLoc); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXEnumeratingExpansionStmtPatternClass; + } +}; + +/// Represents an expansion statement whose expansion-initializer is +/// type-dependent. +/// +/// This will be instantiated as either a 'CXXIteratingExpansionStmtPattern' or +/// a 'CXXDestructuringExpansionStmtPattern'. Dependent expansion statements can +/// never be enumerating; those are always stored as a +/// 'CXXEnumeratingExpansionStmtPattern', even if the expansion size is +/// dependent because the expression-list contains a pack. +/// +/// Example: +/// \verbatim +/// template +/// void f() { +/// template for (auto x : T()) { +/// // ... +/// } +/// } +/// \endverbatim +class CXXDependentExpansionStmtPattern : public CXXExpansionStmtPattern { + friend class ASTStmtReader; + +public: + CXXDependentExpansionStmtPattern(EmptyShell Empty); + CXXDependentExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, + Expr *ExpansionInitializer, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation RParenLoc); + + Expr *getExpansionInitializer() { + return cast(SubStmts[EXPANSION_INITIALIZER]); + } + const Expr *getExpansionInitializer() const { + return cast(SubStmts[EXPANSION_INITIALIZER]); + } + void setExpansionInitializer(Expr *S) { SubStmts[EXPANSION_INITIALIZER] = S; } + + child_range children() { + return child_range(SubStmts, + SubStmts + COUNT_CXXDependentExpansionStmtPattern); + } + + const_child_range children() const { + return const_child_range(SubStmts, + SubStmts + COUNT_CXXDependentExpansionStmtPattern); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDependentExpansionStmtPatternClass; + } +}; + +/// Represents an unexpanded iterating expansion statement. +/// +/// An 'iterating' expansion statement is one whose expansion-initializer is a +/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is +/// determined based on a number of conditions as stated in [stmt.expand] and +/// [stmt.ranged]). +/// +/// The expression used to compute the size of the expansion is not stored and +/// is only created at the moment of expansion. +/// +/// Example: +/// \verbatim +/// static constexpr std::string_view foo = "1234"; +/// template for (auto x : foo) { +/// // ... +/// } +/// \endverbatim +class CXXIteratingExpansionStmtPattern : public CXXExpansionStmtPattern { + friend class ASTStmtReader; + +public: + CXXIteratingExpansionStmtPattern(EmptyShell Empty); + CXXIteratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, DeclStmt *Range, + DeclStmt *Begin, DeclStmt *End, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation RParenLoc); + + const DeclStmt *getRangeVarStmt() const { + return cast(SubStmts[RANGE]); + } + DeclStmt *getRangeVarStmt() { return cast(SubStmts[RANGE]); } + void setRangeVarStmt(DeclStmt *S) { SubStmts[RANGE] = S; } + + const VarDecl *getRangeVar() const { + return cast(getRangeVarStmt()->getSingleDecl()); + } + + VarDecl *getRangeVar() { + return cast(getRangeVarStmt()->getSingleDecl()); + } + + const DeclStmt *getBeginVarStmt() const { + return cast(SubStmts[BEGIN]); + } + DeclStmt *getBeginVarStmt() { return cast(SubStmts[BEGIN]); } + void setBeginVarStmt(DeclStmt *S) { SubStmts[BEGIN] = S; } + + const VarDecl *getBeginVar() const { + return cast(getBeginVarStmt()->getSingleDecl()); + } + + VarDecl *getBeginVar() { + return cast(getBeginVarStmt()->getSingleDecl()); + } + + const DeclStmt *getEndVarStmt() const { + return cast(SubStmts[END]); + } + DeclStmt *getEndVarStmt() { return cast(SubStmts[END]); } + void setEndVarStmt(DeclStmt *S) { SubStmts[END] = S; } + + const VarDecl *getEndVar() const { + return cast(getEndVarStmt()->getSingleDecl()); + } + + VarDecl *getEndVar() { + return cast(getEndVarStmt()->getSingleDecl()); + } + + child_range children() { + return child_range(SubStmts, + SubStmts + COUNT_CXXIteratingExpansionStmtPattern); + } + + const_child_range children() const { + return const_child_range(SubStmts, + SubStmts + COUNT_CXXIteratingExpansionStmtPattern); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXIteratingExpansionStmtPatternClass; + } +}; + +/// Represents an unexpanded destructuring expansion statement. +/// +/// A 'destructuring' expansion statement is any expansion statement that is +/// not enumerating or iterating (i.e. destructuring is the last thing we try, +/// and if it doesn't work, the program is ill-formed). +/// +/// This essentially involves treating the expansion-initializer as the +/// initializer of a structured-binding declarations, with the number of +/// bindings and expansion size determined by the usual means (array size, +/// std::tuple_size, etc.). +/// +/// Example: +/// \verbatim +/// std::array a {1, 2, 3}; +/// template for (auto x : a) { +/// // ... +/// } +/// \endverbatim +/// +/// Sema wraps the initializer with a CXXDestructuringExpansionSelectExpr, which +/// selects a binding based on the current expansion index; this is analogous to +/// how 'CXXExpansionInitListSelectExpr' is used; see the documentation of +/// 'CXXEnumeratingExpansionStmtPattern' for more details on this. +class CXXDestructuringExpansionStmtPattern : public CXXExpansionStmtPattern { + friend class ASTStmtReader; + +public: + CXXDestructuringExpansionStmtPattern(EmptyShell Empty); + CXXDestructuringExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, + Stmt *DecompositionDeclStmt, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation RParenLoc); + + Stmt *getDecompositionDeclStmt() { return SubStmts[DECOMP_DECL]; } + const Stmt *getDecompositionDeclStmt() const { return SubStmts[DECOMP_DECL]; } + void setDecompositionDeclStmt(Stmt *S) { SubStmts[DECOMP_DECL] = S; } + + DecompositionDecl *getDecompositionDecl(); + const DecompositionDecl *getDecompositionDecl() const { + return const_cast(this) + ->getDecompositionDecl(); + } + + child_range children() { + return child_range(SubStmts, + SubStmts + COUNT_CXXDestructuringExpansionStmtPattern); + } + + const_child_range children() const { + return const_child_range( + SubStmts, SubStmts + COUNT_CXXDestructuringExpansionStmtPattern); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDestructuringExpansionStmtPatternClass; + } +}; + +/// Represents the code generated for an expanded expansion statement. +/// +/// This holds 'shared statements' and 'instantiations'; these encode the +/// general underlying pattern that all expansion statements desugar to: +/// +/// \verbatim +/// { +/// +/// { +/// <1st instantiation> +/// } +/// ... +/// { +/// +/// } +/// } +/// \endverbatim +/// +/// Here, the only thing that is stored in the AST are the 'shared statements' +/// and the 'CompoundStmt's that wrap the 'instantiations'. The outer braces +/// shown above are implicit. +/// +/// For example, the CXXExpansionStmtInstantiation that corresponds to the +/// following expansion statement +/// +/// \verbatim +/// std::tuple a{1, 2, 3}; +/// template for (auto x : a) { +/// // ... +/// } +/// \endverbatim +/// +/// would be +/// +/// \verbatim +/// { +/// auto [__u0, __u1, __u2] = a; +/// { +/// auto x = __u0; +/// // ... +/// } +/// { +/// auto x = __u1; +/// // ... +/// } +/// { +/// auto x = __u2; +/// // ... +/// } +/// } +/// \endverbatim +class CXXExpansionStmtInstantiation final + : public Stmt, + llvm::TrailingObjects { + friend class ASTStmtReader; + friend TrailingObjects; + + SourceLocation BeginLoc; + SourceLocation EndLoc; + + // Instantiations are stored first, then shared statements. + const unsigned NumInstantiations : 20; + const unsigned NumSharedStmts : 3; + unsigned ShouldApplyLifetimeExtensionToSharedStmts : 1; + + CXXExpansionStmtInstantiation(EmptyShell Empty, unsigned NumInstantiations, + unsigned NumSharedStmts); + CXXExpansionStmtInstantiation(SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Instantiations, + ArrayRef SharedStmts, + bool ShouldApplyLifetimeExtensionToSharedStmts); + +public: + static CXXExpansionStmtInstantiation * + Create(ASTContext &C, SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Instantiations, ArrayRef SharedStmts, + bool ShouldApplyLifetimeExtensionToSharedStmts); + + static CXXExpansionStmtInstantiation *CreateEmpty(ASTContext &C, + EmptyShell Empty, + unsigned NumInstantiations, + unsigned NumSharedStmts); + + ArrayRef getAllSubStmts() const { + return getTrailingObjects(getNumSubStmts()); + } + + MutableArrayRef getAllSubStmts() { + return getTrailingObjects(getNumSubStmts()); + } + + unsigned getNumSubStmts() const { return NumInstantiations + NumSharedStmts; } + + ArrayRef getInstantiations() const { + return getTrailingObjects(NumInstantiations); + } + + ArrayRef getSharedStmts() const { + return getAllSubStmts().drop_front(NumInstantiations); + } + + bool shouldApplyLifetimeExtensionToSharedStmts() const { + return ShouldApplyLifetimeExtensionToSharedStmts; + } + + void setShouldApplyLifetimeExtensionToSharedStmts(bool Apply) { + ShouldApplyLifetimeExtensionToSharedStmts = Apply; + } + + SourceLocation getBeginLoc() const { return BeginLoc; } + SourceLocation getEndLoc() const { return EndLoc; } + + child_range children() { + Stmt **S = getTrailingObjects(); + return child_range(S, S + getNumSubStmts()); + } + + const_child_range children() const { + Stmt *const *S = getTrailingObjects(); + return const_child_range(S, S + getNumSubStmts()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXExpansionStmtInstantiationClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 88ecd526e3d7e..3db8ce0d5aed3 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -266,6 +266,8 @@ class TextNodeDumper void VisitCoawaitExpr(const CoawaitExpr *Node); void VisitCoreturnStmt(const CoreturnStmt *Node); void VisitCompoundStmt(const CompoundStmt *Node); + void + VisitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation *Node); void VisitConstantExpr(const ConstantExpr *Node); void VisitCallExpr(const CallExpr *Node); void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node); @@ -310,6 +312,9 @@ class TextNodeDumper void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node); + void VisitCXXDestructuringExpansionSelectExpr( + const CXXDestructuringExpansionSelectExpr *Node); + void VisitCXXExpansionInitListExpr(const CXXExpansionInitListExpr *Node); void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); void VisitObjCMessageExpr(const ObjCMessageExpr *Node); diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 04311055bb600..23f8e47939bdb 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -101,6 +101,7 @@ def AccessSpec : DeclNode; def Friend : DeclNode; def FriendTemplate : DeclNode; def StaticAssert : DeclNode; +def CXXExpansionStmt : DeclNode, DeclContext; def Block : DeclNode, DeclContext; def OutlinedFunction : DeclNode, DeclContext; def Captured : DeclNode, DeclContext; diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index bf3686bb372d5..505ed481e0895 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -58,6 +58,15 @@ def CXXForRangeStmt : StmtNode; def CoroutineBodyStmt : StmtNode; def CoreturnStmt : StmtNode; +// C++ expansion statements (P1306) +def CXXExpansionStmtPattern : StmtNode; +def CXXEnumeratingExpansionStmtPattern : StmtNode; +def CXXIteratingExpansionStmtPattern : StmtNode; +def CXXDestructuringExpansionStmtPattern : StmtNode; +def CXXDependentExpansionStmtPattern : StmtNode; +def CXXExpansionStmtInstantiation + : StmtNode; // *Not* derived from CXXExpansionStmtPattern! + // Expressions def Expr : StmtNode; def PredefinedExpr : StmtNode; @@ -177,6 +186,11 @@ def CoyieldExpr : StmtNode; def ConceptSpecializationExpr : StmtNode; def RequiresExpr : StmtNode; +// C++26 Expansion statement support expressions +def CXXExpansionInitListExpr : StmtNode; +def CXXExpansionInitListSelectExpr : StmtNode; +def CXXDestructuringExpansionSelectExpr : StmtNode; + // Obj-C Expressions. def ObjCStringLiteral : StmtNode; def ObjCBoxedExpr : StmtNode; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index d7d429eacd67a..36cccdcbd306e 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1460,6 +1460,9 @@ enum DeclCode { /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, + /// A C++ expansion statement. + DECL_EXPANSION_STMT, + /// A record containing CXXBaseSpecifiers. DECL_CXX_BASE_SPECIFIERS, @@ -1833,6 +1836,21 @@ enum StmtCode { STMT_CXX_FOR_RANGE, + /// A CXXEnumeratedExpansionStmt. + STMT_CXX_ENUMERATING_EXPANSION, + + /// A CXXIteratingExpansionStmtPattern. + STMT_CXX_ITERATING_EXPANSION, + + /// A CXXDestructuringExpansionStmtPattern. + STMT_CXX_DESTRUCTURING_EXPANSION, + + /// A CXXDependentExpansionStmtPattern, + STMT_CXX_DEPENDENT_EXPANSION, + + /// A CXXExpansionStmtInstantiation. + STMT_CXX_EXPANSION_INSTANTIATION, + /// A CXXOperatorCallExpr record. EXPR_CXX_OPERATOR_CALL, @@ -1914,16 +1932,19 @@ enum StmtCode { EXPR_TYPE_TRAIT, // TypeTraitExpr EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr - EXPR_PACK_EXPANSION, // PackExpansionExpr - EXPR_PACK_INDEXING, // PackIndexingExpr - EXPR_SIZEOF_PACK, // SizeOfPackExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr - EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr - EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr - EXPR_CXX_FOLD, // CXXFoldExpr - EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr - EXPR_REQUIRES, // RequiresExpr + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_PACK_INDEXING, // PackIndexingExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr + EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr + EXPR_REQUIRES, // RequiresExpr + EXPR_CXX_EXPANSION_INIT_LIST, // CXXExpansionInitListExpr + EXPR_CXX_EXPANSION_INIT_LIST_SELECT, // CXXExpansionInitListSelectExpr + EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT, // CXXDestructuringExpansionSelectExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index c1441744c8578..b94c18e60ba58 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -516,6 +516,7 @@ namespace clang { ExpectedDecl VisitEmptyDecl(EmptyDecl *D); ExpectedDecl VisitAccessSpecDecl(AccessSpecDecl *D); ExpectedDecl VisitStaticAssertDecl(StaticAssertDecl *D); + ExpectedDecl VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D); ExpectedDecl VisitTranslationUnitDecl(TranslationUnitDecl *D); ExpectedDecl VisitBindingDecl(BindingDecl *D); ExpectedDecl VisitNamespaceDecl(NamespaceDecl *D); @@ -608,6 +609,16 @@ namespace clang { ExpectedStmt VisitCXXCatchStmt(CXXCatchStmt *S); ExpectedStmt VisitCXXTryStmt(CXXTryStmt *S); ExpectedStmt VisitCXXForRangeStmt(CXXForRangeStmt *S); + ExpectedStmt VisitCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *S); + ExpectedStmt + VisitCXXIteratingExpansionStmtPattern(CXXIteratingExpansionStmtPattern *S); + ExpectedStmt VisitCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *S); + ExpectedStmt + VisitCXXDependentExpansionStmtPattern(CXXDependentExpansionStmtPattern *S); + ExpectedStmt + VisitCXXExpansionStmtInstantiation(CXXExpansionStmtInstantiation *S); // FIXME: MSDependentExistsStmt ExpectedStmt VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); ExpectedStmt VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); @@ -700,6 +711,11 @@ namespace clang { VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E); ExpectedStmt VisitCXXParenListInitExpr(CXXParenListInitExpr *E); + ExpectedStmt VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E); + ExpectedStmt + VisitCXXExpansionInitListSelectExpr(CXXExpansionInitListSelectExpr *E); + ExpectedStmt VisitCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *E); // Helper for chaining together multiple imports. If an error is detected, // subsequent imports will return default constructed nodes, so that failure @@ -2852,6 +2868,34 @@ ExpectedDecl ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) { return ToD; } +ExpectedDecl +ASTNodeImporter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { + auto DCOrErr = Importer.ImportContext(D->getDeclContext()); + if (!DCOrErr) + return DCOrErr.takeError(); + DeclContext *DC = *DCOrErr; + DeclContext *LexicalDC = DC; + + Error Err = Error::success(); + auto ToLocation = importChecked(Err, D->getLocation()); + auto ToExpansion = importChecked(Err, D->getExpansionPattern()); + auto ToTemplateParams = importChecked(Err, D->getTemplateParameters()); + auto ToInstantiations = importChecked(Err, D->getInstantiations()); + if (Err) + return std::move(Err); + + CXXExpansionStmtDecl *ToD; + if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, ToLocation, + ToTemplateParams)) + return ToD; + + ToD->setExpansionPattern(ToExpansion); + ToD->setInstantiations(ToInstantiations); + ToD->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToD); + return ToD; +} + ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { // Import the major distinguishing characteristics of this namespace. DeclContext *DC, *LexicalDC; @@ -7450,6 +7494,96 @@ ExpectedStmt ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc); } +ExpectedStmt ASTNodeImporter::VisitCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *S) { + Error Err = Error::success(); + auto ToESD = importChecked(Err, S->getDecl()); + auto ToInit = importChecked(Err, S->getInit()); + auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToColonLoc = importChecked(Err, S->getColonLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) CXXEnumeratingExpansionStmtPattern( + ToESD, ToInit, ToExpansionVar, ToLParenLoc, ToColonLoc, ToRParenLoc); +} +ExpectedStmt ASTNodeImporter::VisitCXXIteratingExpansionStmtPattern( + CXXIteratingExpansionStmtPattern *S) { + Error Err = Error::success(); + auto ToESD = importChecked(Err, S->getDecl()); + auto ToInit = importChecked(Err, S->getInit()); + auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); + auto ToRange = importChecked(Err, S->getRangeVarStmt()); + auto ToBegin = importChecked(Err, S->getBeginVarStmt()); + auto ToEnd = importChecked(Err, S->getEndVarStmt()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToColonLoc = importChecked(Err, S->getColonLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) CXXIteratingExpansionStmtPattern( + ToESD, ToInit, ToExpansionVar, ToRange, ToBegin, ToEnd, ToLParenLoc, + ToColonLoc, ToRParenLoc); +} +ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *S) { + Error Err = Error::success(); + auto ToESD = importChecked(Err, S->getDecl()); + auto ToInit = importChecked(Err, S->getInit()); + auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); + auto ToDecompositionDeclStmt = + importChecked(Err, S->getDecompositionDeclStmt()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToColonLoc = importChecked(Err, S->getColonLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) CXXDestructuringExpansionStmtPattern( + ToESD, ToInit, ToExpansionVar, ToDecompositionDeclStmt, ToLParenLoc, + ToColonLoc, ToRParenLoc); +} +ExpectedStmt ASTNodeImporter::VisitCXXDependentExpansionStmtPattern( + CXXDependentExpansionStmtPattern *S) { + Error Err = Error::success(); + auto ToESD = importChecked(Err, S->getDecl()); + auto ToInit = importChecked(Err, S->getInit()); + auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); + auto ToExpansionInitializer = + importChecked(Err, S->getExpansionInitializer()); + auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); + auto ToColonLoc = importChecked(Err, S->getColonLoc()); + auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) CXXDependentExpansionStmtPattern( + ToESD, ToInit, ToExpansionVar, ToExpansionInitializer, ToLParenLoc, + ToColonLoc, ToRParenLoc); +} +ExpectedStmt ASTNodeImporter::VisitCXXExpansionStmtInstantiation( + CXXExpansionStmtInstantiation *S) { + Error Err = Error::success(); + SmallVector ToInstantiations; + SmallVector ToSharedStmts; + auto ToBeginLoc = importChecked(Err, S->getBeginLoc()); + auto ToEndLoc = importChecked(Err, S->getEndLoc()); + for (Stmt *FromInst : S->getInstantiations()) + ToInstantiations.push_back(importChecked(Err, FromInst)); + for (Stmt *FromShared : S->getSharedStmts()) + ToSharedStmts.push_back(importChecked(Err, FromShared)); + + if (Err) + return std::move(Err); + + return CXXExpansionStmtInstantiation::Create( + Importer.getToContext(), ToBeginLoc, ToEndLoc, ToInstantiations, + ToSharedStmts, S->shouldApplyLifetimeExtensionToSharedStmts()); +} + ExpectedStmt ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { Error Err = Error::success(); @@ -9346,6 +9480,46 @@ ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { ToInitLoc, ToBeginLoc, ToEndLoc); } +ExpectedStmt +ASTNodeImporter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { + Error Err = Error::success(); + SmallVector ToExprs; + auto ToLBraceLoc = importChecked(Err, E->getLBraceLoc()); + auto ToRBraceLoc = importChecked(Err, E->getRBraceLoc()); + for (Expr *FromInst : E->getExprs()) + ToExprs.push_back(importChecked(Err, FromInst)); + + if (Err) + return std::move(Err); + + return CXXExpansionInitListExpr::Create(Importer.getToContext(), ToExprs, + ToLBraceLoc, ToRBraceLoc); +} + +ExpectedStmt ASTNodeImporter::VisitCXXExpansionInitListSelectExpr( + CXXExpansionInitListSelectExpr *E) { + Error Err = Error::success(); + auto ToRange = importChecked(Err, E->getRangeExpr()); + auto ToIndex = importChecked(Err, E->getIndexExpr()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) + CXXExpansionInitListSelectExpr(Importer.getToContext(), ToRange, ToIndex); +} + +ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *E) { + Error Err = Error::success(); + auto ToDecompositionDecl = importChecked(Err, E->getDecompositionDecl()); + auto ToIndex = importChecked(Err, E->getIndexExpr()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) CXXDestructuringExpansionSelectExpr( + Importer.getToContext(), ToDecompositionDecl, ToIndex); +} + Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod) { Error ImportErrors = Error::success(); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 638080ea781a9..2ff9d74f1a8d5 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -959,3 +959,10 @@ ExprDependence clang::computeDependence(OpenACCAsteriskSizeExpr *E) { // way. return ExprDependence::None; } + +ExprDependence clang::computeDependence(CXXExpansionInitListExpr *ILE) { + auto D = ExprDependence::None; + for (Expr *E : ILE->getExprs()) + D |= E->getDependence(); + return D; +} diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 30c6d3ed91f1e..3cbe309d75528 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -325,6 +325,9 @@ unsigned Decl::getTemplateDepth() const { if (auto *TPL = getDescribedTemplateParams()) return TPL->getDepth() + 1; + if (auto *ESD = dyn_cast(this)) + return ESD->getIndexTemplateParm()->getDepth() + 1; + // If this is a dependent lambda, there might be an enclosing variable // template. In this case, the next step is not the parent DeclContext (or // even a DeclContext at all). @@ -1018,6 +1021,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ImplicitConceptSpecialization: case OpenACCDeclare: case OpenACCRoutine: + case CXXExpansionStmt: // Never looked up by name. return 0; } @@ -1382,7 +1386,7 @@ bool DeclContext::isDependentContext() const { if (isFileContext()) return false; - if (isa(this)) + if (isa(this)) return true; if (const auto *Record = dyn_cast(this)) { @@ -1491,6 +1495,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: case Decl::RequiresExprBody: + case Decl::CXXExpansionStmt: // There is only one DeclContext for these entities. return this; @@ -2079,6 +2084,13 @@ RecordDecl *DeclContext::getOuterLexicalRecordContext() { return OutermostRD; } +DeclContext *DeclContext::getEnclosingNonExpansionStatementContext() { + DeclContext *DC = this; + while (isa(DC)) + DC = DC->getParent(); + return DC; +} + bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { // For non-file contexts, this is equivalent to Equals. if (!isFileContext()) diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 47ae613b643b6..9e399b3a81ead 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -113,6 +113,7 @@ namespace { void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP); void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *); void VisitHLSLBufferDecl(HLSLBufferDecl *D); + void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *D); void VisitOpenACCDeclareDecl(OpenACCDeclareDecl *D); void VisitOpenACCRoutineDecl(OpenACCRoutineDecl *D); @@ -1329,6 +1330,11 @@ void DeclPrinter::VisitClassTemplatePartialSpecializationDecl( VisitCXXRecordDecl(D); } +void DeclPrinter::VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *D) { + D->getExpansionPattern()->printPretty(Out, nullptr, Policy, Indentation, "\n", + &Context); +} + //---------------------------------------------------------------------------- // Objective-C declarations //---------------------------------------------------------------------------- diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 2f7ae6d6cac63..edfd5cf91196e 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1717,6 +1717,10 @@ clang::getReplacedTemplateParameter(Decl *D, unsigned Index) { return getReplacedTemplateParameter( cast(D)->getTemplateSpecializationInfo()->getTemplate(), Index); + case Decl::Kind::CXXExpansionStmt: + return { + cast(D)->getTemplateParameters()->getParam(Index), + {}}; default: llvm_unreachable("Unhandled templated declaration kind"); } @@ -1788,3 +1792,22 @@ const Decl &clang::adjustDeclToTemplate(const Decl &D) { // FIXME: Adjust alias templates? return D; } + +CXXExpansionStmtDecl::CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, + TemplateParameterList *TParams) + : Decl(CXXExpansionStmt, DC, Loc), DeclContext(CXXExpansionStmt), + TParams(TParams) {} + +CXXExpansionStmtDecl * +CXXExpansionStmtDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, + TemplateParameterList *TParams) { + return new (C, DC) CXXExpansionStmtDecl(DC, Loc, TParams); +} +CXXExpansionStmtDecl * +CXXExpansionStmtDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { + return new (C, ID) CXXExpansionStmtDecl(nullptr, SourceLocation(), nullptr); +} + +SourceRange CXXExpansionStmtDecl::getSourceRange() const { + return Expansion ? Expansion->getSourceRange() : SourceRange(); +} diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 340bb4b2ed6a3..c61660c90513f 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3688,6 +3688,9 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case FunctionParmPackExprClass: case RecoveryExprClass: case CXXFoldExprClass: + case CXXExpansionInitListSelectExprClass: + case CXXExpansionInitListExprClass: + case CXXDestructuringExpansionSelectExprClass: // Make a conservative assumption for dependent nodes. return IncludePossibleEffects; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index c7f0ff040194d..7ba49f74c1f7d 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -2020,3 +2020,61 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee, SubExprs[SubExpr::RHS] = RHS; setDependence(computeDependence(this)); } + +CXXExpansionInitListExpr::CXXExpansionInitListExpr(EmptyShell ES, + unsigned NumExprs) + : Expr(CXXExpansionInitListExprClass, ES), NumExprs(NumExprs) {} + +CXXExpansionInitListExpr::CXXExpansionInitListExpr(ArrayRef Exprs, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc) + : Expr(CXXExpansionInitListExprClass, QualType(), VK_PRValue, OK_Ordinary), + NumExprs(static_cast(Exprs.size())), LBraceLoc(LBraceLoc), + RBraceLoc(RBraceLoc) { + llvm::uninitialized_copy(Exprs, getTrailingObjects()); + setDependence(computeDependence(this)); +} + +CXXExpansionInitListExpr * +CXXExpansionInitListExpr::Create(const ASTContext &C, ArrayRef Exprs, + SourceLocation LBraceLoc, + SourceLocation RBraceLoc) { + void *Mem = C.Allocate(totalSizeToAlloc(Exprs.size())); + return new (Mem) CXXExpansionInitListExpr(Exprs, LBraceLoc, RBraceLoc); +} + +CXXExpansionInitListExpr * +CXXExpansionInitListExpr::CreateEmpty(const ASTContext &C, EmptyShell Empty, + unsigned NumExprs) { + void *Mem = C.Allocate(totalSizeToAlloc(NumExprs)); + return new (Mem) CXXExpansionInitListExpr(Empty, NumExprs); +} + +CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr(EmptyShell Empty) + : Expr(CXXExpansionInitListSelectExprClass, Empty) {} + +CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr( + const ASTContext &C, CXXExpansionInitListExpr *Range, Expr *Idx) + : Expr(CXXExpansionInitListSelectExprClass, C.DependentTy, VK_PRValue, + OK_Ordinary) { + setDependence(ExprDependence::TypeValueInstantiation); + SubExprs[RANGE] = Range; + SubExprs[INDEX] = Idx; +} + +bool CXXExpansionInitListExpr::containsPackExpansion() const { + return llvm::any_of(getExprs(), + [](const Expr *E) { return isa(E); }); +} + +CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr( + EmptyShell Empty) + : Expr(CXXDestructuringExpansionSelectExprClass, Empty) {} + +CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr( + const ASTContext &C, DecompositionDecl *Decomposition, Expr *Index) + : Expr(CXXDestructuringExpansionSelectExprClass, C.DependentTy, VK_PRValue, + OK_Ordinary), + Decomposition(Decomposition), Index(Index) { + setDependence(ExprDependence::TypeValueInstantiation); +} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index aeacd0dc765ef..5521cdf9d04c9 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -216,6 +216,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: case Expr::RequiresExprClass: + case Expr::CXXExpansionInitListExprClass: + case Expr::CXXExpansionInitListSelectExprClass: + case Expr::CXXDestructuringExpansionSelectExprClass: return Cl::CL_PRValue; case Expr::EmbedExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 3b91678f7d400..d93f87a27e68d 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -20276,6 +20276,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::SYCLUniqueStableNameExprClass: case Expr::CXXParenListInitExprClass: case Expr::HLSLOutArgExprClass: + case Expr::CXXExpansionInitListExprClass: + case Expr::CXXExpansionInitListSelectExprClass: + case Expr::CXXDestructuringExpansionSelectExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); case Expr::InitListExprClass: { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5572e0a7ae59c..28883edc34e6d 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -42,7 +42,7 @@ using namespace clang; namespace { static bool isLocalContainerContext(const DeclContext *DC) { - return isa(DC) || isa(DC) || isa(DC); + return isa(DC); } static const FunctionDecl *getStructor(const FunctionDecl *fn) { @@ -1851,6 +1851,8 @@ static GlobalDecl getParentOfLocalEntity(const DeclContext *DC) { GD = GlobalDecl(CD, Ctor_Complete); else if (auto *DD = dyn_cast(DC)) GD = GlobalDecl(DD, Dtor_Complete); + else if (DC->isExpansionStmt()) + GD = getParentOfLocalEntity(DC->getEnclosingNonExpansionStatementContext()); else GD = GlobalDecl(cast(DC)); return GD; @@ -2191,6 +2193,9 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { if (NoFunction && isLocalContainerContext(DC)) return; + if (DC->isExpansionStmt()) + return; + const NamedDecl *ND = cast(DC); if (mangleSubstitution(ND)) return; @@ -4940,6 +4945,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXParenListInitExprClass: case Expr::PackIndexingExprClass: + case Expr::CXXExpansionInitListSelectExprClass: + case Expr::CXXExpansionInitListExprClass: + case Expr::CXXDestructuringExpansionSelectExprClass: llvm_unreachable("unexpected statement kind"); case Expr::ConstantExprClass: diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index 6a69fe75136f3..87bf376f3770d 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/StmtCXX.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" @@ -125,3 +126,155 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args) Args.ReturnStmtOnAllocFailure; llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data())); } + +CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell Empty) + : Stmt(SC, Empty) {} + +CXXExpansionStmtPattern::CXXExpansionStmtPattern( + StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, + + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc) + : Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc), + RParenLoc(RParenLoc) { + setInit(Init); + setExpansionVarStmt(ExpansionVar); + setBody(nullptr); +} + +CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern( + EmptyShell Empty) + : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty) {} + +CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, + SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc) + : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD, + Init, ExpansionVar, LParenLoc, ColonLoc, + RParenLoc) {} + +SourceLocation CXXExpansionStmtPattern::getBeginLoc() const { + return ParentDecl->getLocation(); +} + +VarDecl *CXXExpansionStmtPattern::getExpansionVariable() { + Decl *LV = cast(getExpansionVarStmt())->getSingleDecl(); + assert(LV && "No expansion variable in CXXExpansionStmtPattern"); + return cast(LV); +} + +bool CXXExpansionStmtPattern::hasDependentSize() const { + if (isa(this)) + return cast( + getExpansionVariable()->getInit()) + ->getRangeExpr() + ->containsPackExpansion(); + + if (auto *Iterating = dyn_cast(this)) { + const Expr *Begin = Iterating->getBeginVar()->getInit(); + const Expr *End = Iterating->getBeginVar()->getInit(); + return Begin->isTypeDependent() || Begin->isValueDependent() || + End->isTypeDependent() || End->isValueDependent(); + } + + if (isa(this)) + return false; + + if (isa(this)) + return true; + + llvm_unreachable("Invalid expansion statement class"); +} + +CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern( + EmptyShell Empty) + : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, Empty) {} + +CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, + DeclStmt *Range, DeclStmt *Begin, DeclStmt *End, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc) + : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, ESD, Init, + ExpansionVar, LParenLoc, ColonLoc, RParenLoc) { + setRangeVarStmt(Range); + setBeginVarStmt(Begin); + setEndVarStmt(End); +} + +CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern( + EmptyShell Empty) + : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass, + Empty) {} + +CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, + Stmt *DecompositionDeclStmt, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc) + : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass, ESD, + Init, ExpansionVar, LParenLoc, ColonLoc, + RParenLoc) { + setDecompositionDeclStmt(DecompositionDeclStmt); +} + +DecompositionDecl * +CXXDestructuringExpansionStmtPattern::getDecompositionDecl() { + return cast( + cast(getDecompositionDeclStmt())->getSingleDecl()); +} + +CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern( + EmptyShell Empty) + : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, Empty) {} + +CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, + Expr *ExpansionInitializer, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc) + : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, ESD, Init, + ExpansionVar, LParenLoc, ColonLoc, RParenLoc) { + setExpansionInitializer(ExpansionInitializer); +} + +CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation( + EmptyShell Empty, unsigned NumInstantiations, unsigned NumSharedStmts) + : Stmt(CXXExpansionStmtInstantiationClass, Empty), + NumInstantiations(NumInstantiations), NumSharedStmts(NumSharedStmts) { + assert(NumSharedStmts <= 4 && "might have to allocate more bits for this"); +} + +CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation( + SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Instantiations, ArrayRef SharedStmts, + bool ShouldApplyLifetimeExtensionToSharedStmts) + : Stmt(CXXExpansionStmtInstantiationClass), BeginLoc(BeginLoc), + EndLoc(EndLoc), NumInstantiations(unsigned(Instantiations.size())), + NumSharedStmts(unsigned(SharedStmts.size())), + ShouldApplyLifetimeExtensionToSharedStmts( + ShouldApplyLifetimeExtensionToSharedStmts) { + assert(NumSharedStmts <= 4 && "might have to allocate more bits for this"); + llvm::uninitialized_copy(Instantiations, getTrailingObjects()); + llvm::uninitialized_copy(SharedStmts, + getTrailingObjects() + NumInstantiations); +} + +CXXExpansionStmtInstantiation *CXXExpansionStmtInstantiation::Create( + ASTContext &C, SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Instantiations, ArrayRef SharedStmts, + bool ShouldApplyLifetimeExtensionToSharedStmts) { + void *Mem = C.Allocate( + totalSizeToAlloc(Instantiations.size() + SharedStmts.size()), + alignof(CXXExpansionStmtInstantiation)); + return new (Mem) CXXExpansionStmtInstantiation( + BeginLoc, EndLoc, Instantiations, SharedStmts, + ShouldApplyLifetimeExtensionToSharedStmts); +} + +CXXExpansionStmtInstantiation * +CXXExpansionStmtInstantiation::CreateEmpty(ASTContext &C, EmptyShell Empty, + unsigned NumInstantiations, + unsigned NumSharedStmts) { + void *Mem = + C.Allocate(totalSizeToAlloc(NumInstantiations + NumSharedStmts), + alignof(CXXExpansionStmtInstantiation)); + return new (Mem) + CXXExpansionStmtInstantiation(Empty, NumInstantiations, NumSharedStmts); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index ff8ca01ec5477..6760d3bbe54cc 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -160,6 +160,8 @@ namespace { } void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); + void VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node, + Expr *Initializer = nullptr); #define ABSTRACT_STMT(CLASS) #define STMT(CLASS, PARENT) \ @@ -263,7 +265,8 @@ void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { PrintRawDeclStmt(Node); // Certain pragma declarations shouldn't have a semi-colon after them. if (!Node->isSingleDecl() || - !isa(Node->getSingleDecl())) + !isa( + Node->getSingleDecl())) OS << ";"; OS << NL; } @@ -447,6 +450,63 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) { PrintControlledStmt(Node->getBody()); } +void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node, + Expr *Initializer) { + OS << "template for ("; + if (Node->getInit()) + PrintInitStmt(Node->getInit(), 14); + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressInitializers = true; + Node->getExpansionVariable()->print(OS, SubPolicy, IndentLevel); + OS << " : "; + PrintExpr(Initializer ? Initializer + : Node->getExpansionVariable()->getInit()); + OS << ")"; + PrintControlledStmt(Node->getBody()); +} + +void StmtPrinter::VisitCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *Node) { + VisitCXXExpansionStmtPattern(Node); +} + +void StmtPrinter::VisitCXXIteratingExpansionStmtPattern( + CXXIteratingExpansionStmtPattern *Node) { + VisitCXXExpansionStmtPattern(Node, Node->getRangeVar()->getInit()); +} + +void StmtPrinter::VisitCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *Node) { + VisitCXXExpansionStmtPattern(Node); +} + +void StmtPrinter::VisitCXXDependentExpansionStmtPattern( + CXXDependentExpansionStmtPattern *Node) { + VisitCXXExpansionStmtPattern(Node, Node->getExpansionInitializer()); +} + +void StmtPrinter::VisitCXXExpansionStmtInstantiation( + CXXExpansionStmtInstantiation *) { + llvm_unreachable("should never be printed"); +} + +void StmtPrinter::VisitCXXExpansionInitListExpr( + CXXExpansionInitListExpr *Node) { + OS << "{ "; + llvm::interleaveComma(Node->getExprs(), OS, [&](Expr *E) { PrintExpr(E); }); + OS << " }"; +} + +void StmtPrinter::VisitCXXExpansionInitListSelectExpr( + CXXExpansionInitListSelectExpr *Node) { + PrintExpr(Node->getRangeExpr()); +} + +void StmtPrinter::VisitCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *Node) { + PrintExpr(Node->getDecompositionDecl()->getInit()); +} + void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) { Indent(); if (Node->isIfExists()) diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 4a8c638c85331..45513c479e1d1 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -364,6 +364,37 @@ void StmtProfiler::VisitCXXForRangeStmt(const CXXForRangeStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitCXXExpansionStmtPattern( + const CXXExpansionStmtPattern *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCXXEnumeratingExpansionStmtPattern( + const CXXEnumeratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); +} + +void StmtProfiler::VisitCXXIteratingExpansionStmtPattern( + const CXXIteratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); +} + +void StmtProfiler::VisitCXXDestructuringExpansionStmtPattern( + const CXXDestructuringExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); +} + +void StmtProfiler::VisitCXXDependentExpansionStmtPattern( + const CXXDependentExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); +} + +void StmtProfiler::VisitCXXExpansionStmtInstantiation( + const CXXExpansionStmtInstantiation *S) { + VisitStmt(S); + ID.AddBoolean(S->shouldApplyLifetimeExtensionToSharedStmts()); +} + void StmtProfiler::VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) { VisitStmt(S); ID.AddBoolean(S->isIfExists()); @@ -2400,6 +2431,22 @@ void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { void StmtProfiler::VisitEmbedExpr(const EmbedExpr *E) { VisitExpr(E); } +void StmtProfiler::VisitCXXExpansionInitListExpr( + const CXXExpansionInitListExpr *E) { + VisitExpr(E); +} + +void StmtProfiler::VisitCXXExpansionInitListSelectExpr( + const CXXExpansionInitListSelectExpr *E) { + VisitExpr(E); +} + +void StmtProfiler::VisitCXXDestructuringExpansionSelectExpr( + const CXXDestructuringExpansionSelectExpr *E) { + VisitExpr(E); + VisitDecl(E->getDecompositionDecl()); +} + void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) { VisitExpr(E); } void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 41aebdb8d2f1b..4d19bf63f3536 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -951,7 +951,11 @@ void TextNodeDumper::dumpBareDeclRef(const Decl *D) { switch (ND->getKind()) { case Decl::Decomposition: { auto *DD = cast(ND); - OS << " first_binding '" << DD->bindings()[0]->getDeclName() << '\''; + + // Empty decomposition decls can occur in destructuring expansion + // statements. + if (!DD->bindings().empty()) + OS << " first_binding '" << DD->bindings()[0]->getDeclName() << '\''; break; } case Decl::Field: { @@ -1495,6 +1499,12 @@ void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) { OS << " implicit"; } +void TextNodeDumper::VisitCXXExpansionStmtInstantiation( + const CXXExpansionStmtInstantiation *Node) { + if (Node->shouldApplyLifetimeExtensionToSharedStmts()) + OS << " applies_lifetime_extension"; +} + void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) { if (Node->hasAPValueResult()) AddChild("value", @@ -1826,6 +1836,17 @@ void TextNodeDumper::VisitCXXDependentScopeMemberExpr( OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember(); } +void TextNodeDumper::VisitCXXExpansionInitListExpr( + const CXXExpansionInitListExpr *Node) { + if (Node->containsPackExpansion()) + OS << " contains_pack"; +} + +void TextNodeDumper::VisitCXXDestructuringExpansionSelectExpr( + const CXXDestructuringExpansionSelectExpr *Node) { + dumpDeclRef(Node->getDecompositionDecl()); +} + void TextNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { OS << " selector="; Node->getSelector().print(OS); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 46addea232b03..5fbfb4023ee4d 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1632,14 +1632,15 @@ DeclContext *Sema::getFunctionLevelDeclContext(bool AllowLambda) const { DeclContext *DC = CurContext; while (true) { - if (isa(DC) || isa(DC) || isa(DC) || - isa(DC)) { + if (isa(DC)) { DC = DC->getParent(); } else if (!AllowLambda && isa(DC) && cast(DC)->getOverloadedOperator() == OO_Call && cast(DC->getParent())->isLambda()) { DC = DC->getParent()->getParent(); - } else break; + } else + break; } return DC; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 651437a6f4c30..468376039fae5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7437,7 +7437,7 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { if (DC->getDeclKind() == Decl::HLSLBuffer) return false; - if (isa(DC)) + if (isa(DC)) return false; llvm_unreachable("Unexpected context"); } @@ -7447,7 +7447,7 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { if (DC->isFileContext() || DC->isFunctionOrMethod() || isa(DC) || isa(DC)) return true; - if (DC->isRecord()) + if (DC->isRecord() || isa(DC)) return false; llvm_unreachable("Unexpected context"); } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a0483c3027199..a56f933638190 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1288,6 +1288,9 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: case Expr::CXXParenListInitExprClass: + case Expr::CXXExpansionInitListSelectExprClass: + case Expr::CXXExpansionInitListExprClass: + case Expr::CXXDestructuringExpansionSelectExprClass: return canSubStmtsThrow(*this, S); case Expr::CompoundLiteralExprClass: @@ -1348,6 +1351,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXFoldExprClass: case Expr::RecoveryExprClass: + case Expr::CXXDependentExpansionStmtPatternClass: return CT_Dependent; case Expr::AsTypeExprClass: @@ -1538,6 +1542,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::SEHTryStmtClass: case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: + case Stmt::CXXEnumeratingExpansionStmtPatternClass: + case Stmt::CXXIteratingExpansionStmtPatternClass: + case Stmt::CXXDestructuringExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtInstantiationClass: return canSubStmtsThrow(*this, S); case Stmt::DeclStmtClass: { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d3c2cc559ea20..7fc6d3cff36b0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -19300,11 +19300,12 @@ bool Sema::tryCaptureVariable( QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. - DeclContext *VarDC = Var->getDeclContext(); + DeclContext *VarDC = + Var->getDeclContext()->getEnclosingNonExpansionStatementContext(); DeclContext *DC = CurContext; // Skip past RequiresExprBodys because they don't constitute function scopes. - while (DC->isRequiresExprBody()) + while (DC->isRequiresExprBody() || DC->isExpansionStmt()) DC = DC->getParent(); // tryCaptureVariable is called every time a DeclRef is formed, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 43bcb4f743cfa..0d7e2a9c5b324 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -7600,7 +7600,6 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { assert(!S.isUnevaluatedContext()); - assert(S.CurContext->isDependentContext()); #ifndef NDEBUG DeclContext *DC = S.CurContext; while (isa_and_nonnull(DC)) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index f65c55a209622..c618f4e0a70db 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -100,8 +100,9 @@ static inline UnsignedOrNone getStackIndexOfNearestEnclosingCaptureReadyLambda( // innermost nested lambda are dependent (otherwise we wouldn't have // arrived here) - so we don't yet have a lambda that can capture the // variable. - if (IsCapturingVariable && - VarToCapture->getDeclContext()->Equals(EnclosingDC)) + if (IsCapturingVariable && VarToCapture->getDeclContext() + ->getEnclosingNonExpansionStatementContext() + ->Equals(EnclosingDC)) return NoLambdaIsCaptureReady; // For an enclosing lambda to be capture ready for an entity, all @@ -126,7 +127,8 @@ static inline UnsignedOrNone getStackIndexOfNearestEnclosingCaptureReadyLambda( if (IsCapturingThis && !LSI->isCXXThisCaptured()) return NoLambdaIsCaptureReady; } - EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC); + EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC) + ->getEnclosingNonExpansionStatementContext(); assert(CurScopeIndex); --CurScopeIndex; @@ -190,11 +192,6 @@ UnsignedOrNone clang::getStackIndexOfNearestEnclosingCaptureCapableLambda( return NoLambdaIsCaptureCapable; const unsigned IndexOfCaptureReadyLambda = *OptionalStackIndex; - assert(((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) || - S.getCurGenericLambda()) && - "The capture ready lambda for a potential capture can only be the " - "current lambda if it is a generic lambda"); - const sema::LambdaScopeInfo *const CaptureReadyLambdaLSI = cast(FunctionScopes[IndexOfCaptureReadyLambda]); @@ -248,7 +245,7 @@ CXXRecordDecl * Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, unsigned LambdaDependencyKind, LambdaCaptureDefault CaptureDefault) { - DeclContext *DC = CurContext; + DeclContext *DC = CurContext->getEnclosingNonExpansionStatementContext(); bool IsGenericLambda = Info && getGenericLambdaTemplateParameterList(getCurLambda(), *this); @@ -1376,7 +1373,9 @@ void Sema::ActOnLambdaClosureQualifiers(LambdaIntroducer &Intro, // odr-use 'this' (in particular, in a default initializer for a non-static // data member). if (Intro.Default != LCD_None && - !LSI->Lambda->getParent()->isFunctionOrMethod() && + !LSI->Lambda->getParent() + ->getEnclosingNonExpansionStatementContext() + ->isFunctionOrMethod() && (getCurrentThisType().isNull() || CheckCXXThisCapture(SourceLocation(), /*Explicit=*/true, /*BuildAndDiagnose=*/false))) @@ -2519,9 +2518,12 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII:: while (FDPattern && FD) { InstantiationAndPatterns.emplace_back(FDPattern, FD); - FDPattern = - dyn_cast(getLambdaAwareParentOfDeclContext(FDPattern)); - FD = dyn_cast(getLambdaAwareParentOfDeclContext(FD)); + FDPattern = dyn_cast( + getLambdaAwareParentOfDeclContext(FDPattern) + ->getEnclosingNonExpansionStatementContext()); + FD = dyn_cast( + getLambdaAwareParentOfDeclContext(FD) + ->getEnclosingNonExpansionStatementContext()); } // Add instantiated parameters and local vars to scopes, starting from the diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 5915d6e57d893..88dcd27d45ad2 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -4455,7 +4455,9 @@ LabelDecl *Sema::LookupExistingLabel(IdentifierInfo *II, SourceLocation Loc) { RedeclarationKind::NotForRedeclaration); // If we found a label, check to see if it is in the same context as us. // When in a Block, we don't want to reuse a label in an enclosing function. - if (!Res || Res->getDeclContext() != CurContext) + if (!Res || + Res->getDeclContext()->getEnclosingNonExpansionStatementContext() != + CurContext->getEnclosingNonExpansionStatementContext()) return nullptr; return cast(Res); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 26693514bb278..f8136c3c24a52 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2087,6 +2087,11 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { InstantiatedMessageExpr.get(), D->getRParenLoc(), D->isFailed()); } +Decl *TemplateDeclInstantiator::VisitCXXExpansionStmtDecl( + CXXExpansionStmtDecl *OldESD) { + llvm_unreachable("TODO"); +} + Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { EnumDecl *PrevDecl = nullptr; if (EnumDecl *PatternPrev = getPreviousDeclForInstantiation(D)) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0e8b674a006d0..f181d0abb5dfd 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9292,6 +9292,59 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { return FinishCXXForRangeStmt(NewStmt.get(), Body.get()); } +template +StmtResult TreeTransform::TransformCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *S) { + llvm_unreachable("TOOD"); +} + +template +StmtResult TreeTransform::TransformCXXIteratingExpansionStmtPattern( + CXXIteratingExpansionStmtPattern *S) { + llvm_unreachable("TOOD"); +} + +template +StmtResult TreeTransform::TransformCXXDependentExpansionStmtPattern( + CXXDependentExpansionStmtPattern *S) { + llvm_unreachable("TOOD"); +} + +template +StmtResult +TreeTransform::TransformCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *) { + // The only time we instantiate an expansion statement is if its expansion + // size is dependent (otherwise, we only instantiate the expansions and + // leave the underlying CXXExpansionStmtPattern as-is). Since destructuring + // expansion statements never have a dependent size, we should never get here. + llvm_unreachable("Should never be instantiated"); +} + +template +ExprResult TreeTransform::TransformCXXExpansionInitListExpr( + CXXExpansionInitListExpr *E) { + llvm_unreachable("TOOD"); +} + +template +StmtResult TreeTransform::TransformCXXExpansionStmtInstantiation( + CXXExpansionStmtInstantiation *S) { + llvm_unreachable("TOOD"); +} + +template +ExprResult TreeTransform::TransformCXXExpansionInitListSelectExpr( + CXXExpansionInitListSelectExpr *E) { + llvm_unreachable("TOOD"); +} + +template +ExprResult TreeTransform::TransformCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *E) { + llvm_unreachable("TOOD"); +} + template StmtResult TreeTransform::TransformMSDependentExistsStmt( diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 69db02f2efc40..d07661a5b2f64 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -459,6 +459,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::HLSLRootSignature: case Decl::OpenACCDeclare: case Decl::OpenACCRoutine: + case Decl::CXXExpansionStmt: return false; // These indirectly derive from Redeclarable but are not actually diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 5456e73956659..3086d7315a862 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -405,6 +405,7 @@ class ASTDeclReader : public DeclVisitor { void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); + void VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D); void VisitBlockDecl(BlockDecl *BD); void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D); void VisitCapturedDecl(CapturedDecl *CD); @@ -2769,6 +2770,14 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { D->RParenLoc = readSourceLocation(); } +void ASTDeclReader::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { + VisitDecl(D); + D->Expansion = cast(Record.readStmt()); + D->Instantiations = + cast_or_null(Record.readStmt()); + D->TParams = Record.readTemplateParameterList(); +} + void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) { VisitDecl(D); } @@ -4083,6 +4092,9 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { case DECL_STATIC_ASSERT: D = StaticAssertDecl::CreateDeserialized(Context, ID); break; + case DECL_EXPANSION_STMT: + D = CXXExpansionStmtDecl::CreateDeserialized(Context, ID); + break; case DECL_OBJC_METHOD: D = ObjCMethodDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index eef97a8588f0b..c74113c4ab0da 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1730,6 +1730,77 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { S->setBody(Record.readSubStmt()); } +void ASTStmtReader::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) { + VisitStmt(S); + S->LParenLoc = readSourceLocation(); + S->ColonLoc = readSourceLocation(); + S->RParenLoc = readSourceLocation(); + S->ParentDecl = cast(Record.readDeclRef()); + S->setInit(Record.readSubStmt()); + S->setExpansionVarStmt(Record.readSubStmt()); + S->setBody(Record.readSubStmt()); +} + +void ASTStmtReader::VisitCXXExpansionStmtInstantiation( + CXXExpansionStmtInstantiation *S) { + VisitStmt(S); + Record.skipInts(2); + S->BeginLoc = readSourceLocation(); + S->EndLoc = readSourceLocation(); + for (unsigned I = 0; I < S->getNumSubStmts(); ++I) + S->getAllSubStmts()[I] = Record.readSubStmt(); + S->setShouldApplyLifetimeExtensionToSharedStmts(Record.readBool()); +} + +void ASTStmtReader::VisitCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); +} + +void ASTStmtReader::VisitCXXIteratingExpansionStmtPattern( + CXXIteratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + S->setRangeVarStmt(cast(Record.readSubStmt())); + S->setBeginVarStmt(cast(Record.readSubStmt())); + S->setEndVarStmt(cast(Record.readSubStmt())); +} + +void ASTStmtReader::VisitCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + S->setDecompositionDeclStmt(Record.readSubStmt()); +} + +void ASTStmtReader::VisitCXXDependentExpansionStmtPattern( + CXXDependentExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + S->setExpansionInitializer(Record.readSubExpr()); +} + +void ASTStmtReader::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { + VisitExpr(E); + assert(Record.peekInt() == E->getNumExprs() && "NumExprFields is wrong ?"); + Record.skipInts(1); + E->LBraceLoc = readSourceLocation(); + E->RBraceLoc = readSourceLocation(); + for (unsigned I = 0; I < E->getNumExprs(); ++I) + E->getExprs()[I] = Record.readSubExpr(); +} + +void ASTStmtReader::VisitCXXExpansionInitListSelectExpr( + CXXExpansionInitListSelectExpr *E) { + VisitExpr(E); + E->setRangeExpr(cast(Record.readSubExpr())); + E->setIndexExpr(Record.readSubExpr()); +} + +void ASTStmtReader::VisitCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *E) { + VisitExpr(E); + E->setDecompositionDecl(cast(Record.readDeclRef())); + E->setIndexExpr(Record.readSubExpr()); +} + void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { VisitStmt(S); S->KeywordLoc = readSourceLocation(); @@ -3566,6 +3637,28 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { /*numHandlers=*/Record[ASTStmtReader::NumStmtFields]); break; + case STMT_CXX_ENUMERATING_EXPANSION: + S = new (Context) CXXEnumeratingExpansionStmtPattern(Empty); + break; + + case STMT_CXX_ITERATING_EXPANSION: + S = new (Context) CXXIteratingExpansionStmtPattern(Empty); + break; + + case STMT_CXX_DESTRUCTURING_EXPANSION: + S = new (Context) CXXDestructuringExpansionStmtPattern(Empty); + break; + + case STMT_CXX_DEPENDENT_EXPANSION: + S = new (Context) CXXDependentExpansionStmtPattern(Empty); + break; + + case STMT_CXX_EXPANSION_INSTANTIATION: + S = CXXExpansionStmtInstantiation::CreateEmpty( + Context, Empty, Record[ASTStmtReader::NumStmtFields], + Record[ASTStmtReader::NumStmtFields + 1]); + break; + case STMT_CXX_FOR_RANGE: S = new (Context) CXXForRangeStmt(Empty); break; @@ -4443,6 +4536,20 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) ConceptSpecializationExpr(Empty); break; } + + case EXPR_CXX_EXPANSION_INIT_LIST: + S = CXXExpansionInitListExpr::CreateEmpty( + Context, Empty, Record[ASTStmtReader::NumExprFields]); + break; + + case EXPR_CXX_EXPANSION_INIT_LIST_SELECT: + S = new (Context) CXXExpansionInitListSelectExpr(Empty); + break; + + case EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT: + S = new (Context) CXXDestructuringExpansionSelectExpr(Empty); + break; + case STMT_OPENACC_COMPUTE_CONSTRUCT: { unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; S = OpenACCComputeConstruct::CreateEmpty(Context, NumClauses); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c9f8797ab973f..23d11341d131a 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -144,6 +144,7 @@ namespace clang { void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); + void VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D); void VisitBlockDecl(BlockDecl *D); void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D); void VisitCapturedDecl(CapturedDecl *D); @@ -2188,6 +2189,14 @@ void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { Code = serialization::DECL_STATIC_ASSERT; } +void ASTDeclWriter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { + VisitDecl(D); + Record.AddStmt(D->getExpansionPattern()); + Record.AddStmt(D->getInstantiations()); + Record.AddTemplateParameterList(D->getTemplateParameters()); + Code = serialization::DECL_EXPANSION_STMT; +} + /// Emit the DeclContext part of a declaration context decl. void ASTDeclWriter::VisitDeclContext(DeclContext *DC) { static_assert(DeclContext::NumDeclContextBits == 13, diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index acf345392aa1a..d795b23525888 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { Code = serialization::STMT_CXX_FOR_RANGE; } +void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) { + VisitStmt(S); + Record.AddSourceLocation(S->getLParenLoc()); + Record.AddSourceLocation(S->getColonLoc()); + Record.AddSourceLocation(S->getRParenLoc()); + Record.AddDeclRef(S->getDecl()); + Record.AddStmt(S->getInit()); + Record.AddStmt(S->getExpansionVarStmt()); + Record.AddStmt(S->getBody()); +} + +void ASTStmtWriter::VisitCXXExpansionStmtInstantiation( + CXXExpansionStmtInstantiation *S) { + VisitStmt(S); + Record.push_back(S->getInstantiations().size()); + Record.push_back(S->getSharedStmts().size()); + Record.AddSourceLocation(S->getBeginLoc()); + Record.AddSourceLocation(S->getEndLoc()); + for (Stmt *St : S->getAllSubStmts()) + Record.AddStmt(St); + Record.push_back(S->shouldApplyLifetimeExtensionToSharedStmts()); + Code = serialization::STMT_CXX_EXPANSION_INSTANTIATION; +} + +void ASTStmtWriter::VisitCXXEnumeratingExpansionStmtPattern( + CXXEnumeratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + Code = serialization::STMT_CXX_ENUMERATING_EXPANSION; +} + +void ASTStmtWriter::VisitCXXIteratingExpansionStmtPattern( + CXXIteratingExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + Record.AddStmt(S->getRangeVarStmt()); + Record.AddStmt(S->getBeginVarStmt()); + Record.AddStmt(S->getEndVarStmt()); + Code = serialization::STMT_CXX_ITERATING_EXPANSION; +} + +void ASTStmtWriter::VisitCXXDestructuringExpansionStmtPattern( + CXXDestructuringExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + Record.AddStmt(S->getDecompositionDeclStmt()); + Code = serialization::STMT_CXX_DESTRUCTURING_EXPANSION; +} + +void ASTStmtWriter::VisitCXXDependentExpansionStmtPattern( + CXXDependentExpansionStmtPattern *S) { + VisitCXXExpansionStmtPattern(S); + Record.AddStmt(S->getExpansionInitializer()); + Code = serialization::STMT_CXX_DEPENDENT_EXPANSION; +} + +void ASTStmtWriter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumExprs()); + Record.AddSourceLocation(E->getLBraceLoc()); + Record.AddSourceLocation(E->getRBraceLoc()); + for (Expr *SubExpr : E->getExprs()) + Record.AddStmt(SubExpr); + Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST; +} + +void ASTStmtWriter::VisitCXXExpansionInitListSelectExpr( + CXXExpansionInitListSelectExpr *E) { + VisitExpr(E); + Record.AddStmt(E->getRangeExpr()); + Record.AddStmt(E->getIndexExpr()); + Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST_SELECT; +} + +void ASTStmtWriter::VisitCXXDestructuringExpansionSelectExpr( + CXXDestructuringExpansionSelectExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getDecompositionDecl()); + Record.AddStmt(E->getIndexExpr()); + Code = serialization::EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT; +} + void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { VisitStmt(S); Record.AddSourceLocation(S->getKeywordLoc()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index a759aee47b8ea..38106f154c15e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1752,6 +1752,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SEHExceptStmtClass: case Stmt::SEHLeaveStmtClass: case Stmt::SEHFinallyStmtClass: + case Stmt::CXXEnumeratingExpansionStmtPatternClass: + case Stmt::CXXIteratingExpansionStmtPatternClass: + case Stmt::CXXDestructuringExpansionStmtPatternClass: + case Stmt::CXXDependentExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtInstantiationClass: + case Stmt::CXXExpansionInitListExprClass: + case Stmt::CXXExpansionInitListSelectExprClass: + case Stmt::CXXDestructuringExpansionSelectExprClass: case Stmt::OMPCanonicalLoopClass: case Stmt::OMPParallelDirectiveClass: case Stmt::OMPSimdDirectiveClass: diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index f4d6fa72a1dfe..d4da1cc8ba722 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7254,6 +7254,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::UnresolvedUsingIfExists: case Decl::OpenACCDeclare: case Decl::OpenACCRoutine: + case Decl::CXXExpansionStmt: return C; // Declaration kinds that don't make any sense here, but are diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 0a43d73063c1f..f0ae4f0b593a2 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -290,6 +290,11 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::CoroutineBodyStmtClass: case Stmt::CoreturnStmtClass: + case Stmt::CXXEnumeratingExpansionStmtPatternClass: + case Stmt::CXXIteratingExpansionStmtPatternClass: + case Stmt::CXXDestructuringExpansionStmtPatternClass: + case Stmt::CXXDependentExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtInstantiationClass: K = CXCursor_UnexposedStmt; break; @@ -338,6 +343,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::EmbedExprClass: case Stmt::HLSLOutArgExprClass: case Stmt::OpenACCAsteriskSizeExprClass: + case Stmt::CXXExpansionInitListExprClass: + case Stmt::CXXExpansionInitListSelectExprClass: + case Stmt::CXXDestructuringExpansionSelectExprClass: K = CXCursor_UnexposedExpr; break; From 902410bcc59271f217d74b419b088c1ca1359d0f Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 26 Nov 2025 18:59:18 +0100 Subject: [PATCH 2/9] Add missing enumerators --- clang/lib/CodeGen/CGDecl.cpp | 3 +++ clang/lib/CodeGen/CGStmt.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 8b1cd83af2396..7c96e38908267 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -143,6 +143,9 @@ void CodeGenFunction::EmitDecl(const Decl &D, bool EvaluateConditionDecl) { // None of these decls require codegen support. return; + case Decl::CXXExpansionStmt: + llvm_unreachable("TODO"); + case Decl::NamespaceAlias: if (CGDebugInfo *DI = getDebugInfo()) DI->EmitNamespaceAlias(cast(D)); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 36be3295950b8..40c92035008ae 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -204,6 +204,13 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::CXXForRangeStmtClass: EmitCXXForRangeStmt(cast(*S), Attrs); break; + case Stmt::CXXEnumeratingExpansionStmtPatternClass: + case Stmt::CXXIteratingExpansionStmtPatternClass: + case Stmt::CXXDestructuringExpansionStmtPatternClass: + case Stmt::CXXDependentExpansionStmtPatternClass: + llvm_unreachable("unexpanded expansion statements should not be emitted"); + case Stmt::CXXExpansionStmtInstantiationClass: + llvm_unreachable("Todo"); case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast(*S)); break; From f812c54d41167234340df355aa3645e5ba7a1fd2 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Mon, 1 Dec 2025 18:25:45 +0100 Subject: [PATCH 3/9] Documentation improvements --- clang/include/clang/AST/Decl.h | 2 +- clang/include/clang/AST/DeclTemplate.h | 32 ++++++++++++++++------ clang/include/clang/AST/ExprCXX.h | 13 +++++++++ clang/include/clang/AST/StmtCXX.h | 38 +++++++++++++++++--------- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index b8f8e002ebcce..e15f4dcd3a0bc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1247,7 +1247,7 @@ class VarDecl : public DeclaratorDecl, public Redeclarable { /// Returns true for local variable declarations other than parameters. /// Note that this includes static variables inside of functions. It also - /// includes variables inside blocks. + /// includes variables inside blocks and expansion statements. /// /// void foo() { int x; static int y; extern int z; } bool isLocalVarDecl() const { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 45a58b6589074..6f4adf076a0a2 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3375,7 +3375,18 @@ class TemplateParamObjectDecl : public ValueDecl, /// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for /// codegen and constant evaluation. /// -/// For example, if the user writes the following expansion statement: +/// There are three kinds of expansion statements; they correspond to three +/// derived classes of 'CXXExpansionStmtPattern'. There is also a fourth derived +/// class that is used if we don't know what kind of expansion statement we're +/// dealing with (because the thing we're expanding is dependent). See the +/// comment on those classes for more information about how they work: +/// +/// 1. CXXEnumeratingExpansionStmtPattern +/// 2. CXXIteratingExpansionStmtPattern +/// 3. CXXDestructuringExpansionStmtPattern +/// 4. CXXDependentExpansionStmtPattern +/// +/// As an example, if the user writes the following expansion statement: /// \verbatim /// std::tuple a{1, 2, 3}; /// template for (auto x : a) { @@ -3389,28 +3400,33 @@ class TemplateParamObjectDecl : public ValueDecl, /// 'a'. /// /// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that -/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion: +/// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e. +/// those marked as 'Actual "CompoundStmt"' below) are actually present as +/// 'CompoundStmt's in the AST; the outer braces that wrap everything do *not* +/// correspond to an actual 'CompoundStmt' and are implicit in the sense that we +/// simply push a scope when evaluating or emitting IR for a +/// 'CXXExpansionStmtInstantiation'. /// /// \verbatim -/// { +/// { // Not actually present in the AST. /// auto [__u0, __u1, __u2] = a; -/// { +/// { // Actual 'CompoundStmt'. /// auto x = __u0; /// // ... /// } -/// { +/// { // Actual 'CompoundStmt'. /// auto x = __u1; /// // ... /// } -/// { +/// { // Actual 'CompoundStmt'. /// auto x = __u2; /// // ... /// } /// } /// \endverbatim /// -/// The outer braces shown above are implicit; we don't actually create another -/// CompoundStmt wrapping everything. +/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes +/// as to why this node exist and how it is used. /// /// \see CXXExpansionStmtPattern /// \see CXXExpansionStmtInstantiation diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 668a51dad0ae9..a190a178bfce8 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5501,6 +5501,19 @@ class BuiltinBitCastExpr final /// Represents an expansion-init-list of an enumerating expansion statement. /// +/// For example, in +/// \verbatim +/// template for (auto x : { 1, 2, 3 }) { +/// // ... +/// } +/// \endverbatim +/// +/// the '{ 1, 2, 3 }' part is parsed and stored as a 'CXXExpansionInitListExpr'; +/// syntactically, this *looks* very similar to an initializer list, but it +/// isn't actually an expression: '{ 1, 2, 3 }' as a whole is never evaluated +/// or emitted, only the individual expressions '1', '2', and '3' are. We still +/// represent it as an expression in the AST for simplicity. +/// /// \see CXXEnumeratingExpansionStmtPattern class CXXExpansionInitListExpr final : public Expr, diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index 96c3f912d6c3e..2ecb653126e5f 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -533,11 +533,7 @@ class CoreturnStmt : public Stmt { /// subexpressions required by its derived classes. This is to simplify the /// implementation of 'children()' and friends. /// -/// \see CXXExpansionStmtDecl -/// \see CXXEnumeratingExpansionStmtPattern -/// \see CXXIteratingExpansionStmtPattern -/// \see CXXDestructuringExpansionStmtPattern -/// \see CXXDependentExpansionStmtPattern +/// \see CXXExpansionStmtDecl for more documentation on expansion statements. class CXXExpansionStmtPattern : public Stmt { friend class ASTStmtReader; @@ -878,25 +874,28 @@ class CXXDestructuringExpansionStmtPattern : public CXXExpansionStmtPattern { /// Represents the code generated for an expanded expansion statement. /// /// This holds 'shared statements' and 'instantiations'; these encode the -/// general underlying pattern that all expansion statements desugar to: +/// general underlying pattern that all expansion statements desugar to. Note +/// that only the inner '{}' (i.e. those marked as 'Actual "CompoundStmt"' +/// below) are actually present as 'CompoundStmt's in the AST; the outer braces +/// that wrap everything do *not* correspond to an actual 'CompoundStmt' and are +/// implicit in the sense that we simply push a scope when evaluating or +/// emitting IR for a 'CXXExpansionStmtInstantiation'. +/// +/// The 'instantiations' are precisely these inner compound statements. /// /// \verbatim -/// { +/// { // Not actually present in the AST. /// -/// { +/// { // Actual 'CompoundStmt'. /// <1st instantiation> /// } /// ... -/// { +/// { // Actual 'CompoundStmt'. /// /// } /// } /// \endverbatim /// -/// Here, the only thing that is stored in the AST are the 'shared statements' -/// and the 'CompoundStmt's that wrap the 'instantiations'. The outer braces -/// shown above are implicit. -/// /// For example, the CXXExpansionStmtInstantiation that corresponds to the /// following expansion statement /// @@ -926,6 +925,19 @@ class CXXDestructuringExpansionStmtPattern : public CXXExpansionStmtPattern { /// } /// } /// \endverbatim +/// +/// There are two reasons why this needs to exist and why we don't just store a +/// list of instantiations in some other node: +/// +/// 1. We need custom codegen to handle break/continue in expansion statements +/// properly, so it can't just be a compound statement. +/// +/// 2. The expansions are created after both the pattern and the +/// 'CXXExpansionStmtDecl', so we can't just store them as trailing data in +/// either of those nodes (because we don't know how many expansions there +/// will be when those notes are allocated). +/// +/// \see CXXExpansionStmtDecl class CXXExpansionStmtInstantiation final : public Stmt, llvm::TrailingObjects { From ec6fde37824bad20fa902aab4e4ae36c907092c0 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Mon, 1 Dec 2025 19:13:34 +0100 Subject: [PATCH 4/9] Fix copy-paste error and only check for instantiation dependence --- clang/lib/AST/StmtCXX.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index 87bf376f3770d..f34c11d4eff39 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -171,9 +171,8 @@ bool CXXExpansionStmtPattern::hasDependentSize() const { if (auto *Iterating = dyn_cast(this)) { const Expr *Begin = Iterating->getBeginVar()->getInit(); - const Expr *End = Iterating->getBeginVar()->getInit(); - return Begin->isTypeDependent() || Begin->isValueDependent() || - End->isTypeDependent() || End->isValueDependent(); + const Expr *End = Iterating->getEndVar()->getInit(); + return Begin->isInstantiationDependent() || End->isInstantiationDependent(); } if (isa(this)) From 4415e4dbdfe833269586c7db50d8516629a59315 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Mon, 1 Dec 2025 21:29:18 +0100 Subject: [PATCH 5/9] Do not create a template parameter list for the index --- clang/include/clang/AST/DeclTemplate.h | 12 ++++++------ clang/lib/AST/ASTImporter.cpp | 4 ++-- clang/lib/AST/DeclTemplate.cpp | 13 ++++++------- clang/lib/Serialization/ASTReaderDecl.cpp | 2 +- clang/lib/Serialization/ASTWriterDecl.cpp | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 6f4adf076a0a2..d0fbbabe94aa2 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3432,18 +3432,18 @@ class TemplateParamObjectDecl : public ValueDecl, /// \see CXXExpansionStmtInstantiation class CXXExpansionStmtDecl : public Decl, public DeclContext { CXXExpansionStmtPattern *Expansion = nullptr; - TemplateParameterList *TParams; + NonTypeTemplateParmDecl *IndexNTTP = nullptr; CXXExpansionStmtInstantiation *Instantiations = nullptr; CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, - TemplateParameterList *TParams); + NonTypeTemplateParmDecl *NTTP); public: friend class ASTDeclReader; static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, - TemplateParameterList *TParams); + NonTypeTemplateParmDecl *NTTP); static CXXExpansionStmtDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); @@ -3462,10 +3462,10 @@ class CXXExpansionStmtDecl : public Decl, public DeclContext { Instantiations = S; } - NonTypeTemplateParmDecl *getIndexTemplateParm() const { - return cast(TParams->getParam(0)); + NonTypeTemplateParmDecl *getIndexTemplateParm() { return IndexNTTP; } + const NonTypeTemplateParmDecl *getIndexTemplateParm() const { + return IndexNTTP; } - TemplateParameterList *getTemplateParameters() const { return TParams; } SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b94c18e60ba58..225c573ecc042 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2879,14 +2879,14 @@ ASTNodeImporter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { Error Err = Error::success(); auto ToLocation = importChecked(Err, D->getLocation()); auto ToExpansion = importChecked(Err, D->getExpansionPattern()); - auto ToTemplateParams = importChecked(Err, D->getTemplateParameters()); + auto ToIndex = importChecked(Err, D->getIndexTemplateParm()); auto ToInstantiations = importChecked(Err, D->getInstantiations()); if (Err) return std::move(Err); CXXExpansionStmtDecl *ToD; if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, ToLocation, - ToTemplateParams)) + ToIndex)) return ToD; ToD->setExpansionPattern(ToExpansion); diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index edfd5cf91196e..a770112409486 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1718,9 +1718,8 @@ clang::getReplacedTemplateParameter(Decl *D, unsigned Index) { cast(D)->getTemplateSpecializationInfo()->getTemplate(), Index); case Decl::Kind::CXXExpansionStmt: - return { - cast(D)->getTemplateParameters()->getParam(Index), - {}}; + assert(Index == 0 && "expansion stmts only have a single template param"); + return {cast(D)->getIndexTemplateParm(), {}}; default: llvm_unreachable("Unhandled templated declaration kind"); } @@ -1794,14 +1793,14 @@ const Decl &clang::adjustDeclToTemplate(const Decl &D) { } CXXExpansionStmtDecl::CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, - TemplateParameterList *TParams) + NonTypeTemplateParmDecl *NTTP) : Decl(CXXExpansionStmt, DC, Loc), DeclContext(CXXExpansionStmt), - TParams(TParams) {} + IndexNTTP(NTTP) {} CXXExpansionStmtDecl * CXXExpansionStmtDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, - TemplateParameterList *TParams) { - return new (C, DC) CXXExpansionStmtDecl(DC, Loc, TParams); + NonTypeTemplateParmDecl *NTTP) { + return new (C, DC) CXXExpansionStmtDecl(DC, Loc, NTTP); } CXXExpansionStmtDecl * CXXExpansionStmtDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 3086d7315a862..e8da8a3060904 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2775,7 +2775,7 @@ void ASTDeclReader::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { D->Expansion = cast(Record.readStmt()); D->Instantiations = cast_or_null(Record.readStmt()); - D->TParams = Record.readTemplateParameterList(); + D->IndexNTTP = cast(Record.readDeclRef()); } void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 23d11341d131a..c65c9f8fc581f 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -2193,7 +2193,7 @@ void ASTDeclWriter::VisitCXXExpansionStmtDecl(CXXExpansionStmtDecl *D) { VisitDecl(D); Record.AddStmt(D->getExpansionPattern()); Record.AddStmt(D->getInstantiations()); - Record.AddTemplateParameterList(D->getTemplateParameters()); + Record.AddDeclRef(D->getIndexTemplateParm()); Code = serialization::DECL_EXPANSION_STMT; } From 8a4a548b2ec5d4fa9cc0b0bec96e324f8745c4f2 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 3 Dec 2025 18:17:15 +0100 Subject: [PATCH 6/9] Eliminate CXXExpansionInitListExpr --- clang/include/clang/AST/ComputeDependence.h | 3 - clang/include/clang/AST/ExprCXX.h | 85 ++----------------- clang/include/clang/AST/RecursiveASTVisitor.h | 1 - clang/include/clang/AST/StmtCXX.h | 6 +- clang/include/clang/AST/TextNodeDumper.h | 1 - clang/include/clang/Basic/StmtNodes.td | 1 - .../include/clang/Serialization/ASTBitCodes.h | 1 - clang/lib/AST/ASTImporter.cpp | 17 ---- clang/lib/AST/ComputeDependence.cpp | 7 -- clang/lib/AST/Expr.cpp | 1 - clang/lib/AST/ExprCXX.cpp | 36 +------- clang/lib/AST/ExprClassification.cpp | 1 - clang/lib/AST/ExprConstant.cpp | 1 - clang/lib/AST/ItaniumMangle.cpp | 1 - clang/lib/AST/StmtCXX.cpp | 22 ----- clang/lib/AST/StmtPrinter.cpp | 7 -- clang/lib/AST/StmtProfile.cpp | 5 -- clang/lib/AST/TextNodeDumper.cpp | 6 -- clang/lib/Sema/SemaExceptionSpec.cpp | 1 - clang/lib/Serialization/ASTReaderStmt.cpp | 17 +--- clang/lib/Serialization/ASTWriterStmt.cpp | 10 --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 - clang/tools/libclang/CXCursor.cpp | 1 - 23 files changed, 10 insertions(+), 222 deletions(-) diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 792f45bea5aeb..c298f2620f211 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -94,7 +94,6 @@ class DesignatedInitExpr; class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; -class CXXExpansionInitListExpr; class ArraySectionExpr; class OMPArrayShapingExpr; class OMPIteratorExpr; @@ -192,8 +191,6 @@ ExprDependence computeDependence(ParenListExpr *E); ExprDependence computeDependence(PseudoObjectExpr *E); ExprDependence computeDependence(AtomicExpr *E); -ExprDependence computeDependence(CXXExpansionInitListExpr *E); - ExprDependence computeDependence(ArraySectionExpr *E); ExprDependence computeDependence(OMPArrayShapingExpr *E); ExprDependence computeDependence(OMPIteratorExpr *E); diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index a190a178bfce8..6bf2d52399285 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5499,79 +5499,6 @@ class BuiltinBitCastExpr final } }; -/// Represents an expansion-init-list of an enumerating expansion statement. -/// -/// For example, in -/// \verbatim -/// template for (auto x : { 1, 2, 3 }) { -/// // ... -/// } -/// \endverbatim -/// -/// the '{ 1, 2, 3 }' part is parsed and stored as a 'CXXExpansionInitListExpr'; -/// syntactically, this *looks* very similar to an initializer list, but it -/// isn't actually an expression: '{ 1, 2, 3 }' as a whole is never evaluated -/// or emitted, only the individual expressions '1', '2', and '3' are. We still -/// represent it as an expression in the AST for simplicity. -/// -/// \see CXXEnumeratingExpansionStmtPattern -class CXXExpansionInitListExpr final - : public Expr, - llvm::TrailingObjects { - friend class ASTStmtReader; - friend TrailingObjects; - - const unsigned NumExprs; - SourceLocation LBraceLoc; - SourceLocation RBraceLoc; - - CXXExpansionInitListExpr(EmptyShell ES, unsigned NumExprs); - CXXExpansionInitListExpr(ArrayRef Exprs, SourceLocation LBraceLoc, - SourceLocation RBraceLoc); - -public: - static CXXExpansionInitListExpr *Create(const ASTContext &C, - ArrayRef Exprs, - SourceLocation LBraceLoc, - SourceLocation RBraceLoc); - - static CXXExpansionInitListExpr * - CreateEmpty(const ASTContext &C, EmptyShell Empty, unsigned NumExprs); - - ArrayRef getExprs() const { return getTrailingObjects(NumExprs); } - MutableArrayRef getExprs() { return getTrailingObjects(NumExprs); } - unsigned getNumExprs() const { return NumExprs; } - - bool containsPackExpansion() const; - - SourceLocation getBeginLoc() const { return getLBraceLoc(); } - SourceLocation getEndLoc() const { return getRBraceLoc(); } - - SourceLocation getLBraceLoc() const { return LBraceLoc; } - SourceLocation getRBraceLoc() const { return RBraceLoc; } - - child_range children() { - const_child_range CCR = - const_cast(this)->children(); - return child_range(cast_away_const(CCR.begin()), - cast_away_const(CCR.end())); - } - - const_child_range children() const { - Stmt **Stmts = getTrailingStmts(); - return const_child_range(Stmts, Stmts + NumExprs); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXExpansionInitListExprClass; - } - -private: - Stmt **getTrailingStmts() const { - return reinterpret_cast(const_cast(getTrailingObjects())); - } -}; - /// Helper that selects an expression from an expansion init list depending /// on the current expansion index. /// @@ -5585,17 +5512,17 @@ class CXXExpansionInitListSelectExpr : public Expr { public: CXXExpansionInitListSelectExpr(EmptyShell Empty); CXXExpansionInitListSelectExpr(const ASTContext &C, - CXXExpansionInitListExpr *Range, Expr *Idx); + InitListExpr *Range, Expr *Idx); - CXXExpansionInitListExpr *getRangeExpr() { - return cast(SubExprs[RANGE]); + InitListExpr *getRangeExpr() { + return cast(SubExprs[RANGE]); } - const CXXExpansionInitListExpr *getRangeExpr() const { - return cast(SubExprs[RANGE]); + const InitListExpr *getRangeExpr() const { + return cast(SubExprs[RANGE]); } - void setRangeExpr(CXXExpansionInitListExpr *E) { SubExprs[RANGE] = E; } + void setRangeExpr(InitListExpr *E) { SubExprs[RANGE] = E; } Expr *getIndexExpr() { return SubExprs[INDEX]; } const Expr *getIndexExpr() const { return SubExprs[INDEX]; } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 24052df70c7a8..b325df7328f76 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3130,7 +3130,6 @@ DEF_TRAVERSE_STMT(CXXIteratingExpansionStmtPattern, {}) DEF_TRAVERSE_STMT(CXXDestructuringExpansionStmtPattern, {}) DEF_TRAVERSE_STMT(CXXDependentExpansionStmtPattern, {}) DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {}) -DEF_TRAVERSE_STMT(CXXExpansionInitListExpr, {}) DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {}) DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {}) diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index 2ecb653126e5f..f796f317c363e 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -586,8 +586,6 @@ class CXXExpansionStmtPattern : public Stmt { return getBody() ? getBody()->getEndLoc() : RParenLoc; } - bool hasDependentSize() const; - CXXExpansionStmtDecl *getDecl() { return ParentDecl; } const CXXExpansionStmtDecl *getDecl() const { return ParentDecl; } @@ -632,7 +630,7 @@ class CXXExpansionStmtPattern : public Stmt { /// an initializer list, but it isn't actually an expression in and of itself /// (in that it is never evaluated or emitted) and instead is just treated as /// a group of expressions. The expansion initializer of this is always a -/// 'CXXExpansionInitListExpr'. +/// syntactic-form 'InitListExpr'. /// /// Example: /// \verbatim @@ -644,7 +642,7 @@ class CXXExpansionStmtPattern : public Stmt { /// Note that the expression-list may also contain pack expansions, e.g. /// '{ 1, xs... }', in which case the expansion size is dependent. /// -/// Here, the '{ 1, 2, 3 }' is parsed as a 'CXXExpansionInitListExpr'. This node +/// Here, the '{ 1, 2, 3 }' is parsed as an 'InitListExpr'. This node /// handles storing (and pack-expanding) the individual expressions. /// /// Sema then wraps this with a 'CXXExpansionInitListSelectExpr', which also diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 3db8ce0d5aed3..64998c128053a 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -314,7 +314,6 @@ class TextNodeDumper VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node); void VisitCXXDestructuringExpansionSelectExpr( const CXXDestructuringExpansionSelectExpr *Node); - void VisitCXXExpansionInitListExpr(const CXXExpansionInitListExpr *Node); void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); void VisitObjCMessageExpr(const ObjCMessageExpr *Node); diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 505ed481e0895..abbde50c7016b 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -187,7 +187,6 @@ def ConceptSpecializationExpr : StmtNode; def RequiresExpr : StmtNode; // C++26 Expansion statement support expressions -def CXXExpansionInitListExpr : StmtNode; def CXXExpansionInitListSelectExpr : StmtNode; def CXXDestructuringExpansionSelectExpr : StmtNode; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 36cccdcbd306e..033407dbba2f4 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1942,7 +1942,6 @@ enum StmtCode { EXPR_CXX_FOLD, // CXXFoldExpr EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr EXPR_REQUIRES, // RequiresExpr - EXPR_CXX_EXPANSION_INIT_LIST, // CXXExpansionInitListExpr EXPR_CXX_EXPANSION_INIT_LIST_SELECT, // CXXExpansionInitListSelectExpr EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT, // CXXDestructuringExpansionSelectExpr diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 225c573ecc042..0b65ec4f4cd8c 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -711,7 +711,6 @@ namespace clang { VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E); ExpectedStmt VisitCXXParenListInitExpr(CXXParenListInitExpr *E); - ExpectedStmt VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E); ExpectedStmt VisitCXXExpansionInitListSelectExpr(CXXExpansionInitListSelectExpr *E); ExpectedStmt VisitCXXDestructuringExpansionSelectExpr( @@ -9480,22 +9479,6 @@ ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { ToInitLoc, ToBeginLoc, ToEndLoc); } -ExpectedStmt -ASTNodeImporter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { - Error Err = Error::success(); - SmallVector ToExprs; - auto ToLBraceLoc = importChecked(Err, E->getLBraceLoc()); - auto ToRBraceLoc = importChecked(Err, E->getRBraceLoc()); - for (Expr *FromInst : E->getExprs()) - ToExprs.push_back(importChecked(Err, FromInst)); - - if (Err) - return std::move(Err); - - return CXXExpansionInitListExpr::Create(Importer.getToContext(), ToExprs, - ToLBraceLoc, ToRBraceLoc); -} - ExpectedStmt ASTNodeImporter::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *E) { Error Err = Error::success(); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 2ff9d74f1a8d5..638080ea781a9 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -959,10 +959,3 @@ ExprDependence clang::computeDependence(OpenACCAsteriskSizeExpr *E) { // way. return ExprDependence::None; } - -ExprDependence clang::computeDependence(CXXExpansionInitListExpr *ILE) { - auto D = ExprDependence::None; - for (Expr *E : ILE->getExprs()) - D |= E->getDependence(); - return D; -} diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index c61660c90513f..af2d264623f89 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3689,7 +3689,6 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case RecoveryExprClass: case CXXFoldExprClass: case CXXExpansionInitListSelectExprClass: - case CXXExpansionInitListExprClass: case CXXDestructuringExpansionSelectExprClass: // Make a conservative assumption for dependent nodes. return IncludePossibleEffects; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 7ba49f74c1f7d..8975d9af87ce1 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -2021,40 +2021,11 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee, setDependence(computeDependence(this)); } -CXXExpansionInitListExpr::CXXExpansionInitListExpr(EmptyShell ES, - unsigned NumExprs) - : Expr(CXXExpansionInitListExprClass, ES), NumExprs(NumExprs) {} - -CXXExpansionInitListExpr::CXXExpansionInitListExpr(ArrayRef Exprs, - SourceLocation LBraceLoc, - SourceLocation RBraceLoc) - : Expr(CXXExpansionInitListExprClass, QualType(), VK_PRValue, OK_Ordinary), - NumExprs(static_cast(Exprs.size())), LBraceLoc(LBraceLoc), - RBraceLoc(RBraceLoc) { - llvm::uninitialized_copy(Exprs, getTrailingObjects()); - setDependence(computeDependence(this)); -} - -CXXExpansionInitListExpr * -CXXExpansionInitListExpr::Create(const ASTContext &C, ArrayRef Exprs, - SourceLocation LBraceLoc, - SourceLocation RBraceLoc) { - void *Mem = C.Allocate(totalSizeToAlloc(Exprs.size())); - return new (Mem) CXXExpansionInitListExpr(Exprs, LBraceLoc, RBraceLoc); -} - -CXXExpansionInitListExpr * -CXXExpansionInitListExpr::CreateEmpty(const ASTContext &C, EmptyShell Empty, - unsigned NumExprs) { - void *Mem = C.Allocate(totalSizeToAlloc(NumExprs)); - return new (Mem) CXXExpansionInitListExpr(Empty, NumExprs); -} - CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr(EmptyShell Empty) : Expr(CXXExpansionInitListSelectExprClass, Empty) {} CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr( - const ASTContext &C, CXXExpansionInitListExpr *Range, Expr *Idx) + const ASTContext &C, InitListExpr *Range, Expr *Idx) : Expr(CXXExpansionInitListSelectExprClass, C.DependentTy, VK_PRValue, OK_Ordinary) { setDependence(ExprDependence::TypeValueInstantiation); @@ -2062,11 +2033,6 @@ CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr( SubExprs[INDEX] = Idx; } -bool CXXExpansionInitListExpr::containsPackExpansion() const { - return llvm::any_of(getExprs(), - [](const Expr *E) { return isa(E); }); -} - CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr( EmptyShell Empty) : Expr(CXXDestructuringExpansionSelectExprClass, Empty) {} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 5521cdf9d04c9..1b139ac0954b8 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -216,7 +216,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: case Expr::RequiresExprClass: - case Expr::CXXExpansionInitListExprClass: case Expr::CXXExpansionInitListSelectExprClass: case Expr::CXXDestructuringExpansionSelectExprClass: return Cl::CL_PRValue; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d93f87a27e68d..0bd56bb0a76e2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -20276,7 +20276,6 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::SYCLUniqueStableNameExprClass: case Expr::CXXParenListInitExprClass: case Expr::HLSLOutArgExprClass: - case Expr::CXXExpansionInitListExprClass: case Expr::CXXExpansionInitListSelectExprClass: case Expr::CXXDestructuringExpansionSelectExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 28883edc34e6d..db8cdc0a33d04 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4946,7 +4946,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::CXXParenListInitExprClass: case Expr::PackIndexingExprClass: case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXExpansionInitListExprClass: case Expr::CXXDestructuringExpansionSelectExprClass: llvm_unreachable("unexpected statement kind"); diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index f34c11d4eff39..da4e3be6eaa2f 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -162,28 +162,6 @@ VarDecl *CXXExpansionStmtPattern::getExpansionVariable() { return cast(LV); } -bool CXXExpansionStmtPattern::hasDependentSize() const { - if (isa(this)) - return cast( - getExpansionVariable()->getInit()) - ->getRangeExpr() - ->containsPackExpansion(); - - if (auto *Iterating = dyn_cast(this)) { - const Expr *Begin = Iterating->getBeginVar()->getInit(); - const Expr *End = Iterating->getEndVar()->getInit(); - return Begin->isInstantiationDependent() || End->isInstantiationDependent(); - } - - if (isa(this)) - return false; - - if (isa(this)) - return true; - - llvm_unreachable("Invalid expansion statement class"); -} - CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern( EmptyShell Empty) : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, Empty) {} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 6760d3bbe54cc..165bbd046f5f4 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -490,13 +490,6 @@ void StmtPrinter::VisitCXXExpansionStmtInstantiation( llvm_unreachable("should never be printed"); } -void StmtPrinter::VisitCXXExpansionInitListExpr( - CXXExpansionInitListExpr *Node) { - OS << "{ "; - llvm::interleaveComma(Node->getExprs(), OS, [&](Expr *E) { PrintExpr(E); }); - OS << " }"; -} - void StmtPrinter::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *Node) { PrintExpr(Node->getRangeExpr()); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 45513c479e1d1..08759bbaa2ed3 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2431,11 +2431,6 @@ void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { void StmtProfiler::VisitEmbedExpr(const EmbedExpr *E) { VisitExpr(E); } -void StmtProfiler::VisitCXXExpansionInitListExpr( - const CXXExpansionInitListExpr *E) { - VisitExpr(E); -} - void StmtProfiler::VisitCXXExpansionInitListSelectExpr( const CXXExpansionInitListSelectExpr *E) { VisitExpr(E); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 4d19bf63f3536..e20cb63ee54b8 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1836,12 +1836,6 @@ void TextNodeDumper::VisitCXXDependentScopeMemberExpr( OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember(); } -void TextNodeDumper::VisitCXXExpansionInitListExpr( - const CXXExpansionInitListExpr *Node) { - if (Node->containsPackExpansion()) - OS << " contains_pack"; -} - void TextNodeDumper::VisitCXXDestructuringExpansionSelectExpr( const CXXDestructuringExpansionSelectExpr *Node) { dumpDeclRef(Node->getDecompositionDecl()); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a56f933638190..5839785dbaab2 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1289,7 +1289,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::VAArgExprClass: case Expr::CXXParenListInitExprClass: case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXExpansionInitListExprClass: case Expr::CXXDestructuringExpansionSelectExprClass: return canSubStmtsThrow(*this, S); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index c74113c4ab0da..f3ea8c99666eb 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1777,20 +1777,10 @@ void ASTStmtReader::VisitCXXDependentExpansionStmtPattern( S->setExpansionInitializer(Record.readSubExpr()); } -void ASTStmtReader::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { - VisitExpr(E); - assert(Record.peekInt() == E->getNumExprs() && "NumExprFields is wrong ?"); - Record.skipInts(1); - E->LBraceLoc = readSourceLocation(); - E->RBraceLoc = readSourceLocation(); - for (unsigned I = 0; I < E->getNumExprs(); ++I) - E->getExprs()[I] = Record.readSubExpr(); -} - void ASTStmtReader::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *E) { VisitExpr(E); - E->setRangeExpr(cast(Record.readSubExpr())); + E->setRangeExpr(cast(Record.readSubExpr())); E->setIndexExpr(Record.readSubExpr()); } @@ -4537,11 +4527,6 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } - case EXPR_CXX_EXPANSION_INIT_LIST: - S = CXXExpansionInitListExpr::CreateEmpty( - Context, Empty, Record[ASTStmtReader::NumExprFields]); - break; - case EXPR_CXX_EXPANSION_INIT_LIST_SELECT: S = new (Context) CXXExpansionInitListSelectExpr(Empty); break; diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index d795b23525888..8319a59bc951f 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1757,16 +1757,6 @@ void ASTStmtWriter::VisitCXXDependentExpansionStmtPattern( Code = serialization::STMT_CXX_DEPENDENT_EXPANSION; } -void ASTStmtWriter::VisitCXXExpansionInitListExpr(CXXExpansionInitListExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumExprs()); - Record.AddSourceLocation(E->getLBraceLoc()); - Record.AddSourceLocation(E->getRBraceLoc()); - for (Expr *SubExpr : E->getExprs()) - Record.AddStmt(SubExpr); - Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST; -} - void ASTStmtWriter::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *E) { VisitExpr(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 38106f154c15e..53f85c22dd020 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1757,7 +1757,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXDestructuringExpansionStmtPatternClass: case Stmt::CXXDependentExpansionStmtPatternClass: case Stmt::CXXExpansionStmtInstantiationClass: - case Stmt::CXXExpansionInitListExprClass: case Stmt::CXXExpansionInitListSelectExprClass: case Stmt::CXXDestructuringExpansionSelectExprClass: case Stmt::OMPCanonicalLoopClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index f0ae4f0b593a2..ecd1f86c3ddb6 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -343,7 +343,6 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::EmbedExprClass: case Stmt::HLSLOutArgExprClass: case Stmt::OpenACCAsteriskSizeExprClass: - case Stmt::CXXExpansionInitListExprClass: case Stmt::CXXExpansionInitListSelectExprClass: case Stmt::CXXDestructuringExpansionSelectExprClass: K = CXCursor_UnexposedExpr; From 76330f99eaed92260746a95dfe08b8496c14f7c3 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 3 Dec 2025 20:14:37 +0100 Subject: [PATCH 7/9] Merge all pattern kinds into a single AST node --- clang/include/clang/AST/RecursiveASTVisitor.h | 5 +- clang/include/clang/AST/StmtCXX.h | 495 +++++++++--------- clang/include/clang/AST/TextNodeDumper.h | 1 + clang/include/clang/Basic/StmtNodes.td | 6 +- .../include/clang/Serialization/ASTBitCodes.h | 15 +- clang/lib/AST/ASTImporter.cpp | 106 ++-- clang/lib/AST/StmtCXX.cpp | 145 ++--- clang/lib/AST/StmtPrinter.cpp | 35 +- clang/lib/AST/StmtProfile.cpp | 20 - clang/lib/AST/TextNodeDumper.cpp | 18 + clang/lib/CodeGen/CGStmt.cpp | 5 +- clang/lib/Sema/SemaExceptionSpec.cpp | 10 +- clang/lib/Serialization/ASTReaderStmt.cpp | 50 +- clang/lib/Serialization/ASTWriterStmt.cpp | 36 +- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 5 +- clang/tools/libclang/CXCursor.cpp | 5 +- 16 files changed, 443 insertions(+), 514 deletions(-) diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index b325df7328f76..b145fa9f9cdf0 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3125,10 +3125,7 @@ DEF_TRAVERSE_STMT(RequiresExpr, { TRY_TO(TraverseConceptRequirement(Req)); }) -DEF_TRAVERSE_STMT(CXXEnumeratingExpansionStmtPattern, {}) -DEF_TRAVERSE_STMT(CXXIteratingExpansionStmtPattern, {}) -DEF_TRAVERSE_STMT(CXXDestructuringExpansionStmtPattern, {}) -DEF_TRAVERSE_STMT(CXXDependentExpansionStmtPattern, {}) +DEF_TRAVERSE_STMT(CXXExpansionStmtPattern, {}) DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {}) DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {}) DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {}) diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index f796f317c363e..fcc30c3b1d421 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -525,107 +525,16 @@ class CoreturnStmt : public Stmt { } }; -/// CXXExpansionStmtPattern - Base class for an unexpanded C++ expansion -/// statement. +/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement. /// -/// The main purpose for this class is to store the AST nodes common to all -/// variants of expansion statements; it also provides storage for additional -/// subexpressions required by its derived classes. This is to simplify the -/// implementation of 'children()' and friends. +/// There are four kinds of expansion statements. /// -/// \see CXXExpansionStmtDecl for more documentation on expansion statements. -class CXXExpansionStmtPattern : public Stmt { - friend class ASTStmtReader; - - CXXExpansionStmtDecl *ParentDecl; - SourceLocation LParenLoc; - SourceLocation ColonLoc; - SourceLocation RParenLoc; - -protected: - enum SubStmt { - INIT, - VAR, - BODY, - FIRST_CHILD_STMT, - - // CXXDependentExpansionStmtPattern - EXPANSION_INITIALIZER = FIRST_CHILD_STMT, - COUNT_CXXDependentExpansionStmtPattern, - - // CXXDestructuringExpansionStmtPattern - DECOMP_DECL = FIRST_CHILD_STMT, - COUNT_CXXDestructuringExpansionStmtPattern, - - // CXXIteratingExpansionStmtPattern - RANGE = FIRST_CHILD_STMT, - BEGIN, - END, - COUNT_CXXIteratingExpansionStmtPattern, - - MAX_COUNT = COUNT_CXXIteratingExpansionStmtPattern, - }; - - // Managing the memory for this properly would be rather complicated, and - // expansion statements are fairly uncommon, so just allocate space for the - // maximum amount of substatements we could possibly have. - Stmt *SubStmts[MAX_COUNT]; - - CXXExpansionStmtPattern(StmtClass SC, EmptyShell Empty); - CXXExpansionStmtPattern(StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, - DeclStmt *ExpansionVar, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation RParenLoc); - -public: - SourceLocation getLParenLoc() const { return LParenLoc; } - SourceLocation getColonLoc() const { return ColonLoc; } - SourceLocation getRParenLoc() const { return RParenLoc; } - - SourceLocation getBeginLoc() const; - SourceLocation getEndLoc() const { - return getBody() ? getBody()->getEndLoc() : RParenLoc; - } - - CXXExpansionStmtDecl *getDecl() { return ParentDecl; } - const CXXExpansionStmtDecl *getDecl() const { return ParentDecl; } - - Stmt *getInit() { return SubStmts[INIT]; } - const Stmt *getInit() const { return SubStmts[INIT]; } - void setInit(Stmt *S) { SubStmts[INIT] = S; } - - VarDecl *getExpansionVariable(); - const VarDecl *getExpansionVariable() const { - return const_cast(this)->getExpansionVariable(); - } - - DeclStmt *getExpansionVarStmt() { return cast(SubStmts[VAR]); } - const DeclStmt *getExpansionVarStmt() const { - return cast(SubStmts[VAR]); - } - - void setExpansionVarStmt(Stmt *S) { SubStmts[VAR] = S; } - - Stmt *getBody() { return SubStmts[BODY]; } - const Stmt *getBody() const { return SubStmts[BODY]; } - void setBody(Stmt *S) { SubStmts[BODY] = S; } - - static bool classof(const Stmt *T) { - return T->getStmtClass() >= firstCXXExpansionStmtPatternConstant && - T->getStmtClass() <= lastCXXExpansionStmtPatternConstant; - } - - child_range children() { - return child_range(SubStmts, SubStmts + FIRST_CHILD_STMT); - } - - const_child_range children() const { - return const_child_range(SubStmts, SubStmts + FIRST_CHILD_STMT); - } -}; - -/// Represents an unexpanded enumerating expansion statement. +/// 1. Enumerating expansion statements. +/// 2. Iterating expansion statements. +/// 3. Destructuring expansion statements. +/// 4. Dependent expansion statements. /// -/// An 'enumerating' expansion statement is one whose expansion-initializer +/// 1. An 'enumerating' expansion statement is one whose expansion-initializer /// is a brace-enclosed expression-list; this list is syntactically similar to /// an initializer list, but it isn't actually an expression in and of itself /// (in that it is never evaluated or emitted) and instead is just treated as @@ -654,30 +563,54 @@ class CXXExpansionStmtPattern : public Stmt { /// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and /// BuildCXXExpansionInitListSelectExpr(), when called via TreeTransform, /// 'instantiates' the expression '{ a, b, c }' to just 'b'. -class CXXEnumeratingExpansionStmtPattern : public CXXExpansionStmtPattern { - friend class ASTStmtReader; - -public: - CXXEnumeratingExpansionStmtPattern(EmptyShell Empty); - CXXEnumeratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, - DeclStmt *ExpansionVar, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation RParenLoc); - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXEnumeratingExpansionStmtPatternClass; - } -}; - -/// Represents an expansion statement whose expansion-initializer is +/// +/// 2. Represents an unexpanded iterating expansion statement. +/// +/// An 'iterating' expansion statement is one whose expansion-initializer is a +/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is +/// determined based on a number of conditions as stated in [stmt.expand] and +/// [stmt.ranged]). +/// +/// The expression used to compute the size of the expansion is not stored and +/// is only created at the moment of expansion. +/// +/// Example: +/// \verbatim +/// static constexpr std::string_view foo = "1234"; +/// template for (auto x : foo) { +/// // ... +/// } +/// \endverbatim +/// +/// 3. Represents an unexpanded destructuring expansion statement. +/// +/// A 'destructuring' expansion statement is any expansion statement that is +/// not enumerating or iterating (i.e. destructuring is the last thing we try, +/// and if it doesn't work, the program is ill-formed). +/// +/// This essentially involves treating the expansion-initializer as the +/// initializer of a structured-binding declarations, with the number of +/// bindings and expansion size determined by the usual means (array size, +/// std::tuple_size, etc.). +/// +/// Example: +/// \verbatim +/// std::array a {1, 2, 3}; +/// template for (auto x : a) { +/// // ... +/// } +/// \endverbatim +/// +/// Sema wraps the initializer with a CXXDestructuringExpansionSelectExpr, which +/// selects a binding based on the current expansion index; this is analogous to +/// how 'CXXExpansionInitListSelectExpr' is used. +/// +/// 4. Represents an expansion statement whose expansion-initializer is /// type-dependent. /// -/// This will be instantiated as either a 'CXXIteratingExpansionStmtPattern' or -/// a 'CXXDestructuringExpansionStmtPattern'. Dependent expansion statements can -/// never be enumerating; those are always stored as a -/// 'CXXEnumeratingExpansionStmtPattern', even if the expansion size is -/// dependent because the expression-list contains a pack. +/// This will be instantiated as either an iterating or destructuring expansion +/// statement. Dependent expansion statements can never be enumerating, even if +/// the expansion size is dependent because the expression-list contains a pack. /// /// Example: /// \verbatim @@ -688,184 +621,278 @@ class CXXEnumeratingExpansionStmtPattern : public CXXExpansionStmtPattern { /// } /// } /// \endverbatim -class CXXDependentExpansionStmtPattern : public CXXExpansionStmtPattern { +/// +/// \see CXXExpansionStmtDecl for more documentation on expansion statements. +class CXXExpansionStmtPattern final + : public Stmt, + llvm::TrailingObjects { friend class ASTStmtReader; + friend TrailingObjects; public: - CXXDependentExpansionStmtPattern(EmptyShell Empty); - CXXDependentExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, - DeclStmt *ExpansionVar, - Expr *ExpansionInitializer, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation RParenLoc); + enum class ExpansionStmtKind : uint8_t { + Enumerating, + Iterating, + Destructuring, + Dependent, + }; - Expr *getExpansionInitializer() { - return cast(SubStmts[EXPANSION_INITIALIZER]); - } - const Expr *getExpansionInitializer() const { - return cast(SubStmts[EXPANSION_INITIALIZER]); +private: + ExpansionStmtKind PatternKind; + SourceLocation LParenLoc; + SourceLocation ColonLoc; + SourceLocation RParenLoc; + CXXExpansionStmtDecl *ParentDecl; + + enum SubStmt { + INIT, + VAR, + BODY, + FIRST_CHILD_STMT, + COUNT_Enumerating = FIRST_CHILD_STMT, + + // Dependent expansion initializer. + EXPANSION_INITIALIZER = FIRST_CHILD_STMT, + COUNT_Dependent, + + // Destructuring expansion statement. + DECOMP_DECL = FIRST_CHILD_STMT, + COUNT_Destructuring, + + // Iterating expansion statement. + RANGE = FIRST_CHILD_STMT, + BEGIN, + END, + COUNT_Iterating, + }; + + CXXExpansionStmtPattern(ExpansionStmtKind PatternKind, EmptyShell Empty); + CXXExpansionStmtPattern(ExpansionStmtKind PatternKind, + CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc); + +public: + static CXXExpansionStmtPattern * + CreateEmpty(ASTContext &Context, EmptyShell Empty, ExpansionStmtKind Kind); + + /// Create a dependent expansion statement pattern. + static CXXExpansionStmtPattern * + CreateDependent(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, Expr *ExpansionInitializer, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc); + + /// Create a destructuring expansion statement pattern. + static CXXExpansionStmtPattern * + CreateDestructuring(ASTContext &Context, CXXExpansionStmtDecl *ESD, + Stmt *Init, DeclStmt *ExpansionVar, + Stmt *DecompositionDeclStmt, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc); + + /// Create an enumerating expansion statement pattern. + static CXXExpansionStmtPattern * + CreateEnumerating(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc); + + /// Create an iterating expansion statement pattern. + static CXXExpansionStmtPattern * + CreateIterating(ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, DeclStmt *Range, DeclStmt *Begin, + DeclStmt *End, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc); + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + SourceLocation getBeginLoc() const; + SourceLocation getEndLoc() const { + return getBody() ? getBody()->getEndLoc() : RParenLoc; } - void setExpansionInitializer(Expr *S) { SubStmts[EXPANSION_INITIALIZER] = S; } - child_range children() { - return child_range(SubStmts, - SubStmts + COUNT_CXXDependentExpansionStmtPattern); + ExpansionStmtKind getKind() const { return PatternKind; } + bool isDependent() const { + return PatternKind == ExpansionStmtKind::Dependent; + } + bool isEnumerating() const { + return PatternKind == ExpansionStmtKind::Enumerating; + } + bool isIterating() const { + return PatternKind == ExpansionStmtKind::Iterating; + } + bool isDestructuring() const { + return PatternKind == ExpansionStmtKind::Destructuring; } - const_child_range children() const { - return const_child_range(SubStmts, - SubStmts + COUNT_CXXDependentExpansionStmtPattern); + unsigned getNumSubStmts() const { return getNumSubStmts(PatternKind); } + + // Accessors for subcomponents common to all expansion statements. + CXXExpansionStmtDecl *getDecl() { return ParentDecl; } + const CXXExpansionStmtDecl *getDecl() const { return ParentDecl; } + + Stmt *getInit() { return getSubStmt(INIT); } + const Stmt *getInit() const { return getSubStmt(INIT); } + void setInit(Stmt *S) { getSubStmt(INIT) = S; } + + VarDecl *getExpansionVariable(); + const VarDecl *getExpansionVariable() const { + return const_cast(this)->getExpansionVariable(); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXDependentExpansionStmtPatternClass; + DeclStmt *getExpansionVarStmt() { return cast(getSubStmt(VAR)); } + const DeclStmt *getExpansionVarStmt() const { + return cast(getSubStmt(VAR)); } -}; -/// Represents an unexpanded iterating expansion statement. -/// -/// An 'iterating' expansion statement is one whose expansion-initializer is a -/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is -/// determined based on a number of conditions as stated in [stmt.expand] and -/// [stmt.ranged]). -/// -/// The expression used to compute the size of the expansion is not stored and -/// is only created at the moment of expansion. -/// -/// Example: -/// \verbatim -/// static constexpr std::string_view foo = "1234"; -/// template for (auto x : foo) { -/// // ... -/// } -/// \endverbatim -class CXXIteratingExpansionStmtPattern : public CXXExpansionStmtPattern { - friend class ASTStmtReader; + void setExpansionVarStmt(Stmt *S) { getSubStmt(VAR) = S; } -public: - CXXIteratingExpansionStmtPattern(EmptyShell Empty); - CXXIteratingExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, - DeclStmt *ExpansionVar, DeclStmt *Range, - DeclStmt *Begin, DeclStmt *End, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation RParenLoc); + Stmt *getBody() { return getSubStmt(BODY); } + const Stmt *getBody() const { return getSubStmt(BODY); } + void setBody(Stmt *S) { getSubStmt(BODY) = S; } + // Accessors for iterating statements. const DeclStmt *getRangeVarStmt() const { - return cast(SubStmts[RANGE]); + assert(isIterating()); + return cast(getSubStmt(RANGE)); + } + + DeclStmt *getRangeVarStmt() { + assert(isIterating()); + return cast(getSubStmt(RANGE)); + } + + void setRangeVarStmt(DeclStmt *S) { + assert(isIterating()); + getSubStmt(RANGE) = S; } - DeclStmt *getRangeVarStmt() { return cast(SubStmts[RANGE]); } - void setRangeVarStmt(DeclStmt *S) { SubStmts[RANGE] = S; } const VarDecl *getRangeVar() const { + assert(isIterating()); return cast(getRangeVarStmt()->getSingleDecl()); } VarDecl *getRangeVar() { + assert(isIterating()); return cast(getRangeVarStmt()->getSingleDecl()); } const DeclStmt *getBeginVarStmt() const { - return cast(SubStmts[BEGIN]); + assert(isIterating()); + return cast(getSubStmt(BEGIN)); + } + + DeclStmt *getBeginVarStmt() { + assert(isIterating()); + return cast(getSubStmt(BEGIN)); + } + + void setBeginVarStmt(DeclStmt *S) { + assert(isIterating()); + getSubStmt(BEGIN) = S; } - DeclStmt *getBeginVarStmt() { return cast(SubStmts[BEGIN]); } - void setBeginVarStmt(DeclStmt *S) { SubStmts[BEGIN] = S; } const VarDecl *getBeginVar() const { + assert(isIterating()); return cast(getBeginVarStmt()->getSingleDecl()); } VarDecl *getBeginVar() { + assert(isIterating()); return cast(getBeginVarStmt()->getSingleDecl()); } const DeclStmt *getEndVarStmt() const { - return cast(SubStmts[END]); + assert(isIterating()); + return cast(getSubStmt(END)); + } + + DeclStmt *getEndVarStmt() { + assert(isIterating()); + return cast(getSubStmt(END)); + } + + void setEndVarStmt(DeclStmt *S) { + assert(isIterating()); + getSubStmt(END) = S; } - DeclStmt *getEndVarStmt() { return cast(SubStmts[END]); } - void setEndVarStmt(DeclStmt *S) { SubStmts[END] = S; } const VarDecl *getEndVar() const { + assert(isIterating()); return cast(getEndVarStmt()->getSingleDecl()); } VarDecl *getEndVar() { + assert(isIterating()); return cast(getEndVarStmt()->getSingleDecl()); } - child_range children() { - return child_range(SubStmts, - SubStmts + COUNT_CXXIteratingExpansionStmtPattern); + // Accessors for destructuring statements. + Stmt *getDecompositionDeclStmt() { + assert(isDestructuring()); + return getSubStmt(DECOMP_DECL); } - const_child_range children() const { - return const_child_range(SubStmts, - SubStmts + COUNT_CXXIteratingExpansionStmtPattern); + const Stmt *getDecompositionDeclStmt() const { + assert(isDestructuring()); + return getSubStmt(DECOMP_DECL); } - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXIteratingExpansionStmtPatternClass; + void setDecompositionDeclStmt(Stmt *S) { + assert(isDestructuring()); + getSubStmt(DECOMP_DECL) = S; } -}; - -/// Represents an unexpanded destructuring expansion statement. -/// -/// A 'destructuring' expansion statement is any expansion statement that is -/// not enumerating or iterating (i.e. destructuring is the last thing we try, -/// and if it doesn't work, the program is ill-formed). -/// -/// This essentially involves treating the expansion-initializer as the -/// initializer of a structured-binding declarations, with the number of -/// bindings and expansion size determined by the usual means (array size, -/// std::tuple_size, etc.). -/// -/// Example: -/// \verbatim -/// std::array a {1, 2, 3}; -/// template for (auto x : a) { -/// // ... -/// } -/// \endverbatim -/// -/// Sema wraps the initializer with a CXXDestructuringExpansionSelectExpr, which -/// selects a binding based on the current expansion index; this is analogous to -/// how 'CXXExpansionInitListSelectExpr' is used; see the documentation of -/// 'CXXEnumeratingExpansionStmtPattern' for more details on this. -class CXXDestructuringExpansionStmtPattern : public CXXExpansionStmtPattern { - friend class ASTStmtReader; - -public: - CXXDestructuringExpansionStmtPattern(EmptyShell Empty); - CXXDestructuringExpansionStmtPattern(CXXExpansionStmtDecl *ESD, Stmt *Init, - DeclStmt *ExpansionVar, - Stmt *DecompositionDeclStmt, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation RParenLoc); - - Stmt *getDecompositionDeclStmt() { return SubStmts[DECOMP_DECL]; } - const Stmt *getDecompositionDeclStmt() const { return SubStmts[DECOMP_DECL]; } - void setDecompositionDeclStmt(Stmt *S) { SubStmts[DECOMP_DECL] = S; } DecompositionDecl *getDecompositionDecl(); const DecompositionDecl *getDecompositionDecl() const { - return const_cast(this) - ->getDecompositionDecl(); + return const_cast(this)->getDecompositionDecl(); + } + + // Accessors for dependent statements. + Expr *getExpansionInitializer() { + assert(isDependent()); + return cast(getSubStmt(EXPANSION_INITIALIZER)); + } + + const Expr *getExpansionInitializer() const { + assert(isDependent()); + return cast(getSubStmt(EXPANSION_INITIALIZER)); + } + + void setExpansionInitializer(Expr *S) { + assert(isDependent()); + getSubStmt(EXPANSION_INITIALIZER) = S; } child_range children() { - return child_range(SubStmts, - SubStmts + COUNT_CXXDestructuringExpansionStmtPattern); + return child_range(getTrailingObjects(), + getTrailingObjects() + getNumSubStmts()); } const_child_range children() const { - return const_child_range( - SubStmts, SubStmts + COUNT_CXXDestructuringExpansionStmtPattern); + return const_child_range(getTrailingObjects(), + getTrailingObjects() + getNumSubStmts()); } static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXDestructuringExpansionStmtPatternClass; + return T->getStmtClass() == CXXExpansionStmtPatternClass; + } + +private: + template + static CXXExpansionStmtPattern *AllocateAndConstruct(ASTContext &Context, + ExpansionStmtKind Kind, + Args &&...Arguments); + + static unsigned getNumSubStmts(ExpansionStmtKind Kind); + Stmt *getSubStmt(unsigned Idx) const { + assert(Idx < getNumSubStmts()); + return getTrailingObjects()[Idx]; + } + + Stmt *&getSubStmt(unsigned Idx) { + assert(Idx < getNumSubStmts()); + return getTrailingObjects()[Idx]; } }; diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 64998c128053a..24a152cfe1de4 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -266,6 +266,7 @@ class TextNodeDumper void VisitCoawaitExpr(const CoawaitExpr *Node); void VisitCoreturnStmt(const CoreturnStmt *Node); void VisitCompoundStmt(const CompoundStmt *Node); + void VisitCXXExpansionStmtPattern(const CXXExpansionStmtPattern *Node); void VisitCXXExpansionStmtInstantiation(const CXXExpansionStmtInstantiation *Node); void VisitConstantExpr(const ConstantExpr *Node); diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index abbde50c7016b..1df99734f713f 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -59,11 +59,7 @@ def CoroutineBodyStmt : StmtNode; def CoreturnStmt : StmtNode; // C++ expansion statements (P1306) -def CXXExpansionStmtPattern : StmtNode; -def CXXEnumeratingExpansionStmtPattern : StmtNode; -def CXXIteratingExpansionStmtPattern : StmtNode; -def CXXDestructuringExpansionStmtPattern : StmtNode; -def CXXDependentExpansionStmtPattern : StmtNode; +def CXXExpansionStmtPattern : StmtNode; def CXXExpansionStmtInstantiation : StmtNode; // *Not* derived from CXXExpansionStmtPattern! diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 033407dbba2f4..e90fc6bdabca7 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1836,19 +1836,10 @@ enum StmtCode { STMT_CXX_FOR_RANGE, - /// A CXXEnumeratedExpansionStmt. - STMT_CXX_ENUMERATING_EXPANSION, + /// A CXXExpansionPatternStmt. + STMT_CXX_EXPANSION_PATTERN, - /// A CXXIteratingExpansionStmtPattern. - STMT_CXX_ITERATING_EXPANSION, - - /// A CXXDestructuringExpansionStmtPattern. - STMT_CXX_DESTRUCTURING_EXPANSION, - - /// A CXXDependentExpansionStmtPattern, - STMT_CXX_DEPENDENT_EXPANSION, - - /// A CXXExpansionStmtInstantiation. + /// A CXXExpansionInstantiationStmt. STMT_CXX_EXPANSION_INSTANTIATION, /// A CXXOperatorCallExpr record. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 0b65ec4f4cd8c..953646ef4aa08 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -609,14 +609,7 @@ namespace clang { ExpectedStmt VisitCXXCatchStmt(CXXCatchStmt *S); ExpectedStmt VisitCXXTryStmt(CXXTryStmt *S); ExpectedStmt VisitCXXForRangeStmt(CXXForRangeStmt *S); - ExpectedStmt VisitCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *S); - ExpectedStmt - VisitCXXIteratingExpansionStmtPattern(CXXIteratingExpansionStmtPattern *S); - ExpectedStmt VisitCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *S); - ExpectedStmt - VisitCXXDependentExpansionStmtPattern(CXXDependentExpansionStmtPattern *S); + ExpectedStmt VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S); ExpectedStmt VisitCXXExpansionStmtInstantiation(CXXExpansionStmtInstantiation *S); // FIXME: MSDependentExistsStmt @@ -7493,8 +7486,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc); } -ExpectedStmt ASTNodeImporter::VisitCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *S) { +ExpectedStmt ASTNodeImporter::VisitCXXExpansionStmtPattern( + CXXExpansionStmtPattern *S) { Error Err = Error::success(); auto ToESD = importChecked(Err, S->getDecl()); auto ToInit = importChecked(Err, S->getInit()); @@ -7505,64 +7498,49 @@ ExpectedStmt ASTNodeImporter::VisitCXXEnumeratingExpansionStmtPattern( if (Err) return std::move(Err); - return new (Importer.getToContext()) CXXEnumeratingExpansionStmtPattern( - ToESD, ToInit, ToExpansionVar, ToLParenLoc, ToColonLoc, ToRParenLoc); -} -ExpectedStmt ASTNodeImporter::VisitCXXIteratingExpansionStmtPattern( - CXXIteratingExpansionStmtPattern *S) { - Error Err = Error::success(); - auto ToESD = importChecked(Err, S->getDecl()); - auto ToInit = importChecked(Err, S->getInit()); - auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); - auto ToRange = importChecked(Err, S->getRangeVarStmt()); - auto ToBegin = importChecked(Err, S->getBeginVarStmt()); - auto ToEnd = importChecked(Err, S->getEndVarStmt()); - auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); - auto ToColonLoc = importChecked(Err, S->getColonLoc()); - auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); - if (Err) - return std::move(Err); + switch (S->getKind()) { + case CXXExpansionStmtPattern::ExpansionStmtKind::Enumerating: + return CXXExpansionStmtPattern::CreateEnumerating( + Importer.getToContext(), ToESD, ToInit, ToExpansionVar, ToLParenLoc, + ToColonLoc, ToRParenLoc); - return new (Importer.getToContext()) CXXIteratingExpansionStmtPattern( - ToESD, ToInit, ToExpansionVar, ToRange, ToBegin, ToEnd, ToLParenLoc, - ToColonLoc, ToRParenLoc); -} -ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *S) { - Error Err = Error::success(); - auto ToESD = importChecked(Err, S->getDecl()); - auto ToInit = importChecked(Err, S->getInit()); - auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); - auto ToDecompositionDeclStmt = - importChecked(Err, S->getDecompositionDeclStmt()); - auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); - auto ToColonLoc = importChecked(Err, S->getColonLoc()); - auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); - if (Err) - return std::move(Err); + case CXXExpansionStmtPattern::ExpansionStmtKind::Iterating: { + auto ToRange = importChecked(Err, S->getRangeVarStmt()); + auto ToBegin = importChecked(Err, S->getBeginVarStmt()); + auto ToEnd = importChecked(Err, S->getEndVarStmt()); + if (Err) + return std::move(Err); - return new (Importer.getToContext()) CXXDestructuringExpansionStmtPattern( - ToESD, ToInit, ToExpansionVar, ToDecompositionDeclStmt, ToLParenLoc, - ToColonLoc, ToRParenLoc); -} -ExpectedStmt ASTNodeImporter::VisitCXXDependentExpansionStmtPattern( - CXXDependentExpansionStmtPattern *S) { - Error Err = Error::success(); - auto ToESD = importChecked(Err, S->getDecl()); - auto ToInit = importChecked(Err, S->getInit()); - auto ToExpansionVar = importChecked(Err, S->getExpansionVarStmt()); - auto ToExpansionInitializer = - importChecked(Err, S->getExpansionInitializer()); - auto ToLParenLoc = importChecked(Err, S->getLParenLoc()); - auto ToColonLoc = importChecked(Err, S->getColonLoc()); - auto ToRParenLoc = importChecked(Err, S->getRParenLoc()); - if (Err) - return std::move(Err); + return CXXExpansionStmtPattern::CreateIterating( + Importer.getToContext(), ToESD, ToInit, ToExpansionVar, ToRange, + ToBegin, ToEnd, ToLParenLoc, ToColonLoc, ToRParenLoc); + } - return new (Importer.getToContext()) CXXDependentExpansionStmtPattern( - ToESD, ToInit, ToExpansionVar, ToExpansionInitializer, ToLParenLoc, - ToColonLoc, ToRParenLoc); + case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring: { + auto ToDecompositionDeclStmt = + importChecked(Err, S->getDecompositionDeclStmt()); + if (Err) + return std::move(Err); + + return CXXExpansionStmtPattern::CreateDestructuring( + Importer.getToContext(), ToESD, ToInit, ToExpansionVar, + ToDecompositionDeclStmt, ToLParenLoc, ToColonLoc, ToRParenLoc); + } + + case CXXExpansionStmtPattern::ExpansionStmtKind::Dependent: { + auto ToExpansionInitializer = + importChecked(Err, S->getExpansionInitializer()); + if (Err) + return std::move(Err); + return CXXExpansionStmtPattern::CreateDependent( + Importer.getToContext(), ToESD, ToInit, ToExpansionVar, + ToExpansionInitializer, ToLParenLoc, ToColonLoc, ToRParenLoc); + } + } + + llvm_unreachable("invalid pattern kind"); } + ExpectedStmt ASTNodeImporter::VisitCXXExpansionStmtInstantiation( CXXExpansionStmtInstantiation *S) { Error Err = Error::success(); diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp index da4e3be6eaa2f..6f7cddd490e8d 100644 --- a/clang/lib/AST/StmtCXX.cpp +++ b/clang/lib/AST/StmtCXX.cpp @@ -127,88 +127,115 @@ CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args) llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data())); } -CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell Empty) - : Stmt(SC, Empty) {} +CXXExpansionStmtPattern::CXXExpansionStmtPattern(ExpansionStmtKind PatternKind, + EmptyShell Empty) + : Stmt(CXXExpansionStmtPatternClass, Empty), PatternKind(PatternKind) {} CXXExpansionStmtPattern::CXXExpansionStmtPattern( - StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, - - SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc) - : Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc), - RParenLoc(RParenLoc) { + ExpansionStmtKind PatternKind, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc) + : Stmt(CXXExpansionStmtPatternClass), PatternKind(PatternKind), + LParenLoc(LParenLoc), ColonLoc(ColonLoc), RParenLoc(RParenLoc), + ParentDecl(ESD) { setInit(Init); setExpansionVarStmt(ExpansionVar); setBody(nullptr); } -CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern( - EmptyShell Empty) - : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty) {} +template +CXXExpansionStmtPattern *CXXExpansionStmtPattern::AllocateAndConstruct( + ASTContext &Context, ExpansionStmtKind Kind, Args &&...Arguments) { + std::size_t Size = totalSizeToAlloc(getNumSubStmts(Kind)); + void *Mem = Context.Allocate(Size, alignof(CXXExpansionStmtPattern)); + return new (Mem) + CXXExpansionStmtPattern(Kind, std::forward(Arguments)...); +} -CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern( - CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, - SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation RParenLoc) - : CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD, - Init, ExpansionVar, LParenLoc, ColonLoc, - RParenLoc) {} +CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateDependent( + ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, Expr *ExpansionInitializer, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc) { + CXXExpansionStmtPattern *Pattern = + AllocateAndConstruct(Context, ExpansionStmtKind::Dependent, ESD, Init, + ExpansionVar, LParenLoc, ColonLoc, RParenLoc); + Pattern->setExpansionInitializer(ExpansionInitializer); + return Pattern; +} -SourceLocation CXXExpansionStmtPattern::getBeginLoc() const { - return ParentDecl->getLocation(); +CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateDestructuring( + ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, Stmt *DecompositionDeclStmt, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc) { + CXXExpansionStmtPattern *Pattern = + AllocateAndConstruct(Context, ExpansionStmtKind::Destructuring, ESD, Init, + ExpansionVar, LParenLoc, ColonLoc, RParenLoc); + Pattern->setDecompositionDeclStmt(DecompositionDeclStmt); + return Pattern; } -VarDecl *CXXExpansionStmtPattern::getExpansionVariable() { - Decl *LV = cast(getExpansionVarStmt())->getSingleDecl(); - assert(LV && "No expansion variable in CXXExpansionStmtPattern"); - return cast(LV); +CXXExpansionStmtPattern * +CXXExpansionStmtPattern::CreateEmpty(ASTContext &Context, EmptyShell Empty, + ExpansionStmtKind Kind) { + return AllocateAndConstruct(Context, Kind, Empty); } -CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern( - EmptyShell Empty) - : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, Empty) {} - -CXXIteratingExpansionStmtPattern::CXXIteratingExpansionStmtPattern( - CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, - DeclStmt *Range, DeclStmt *Begin, DeclStmt *End, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation RParenLoc) - : CXXExpansionStmtPattern(CXXIteratingExpansionStmtPatternClass, ESD, Init, - ExpansionVar, LParenLoc, ColonLoc, RParenLoc) { - setRangeVarStmt(Range); - setBeginVarStmt(Begin); - setEndVarStmt(End); +CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateEnumerating( + ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc) { + return AllocateAndConstruct(Context, ExpansionStmtKind::Enumerating, ESD, + Init, ExpansionVar, LParenLoc, ColonLoc, + RParenLoc); } -CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern( - EmptyShell Empty) - : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass, - Empty) {} +CXXExpansionStmtPattern *CXXExpansionStmtPattern::CreateIterating( + ASTContext &Context, CXXExpansionStmtDecl *ESD, Stmt *Init, + DeclStmt *ExpansionVar, DeclStmt *Range, DeclStmt *Begin, DeclStmt *End, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation RParenLoc) { + CXXExpansionStmtPattern *Pattern = + AllocateAndConstruct(Context, ExpansionStmtKind::Iterating, ESD, Init, + ExpansionVar, LParenLoc, ColonLoc, RParenLoc); + Pattern->setRangeVarStmt(Range); + Pattern->setBeginVarStmt(Begin); + Pattern->setEndVarStmt(End); + return Pattern; +} -CXXDestructuringExpansionStmtPattern::CXXDestructuringExpansionStmtPattern( - CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, - Stmt *DecompositionDeclStmt, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation RParenLoc) - : CXXExpansionStmtPattern(CXXDestructuringExpansionStmtPatternClass, ESD, - Init, ExpansionVar, LParenLoc, ColonLoc, - RParenLoc) { - setDecompositionDeclStmt(DecompositionDeclStmt); +SourceLocation CXXExpansionStmtPattern::getBeginLoc() const { + return ParentDecl->getLocation(); } DecompositionDecl * -CXXDestructuringExpansionStmtPattern::getDecompositionDecl() { +CXXExpansionStmtPattern::getDecompositionDecl() { + assert(isDestructuring()); return cast( cast(getDecompositionDeclStmt())->getSingleDecl()); } -CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern( - EmptyShell Empty) - : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, Empty) {} - -CXXDependentExpansionStmtPattern::CXXDependentExpansionStmtPattern( - CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar, - Expr *ExpansionInitializer, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation RParenLoc) - : CXXExpansionStmtPattern(CXXDependentExpansionStmtPatternClass, ESD, Init, - ExpansionVar, LParenLoc, ColonLoc, RParenLoc) { - setExpansionInitializer(ExpansionInitializer); +VarDecl *CXXExpansionStmtPattern::getExpansionVariable() { + Decl *LV = cast(getExpansionVarStmt())->getSingleDecl(); + assert(LV && "No expansion variable in CXXExpansionStmtPattern"); + return cast(LV); +} + +unsigned +CXXExpansionStmtPattern::getNumSubStmts(ExpansionStmtKind PatternKind) { + switch (PatternKind) { + case ExpansionStmtKind::Enumerating: + return COUNT_Enumerating; + case ExpansionStmtKind::Iterating: + return COUNT_Iterating; + case ExpansionStmtKind::Destructuring: + return COUNT_Destructuring; + case ExpansionStmtKind::Dependent: + return COUNT_Dependent; + } + + llvm_unreachable("invalid pattern kind"); } CXXExpansionStmtInstantiation::CXXExpansionStmtInstantiation( diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 165bbd046f5f4..d2f8d62582152 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -160,8 +160,6 @@ namespace { } void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); - void VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node, - Expr *Initializer = nullptr); #define ABSTRACT_STMT(CLASS) #define STMT(CLASS, PARENT) \ @@ -450,8 +448,7 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) { PrintControlledStmt(Node->getBody()); } -void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node, - Expr *Initializer) { +void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node) { OS << "template for ("; if (Node->getInit()) PrintInitStmt(Node->getInit(), 14); @@ -459,30 +456,16 @@ void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node, SubPolicy.SuppressInitializers = true; Node->getExpansionVariable()->print(OS, SubPolicy, IndentLevel); OS << " : "; - PrintExpr(Initializer ? Initializer - : Node->getExpansionVariable()->getInit()); - OS << ")"; - PrintControlledStmt(Node->getBody()); -} -void StmtPrinter::VisitCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *Node) { - VisitCXXExpansionStmtPattern(Node); -} - -void StmtPrinter::VisitCXXIteratingExpansionStmtPattern( - CXXIteratingExpansionStmtPattern *Node) { - VisitCXXExpansionStmtPattern(Node, Node->getRangeVar()->getInit()); -} - -void StmtPrinter::VisitCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *Node) { - VisitCXXExpansionStmtPattern(Node); -} + if (Node->isIterating()) + PrintExpr(Node->getRangeVar()->getInit()); + else if (Node->isDependent()) + PrintExpr(Node->getExpansionInitializer()); + else + PrintExpr(Node->getExpansionVariable()->getInit()); -void StmtPrinter::VisitCXXDependentExpansionStmtPattern( - CXXDependentExpansionStmtPattern *Node) { - VisitCXXExpansionStmtPattern(Node, Node->getExpansionInitializer()); + OS << ")"; + PrintControlledStmt(Node->getBody()); } void StmtPrinter::VisitCXXExpansionStmtInstantiation( diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 08759bbaa2ed3..767479be115f5 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -369,26 +369,6 @@ void StmtProfiler::VisitCXXExpansionStmtPattern( VisitStmt(S); } -void StmtProfiler::VisitCXXEnumeratingExpansionStmtPattern( - const CXXEnumeratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); -} - -void StmtProfiler::VisitCXXIteratingExpansionStmtPattern( - const CXXIteratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); -} - -void StmtProfiler::VisitCXXDestructuringExpansionStmtPattern( - const CXXDestructuringExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); -} - -void StmtProfiler::VisitCXXDependentExpansionStmtPattern( - const CXXDependentExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); -} - void StmtProfiler::VisitCXXExpansionStmtInstantiation( const CXXExpansionStmtInstantiation *S) { VisitStmt(S); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index e20cb63ee54b8..453bcaa5de40f 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1499,6 +1499,24 @@ void clang::TextNodeDumper::VisitCoreturnStmt(const CoreturnStmt *Node) { OS << " implicit"; } +void TextNodeDumper::VisitCXXExpansionStmtPattern( + const CXXExpansionStmtPattern *Node) { + switch (Node->getKind()) { + case CXXExpansionStmtPattern::ExpansionStmtKind::Enumerating: + OS << " enumerating"; + break; + case CXXExpansionStmtPattern::ExpansionStmtKind::Iterating: + OS << " iterating"; + break; + case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring: + OS << " destructuring"; + break; + case CXXExpansionStmtPattern::ExpansionStmtKind::Dependent: + OS << " dependent"; + break; + } +} + void TextNodeDumper::VisitCXXExpansionStmtInstantiation( const CXXExpansionStmtInstantiation *Node) { if (Node->shouldApplyLifetimeExtensionToSharedStmts()) diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 40c92035008ae..6f02ccd99c0e4 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -204,10 +204,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::CXXForRangeStmtClass: EmitCXXForRangeStmt(cast(*S), Attrs); break; - case Stmt::CXXEnumeratingExpansionStmtPatternClass: - case Stmt::CXXIteratingExpansionStmtPatternClass: - case Stmt::CXXDestructuringExpansionStmtPatternClass: - case Stmt::CXXDependentExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtPatternClass: llvm_unreachable("unexpanded expansion statements should not be emitted"); case Stmt::CXXExpansionStmtInstantiationClass: llvm_unreachable("Todo"); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 5839785dbaab2..9c072fa07d1c4 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1350,7 +1350,6 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXFoldExprClass: case Expr::RecoveryExprClass: - case Expr::CXXDependentExpansionStmtPatternClass: return CT_Dependent; case Expr::AsTypeExprClass: @@ -1541,12 +1540,15 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::SEHTryStmtClass: case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: - case Stmt::CXXEnumeratingExpansionStmtPatternClass: - case Stmt::CXXIteratingExpansionStmtPatternClass: - case Stmt::CXXDestructuringExpansionStmtPatternClass: case Stmt::CXXExpansionStmtInstantiationClass: return canSubStmtsThrow(*this, S); + case Stmt::CXXExpansionStmtPatternClass: + if (auto *Pattern = cast(S); + Pattern->isDependent()) + return CT_Dependent; + return canSubStmtsThrow(*this, S); + case Stmt::DeclStmtClass: { CanThrowResult CT = CT_Cannot; for (const Decl *D : cast(S)->decls()) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index f3ea8c99666eb..9b91f56fa3ff6 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1732,13 +1732,13 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { void ASTStmtReader::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) { VisitStmt(S); + Record.skipInts(1); // Skip kind. S->LParenLoc = readSourceLocation(); S->ColonLoc = readSourceLocation(); S->RParenLoc = readSourceLocation(); S->ParentDecl = cast(Record.readDeclRef()); - S->setInit(Record.readSubStmt()); - S->setExpansionVarStmt(Record.readSubStmt()); - S->setBody(Record.readSubStmt()); + for (Stmt *&SubStmt : S->children()) + SubStmt = Record.readSubStmt(); } void ASTStmtReader::VisitCXXExpansionStmtInstantiation( @@ -1752,31 +1752,6 @@ void ASTStmtReader::VisitCXXExpansionStmtInstantiation( S->setShouldApplyLifetimeExtensionToSharedStmts(Record.readBool()); } -void ASTStmtReader::VisitCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); -} - -void ASTStmtReader::VisitCXXIteratingExpansionStmtPattern( - CXXIteratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - S->setRangeVarStmt(cast(Record.readSubStmt())); - S->setBeginVarStmt(cast(Record.readSubStmt())); - S->setEndVarStmt(cast(Record.readSubStmt())); -} - -void ASTStmtReader::VisitCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - S->setDecompositionDeclStmt(Record.readSubStmt()); -} - -void ASTStmtReader::VisitCXXDependentExpansionStmtPattern( - CXXDependentExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - S->setExpansionInitializer(Record.readSubExpr()); -} - void ASTStmtReader::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *E) { VisitExpr(E); @@ -3627,20 +3602,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { /*numHandlers=*/Record[ASTStmtReader::NumStmtFields]); break; - case STMT_CXX_ENUMERATING_EXPANSION: - S = new (Context) CXXEnumeratingExpansionStmtPattern(Empty); - break; - - case STMT_CXX_ITERATING_EXPANSION: - S = new (Context) CXXIteratingExpansionStmtPattern(Empty); - break; - - case STMT_CXX_DESTRUCTURING_EXPANSION: - S = new (Context) CXXDestructuringExpansionStmtPattern(Empty); - break; - - case STMT_CXX_DEPENDENT_EXPANSION: - S = new (Context) CXXDependentExpansionStmtPattern(Empty); + case STMT_CXX_EXPANSION_PATTERN: + S = CXXExpansionStmtPattern::CreateEmpty( + Context, Empty, + static_cast( + Record[ASTStmtReader::NumStmtFields])); break; case STMT_CXX_EXPANSION_INSTANTIATION: diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 8319a59bc951f..8b36dea086427 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1706,13 +1706,14 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) { VisitStmt(S); + Record.push_back(static_cast(S->getKind())); Record.AddSourceLocation(S->getLParenLoc()); Record.AddSourceLocation(S->getColonLoc()); Record.AddSourceLocation(S->getRParenLoc()); Record.AddDeclRef(S->getDecl()); - Record.AddStmt(S->getInit()); - Record.AddStmt(S->getExpansionVarStmt()); - Record.AddStmt(S->getBody()); + for (Stmt* SubStmt : S->children()) + Record.AddStmt(SubStmt); + Code = serialization::STMT_CXX_EXPANSION_PATTERN; } void ASTStmtWriter::VisitCXXExpansionStmtInstantiation( @@ -1728,35 +1729,6 @@ void ASTStmtWriter::VisitCXXExpansionStmtInstantiation( Code = serialization::STMT_CXX_EXPANSION_INSTANTIATION; } -void ASTStmtWriter::VisitCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - Code = serialization::STMT_CXX_ENUMERATING_EXPANSION; -} - -void ASTStmtWriter::VisitCXXIteratingExpansionStmtPattern( - CXXIteratingExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - Record.AddStmt(S->getRangeVarStmt()); - Record.AddStmt(S->getBeginVarStmt()); - Record.AddStmt(S->getEndVarStmt()); - Code = serialization::STMT_CXX_ITERATING_EXPANSION; -} - -void ASTStmtWriter::VisitCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - Record.AddStmt(S->getDecompositionDeclStmt()); - Code = serialization::STMT_CXX_DESTRUCTURING_EXPANSION; -} - -void ASTStmtWriter::VisitCXXDependentExpansionStmtPattern( - CXXDependentExpansionStmtPattern *S) { - VisitCXXExpansionStmtPattern(S); - Record.AddStmt(S->getExpansionInitializer()); - Code = serialization::STMT_CXX_DEPENDENT_EXPANSION; -} - void ASTStmtWriter::VisitCXXExpansionInitListSelectExpr( CXXExpansionInitListSelectExpr *E) { VisitExpr(E); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 53f85c22dd020..3e6f3a7b9090e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1752,10 +1752,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SEHExceptStmtClass: case Stmt::SEHLeaveStmtClass: case Stmt::SEHFinallyStmtClass: - case Stmt::CXXEnumeratingExpansionStmtPatternClass: - case Stmt::CXXIteratingExpansionStmtPatternClass: - case Stmt::CXXDestructuringExpansionStmtPatternClass: - case Stmt::CXXDependentExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtPatternClass: case Stmt::CXXExpansionStmtInstantiationClass: case Stmt::CXXExpansionInitListSelectExprClass: case Stmt::CXXDestructuringExpansionSelectExprClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index ecd1f86c3ddb6..16e02f5a79e01 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -290,10 +290,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::CoroutineBodyStmtClass: case Stmt::CoreturnStmtClass: - case Stmt::CXXEnumeratingExpansionStmtPatternClass: - case Stmt::CXXIteratingExpansionStmtPatternClass: - case Stmt::CXXDestructuringExpansionStmtPatternClass: - case Stmt::CXXDependentExpansionStmtPatternClass: + case Stmt::CXXExpansionStmtPatternClass: case Stmt::CXXExpansionStmtInstantiationClass: K = CXCursor_UnexposedStmt; break; From 66a2c59b9b4c4b94bfa31eba2b3bbd603c053bd0 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 3 Dec 2025 20:16:07 +0100 Subject: [PATCH 8/9] Stub out TreeTransform properly --- clang/lib/Sema/TreeTransform.h | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index f181d0abb5dfd..39afc5692b42f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9293,37 +9293,8 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { } template -StmtResult TreeTransform::TransformCXXEnumeratingExpansionStmtPattern( - CXXEnumeratingExpansionStmtPattern *S) { - llvm_unreachable("TOOD"); -} - -template -StmtResult TreeTransform::TransformCXXIteratingExpansionStmtPattern( - CXXIteratingExpansionStmtPattern *S) { - llvm_unreachable("TOOD"); -} - -template -StmtResult TreeTransform::TransformCXXDependentExpansionStmtPattern( - CXXDependentExpansionStmtPattern *S) { - llvm_unreachable("TOOD"); -} - -template -StmtResult -TreeTransform::TransformCXXDestructuringExpansionStmtPattern( - CXXDestructuringExpansionStmtPattern *) { - // The only time we instantiate an expansion statement is if its expansion - // size is dependent (otherwise, we only instantiate the expansions and - // leave the underlying CXXExpansionStmtPattern as-is). Since destructuring - // expansion statements never have a dependent size, we should never get here. - llvm_unreachable("Should never be instantiated"); -} - -template -ExprResult TreeTransform::TransformCXXExpansionInitListExpr( - CXXExpansionInitListExpr *E) { +StmtResult TreeTransform::TransformCXXExpansionStmtPattern( + CXXExpansionStmtPattern *S) { llvm_unreachable("TOOD"); } From 8432c3da1bfc8e38d02065f64497ac3a2991be39 Mon Sep 17 00:00:00 2001 From: Sirraide Date: Wed, 3 Dec 2025 22:10:24 +0100 Subject: [PATCH 9/9] Only use a single CXXExpansionSelectExpr --- clang/include/clang/AST/DeclTemplate.h | 19 ++---- clang/include/clang/AST/ExprCXX.h | 65 ++----------------- clang/include/clang/AST/RecursiveASTVisitor.h | 3 +- clang/include/clang/AST/StmtCXX.h | 11 ++-- clang/include/clang/AST/TextNodeDumper.h | 2 - clang/include/clang/Basic/StmtNodes.td | 3 +- .../include/clang/Serialization/ASTBitCodes.h | 23 ++++--- clang/lib/AST/ASTImporter.cpp | 23 ++----- clang/lib/AST/Expr.cpp | 3 +- clang/lib/AST/ExprCXX.cpp | 20 ++---- clang/lib/AST/ExprClassification.cpp | 3 +- clang/lib/AST/ExprConstant.cpp | 3 +- clang/lib/AST/ItaniumMangle.cpp | 3 +- clang/lib/AST/StmtPrinter.cpp | 11 ++-- clang/lib/AST/StmtProfile.cpp | 10 +-- clang/lib/AST/TextNodeDumper.cpp | 5 -- clang/lib/Sema/SemaExceptionSpec.cpp | 3 +- clang/lib/Sema/TreeTransform.h | 10 +-- clang/lib/Serialization/ASTReaderStmt.cpp | 19 ++---- clang/lib/Serialization/ASTWriterStmt.cpp | 14 +--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 +- clang/tools/libclang/CXCursor.cpp | 3 +- 22 files changed, 59 insertions(+), 200 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index d0fbbabe94aa2..d30c197853ce5 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3375,16 +3375,8 @@ class TemplateParamObjectDecl : public ValueDecl, /// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for /// codegen and constant evaluation. /// -/// There are three kinds of expansion statements; they correspond to three -/// derived classes of 'CXXExpansionStmtPattern'. There is also a fourth derived -/// class that is used if we don't know what kind of expansion statement we're -/// dealing with (because the thing we're expanding is dependent). See the -/// comment on those classes for more information about how they work: -/// -/// 1. CXXEnumeratingExpansionStmtPattern -/// 2. CXXIteratingExpansionStmtPattern -/// 3. CXXDestructuringExpansionStmtPattern -/// 4. CXXDependentExpansionStmtPattern +/// There are different kinds of expansion statements; see the comment on +/// 'CXXExpansionStmtPattern' for more information. /// /// As an example, if the user writes the following expansion statement: /// \verbatim @@ -3394,10 +3386,9 @@ class TemplateParamObjectDecl : public ValueDecl, /// } /// \endverbatim /// -/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is a -/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things, -/// the declaration of the variable 'x' as well as the expansion-initializer -/// 'a'. +/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' +/// stores, amongst other things, the declaration of the variable 'x' as well +/// as the expansion-initializer 'a'. /// /// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that /// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e. diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 6bf2d52399285..083576c5379bf 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5499,20 +5499,19 @@ class BuiltinBitCastExpr final } }; -/// Helper that selects an expression from an expansion init list depending +/// Helper that selects an expression from an InitListExpr depending /// on the current expansion index. /// -/// \see CXXEnumeratingExpansionStmtPattern -class CXXExpansionInitListSelectExpr : public Expr { +/// \see CXXExpansionStmtPattern +class CXXExpansionSelectExpr : public Expr { friend class ASTStmtReader; enum SubExpr { RANGE, INDEX, COUNT }; Expr *SubExprs[COUNT]; public: - CXXExpansionInitListSelectExpr(EmptyShell Empty); - CXXExpansionInitListSelectExpr(const ASTContext &C, - InitListExpr *Range, Expr *Idx); + CXXExpansionSelectExpr(EmptyShell Empty); + CXXExpansionSelectExpr(const ASTContext &C, InitListExpr *Range, Expr *Idx); InitListExpr *getRangeExpr() { return cast(SubExprs[RANGE]); @@ -5543,61 +5542,9 @@ class CXXExpansionInitListSelectExpr : public Expr { } static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXExpansionInitListSelectExprClass; + return T->getStmtClass() == CXXExpansionSelectExprClass; } }; - -/// This class serves the same purpose as CXXExpansionInitListSelectExpr, but -/// for destructuring expansion statements; that is, instead of selecting among -/// a list of expressions, it selects from a list of 'BindingDecl's. -/// -/// \see CXXEnumeratingExpansionStmtPattern -/// \see CXXDestructuringExpansionStmtPattern -class CXXDestructuringExpansionSelectExpr : public Expr { - friend class ASTStmtReader; - - DecompositionDecl *Decomposition; - Expr *Index; - -public: - CXXDestructuringExpansionSelectExpr(EmptyShell Empty); - CXXDestructuringExpansionSelectExpr(const ASTContext &C, - DecompositionDecl *Decomposition, - Expr *Index); - - DecompositionDecl *getDecompositionDecl() { - return cast(Decomposition); - } - - const DecompositionDecl *getDecompositionDecl() const { - return cast(Decomposition); - } - - void setDecompositionDecl(DecompositionDecl *E) { Decomposition = E; } - - Expr *getIndexExpr() { return Index; } - const Expr *getIndexExpr() const { return Index; } - void setIndexExpr(Expr *E) { Index = E; } - - SourceLocation getBeginLoc() const { return Decomposition->getBeginLoc(); } - SourceLocation getEndLoc() const { return Decomposition->getEndLoc(); } - - child_range children() { - return child_range(reinterpret_cast(&Index), - reinterpret_cast(&Index + 1)); - } - - const_child_range children() const { - return const_child_range( - reinterpret_cast(const_cast(&Index)), - reinterpret_cast(const_cast(&Index + 1))); - } - - static bool classof(const Stmt *T) { - return T->getStmtClass() == CXXDestructuringExpansionSelectExprClass; - } -}; - } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index b145fa9f9cdf0..5502d68f99ad3 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3127,8 +3127,7 @@ DEF_TRAVERSE_STMT(RequiresExpr, { DEF_TRAVERSE_STMT(CXXExpansionStmtPattern, {}) DEF_TRAVERSE_STMT(CXXExpansionStmtInstantiation, {}) -DEF_TRAVERSE_STMT(CXXExpansionInitListSelectExpr, {}) -DEF_TRAVERSE_STMT(CXXDestructuringExpansionSelectExpr, {}) +DEF_TRAVERSE_STMT(CXXExpansionSelectExpr, {}) // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h index fcc30c3b1d421..1caae321df54c 100644 --- a/clang/include/clang/AST/StmtCXX.h +++ b/clang/include/clang/AST/StmtCXX.h @@ -554,14 +554,14 @@ class CoreturnStmt : public Stmt { /// Here, the '{ 1, 2, 3 }' is parsed as an 'InitListExpr'. This node /// handles storing (and pack-expanding) the individual expressions. /// -/// Sema then wraps this with a 'CXXExpansionInitListSelectExpr', which also +/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also /// contains a reference to an integral NTTP that is used as the expansion /// index; this index is either dependent (if the expansion-size is dependent), /// or set to a value of I in the I-th expansion during the expansion process. /// -/// The actual expansion is done by 'BuildCXXExpansionInitListSelectExpr()': for +/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for /// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and -/// BuildCXXExpansionInitListSelectExpr(), when called via TreeTransform, +/// BuildCXXExpansionSelectExpr(), when called via TreeTransform, /// 'instantiates' the expression '{ a, b, c }' to just 'b'. /// /// 2. Represents an unexpanded iterating expansion statement. @@ -601,9 +601,8 @@ class CoreturnStmt : public Stmt { /// } /// \endverbatim /// -/// Sema wraps the initializer with a CXXDestructuringExpansionSelectExpr, which -/// selects a binding based on the current expansion index; this is analogous to -/// how 'CXXExpansionInitListSelectExpr' is used. +/// Sema wraps the initializer with a CXXExpansionSelectExpr, which selects a +/// binding based on the current expansion index. /// /// 4. Represents an expansion statement whose expansion-initializer is /// type-dependent. diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 24a152cfe1de4..499dc74d51099 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -313,8 +313,6 @@ class TextNodeDumper void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node); - void VisitCXXDestructuringExpansionSelectExpr( - const CXXDestructuringExpansionSelectExpr *Node); void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node); void VisitObjCMessageExpr(const ObjCMessageExpr *Node); diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 1df99734f713f..d51d4c6d23f7d 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -183,8 +183,7 @@ def ConceptSpecializationExpr : StmtNode; def RequiresExpr : StmtNode; // C++26 Expansion statement support expressions -def CXXExpansionInitListSelectExpr : StmtNode; -def CXXDestructuringExpansionSelectExpr : StmtNode; +def CXXExpansionSelectExpr : StmtNode; // Obj-C Expressions. def ObjCStringLiteral : StmtNode; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index e90fc6bdabca7..ba5713d24a048 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1923,18 +1923,17 @@ enum StmtCode { EXPR_TYPE_TRAIT, // TypeTraitExpr EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr - EXPR_PACK_EXPANSION, // PackExpansionExpr - EXPR_PACK_INDEXING, // PackIndexingExpr - EXPR_SIZEOF_PACK, // SizeOfPackExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr - EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr - EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr - EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr - EXPR_CXX_FOLD, // CXXFoldExpr - EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr - EXPR_REQUIRES, // RequiresExpr - EXPR_CXX_EXPANSION_INIT_LIST_SELECT, // CXXExpansionInitListSelectExpr - EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT, // CXXDestructuringExpansionSelectExpr + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_PACK_INDEXING, // PackIndexingExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr + EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CONCEPT_SPECIALIZATION, // ConceptSpecializationExpr + EXPR_REQUIRES, // RequiresExpr + EXPR_CXX_EXPANSION_SELECT, // CXXExpansionSelectExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 953646ef4aa08..148a5b514b8c8 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -704,10 +704,7 @@ namespace clang { VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E); ExpectedStmt VisitCXXParenListInitExpr(CXXParenListInitExpr *E); - ExpectedStmt - VisitCXXExpansionInitListSelectExpr(CXXExpansionInitListSelectExpr *E); - ExpectedStmt VisitCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *E); + ExpectedStmt VisitCXXExpansionSelectExpr(CXXExpansionSelectExpr *E); // Helper for chaining together multiple imports. If an error is detected, // subsequent imports will return default constructed nodes, so that failure @@ -9457,8 +9454,8 @@ ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { ToInitLoc, ToBeginLoc, ToEndLoc); } -ExpectedStmt ASTNodeImporter::VisitCXXExpansionInitListSelectExpr( - CXXExpansionInitListSelectExpr *E) { +ExpectedStmt ASTNodeImporter::VisitCXXExpansionSelectExpr( + CXXExpansionSelectExpr *E) { Error Err = Error::success(); auto ToRange = importChecked(Err, E->getRangeExpr()); auto ToIndex = importChecked(Err, E->getIndexExpr()); @@ -9466,19 +9463,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXExpansionInitListSelectExpr( return std::move(Err); return new (Importer.getToContext()) - CXXExpansionInitListSelectExpr(Importer.getToContext(), ToRange, ToIndex); -} - -ExpectedStmt ASTNodeImporter::VisitCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *E) { - Error Err = Error::success(); - auto ToDecompositionDecl = importChecked(Err, E->getDecompositionDecl()); - auto ToIndex = importChecked(Err, E->getIndexExpr()); - if (Err) - return std::move(Err); - - return new (Importer.getToContext()) CXXDestructuringExpansionSelectExpr( - Importer.getToContext(), ToDecompositionDecl, ToIndex); + CXXExpansionSelectExpr(Importer.getToContext(), ToRange, ToIndex); } Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index af2d264623f89..2911b0da96bbf 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3688,8 +3688,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case FunctionParmPackExprClass: case RecoveryExprClass: case CXXFoldExprClass: - case CXXExpansionInitListSelectExprClass: - case CXXDestructuringExpansionSelectExprClass: + case CXXExpansionSelectExprClass: // Make a conservative assumption for dependent nodes. return IncludePossibleEffects; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 8975d9af87ce1..8898547e23c0f 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -2021,26 +2021,14 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee, setDependence(computeDependence(this)); } -CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr(EmptyShell Empty) - : Expr(CXXExpansionInitListSelectExprClass, Empty) {} +CXXExpansionSelectExpr::CXXExpansionSelectExpr(EmptyShell Empty) + : Expr(CXXExpansionSelectExprClass, Empty) {} -CXXExpansionInitListSelectExpr::CXXExpansionInitListSelectExpr( +CXXExpansionSelectExpr::CXXExpansionSelectExpr( const ASTContext &C, InitListExpr *Range, Expr *Idx) - : Expr(CXXExpansionInitListSelectExprClass, C.DependentTy, VK_PRValue, + : Expr(CXXExpansionSelectExprClass, C.DependentTy, VK_PRValue, OK_Ordinary) { setDependence(ExprDependence::TypeValueInstantiation); SubExprs[RANGE] = Range; SubExprs[INDEX] = Idx; } - -CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr( - EmptyShell Empty) - : Expr(CXXDestructuringExpansionSelectExprClass, Empty) {} - -CXXDestructuringExpansionSelectExpr::CXXDestructuringExpansionSelectExpr( - const ASTContext &C, DecompositionDecl *Decomposition, Expr *Index) - : Expr(CXXDestructuringExpansionSelectExprClass, C.DependentTy, VK_PRValue, - OK_Ordinary), - Decomposition(Decomposition), Index(Index) { - setDependence(ExprDependence::TypeValueInstantiation); -} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 1b139ac0954b8..3a1ed33e5e5f8 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -216,8 +216,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: case Expr::RequiresExprClass: - case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXDestructuringExpansionSelectExprClass: + case Expr::CXXExpansionSelectExprClass: return Cl::CL_PRValue; case Expr::EmbedExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0bd56bb0a76e2..7ab4f3ce9ffaf 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -20276,8 +20276,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::SYCLUniqueStableNameExprClass: case Expr::CXXParenListInitExprClass: case Expr::HLSLOutArgExprClass: - case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXDestructuringExpansionSelectExprClass: + case Expr::CXXExpansionSelectExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); case Expr::InitListExprClass: { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index db8cdc0a33d04..b3866c0de11f7 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4945,8 +4945,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXParenListInitExprClass: case Expr::PackIndexingExprClass: - case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXDestructuringExpansionSelectExprClass: + case Expr::CXXExpansionSelectExprClass: llvm_unreachable("unexpected statement kind"); case Expr::ConstantExprClass: diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index d2f8d62582152..6032e40ec5ca5 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -461,6 +461,8 @@ void StmtPrinter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *Node) { PrintExpr(Node->getRangeVar()->getInit()); else if (Node->isDependent()) PrintExpr(Node->getExpansionInitializer()); + else if (Node->isDestructuring()) + PrintExpr(Node->getDecompositionDecl()->getInit()); else PrintExpr(Node->getExpansionVariable()->getInit()); @@ -473,16 +475,11 @@ void StmtPrinter::VisitCXXExpansionStmtInstantiation( llvm_unreachable("should never be printed"); } -void StmtPrinter::VisitCXXExpansionInitListSelectExpr( - CXXExpansionInitListSelectExpr *Node) { +void StmtPrinter::VisitCXXExpansionSelectExpr( + CXXExpansionSelectExpr *Node) { PrintExpr(Node->getRangeExpr()); } -void StmtPrinter::VisitCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *Node) { - PrintExpr(Node->getDecompositionDecl()->getInit()); -} - void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) { Indent(); if (Node->isIfExists()) diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 767479be115f5..3500d39e0c703 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2411,17 +2411,11 @@ void StmtProfiler::VisitSourceLocExpr(const SourceLocExpr *E) { void StmtProfiler::VisitEmbedExpr(const EmbedExpr *E) { VisitExpr(E); } -void StmtProfiler::VisitCXXExpansionInitListSelectExpr( - const CXXExpansionInitListSelectExpr *E) { +void StmtProfiler::VisitCXXExpansionSelectExpr( + const CXXExpansionSelectExpr *E) { VisitExpr(E); } -void StmtProfiler::VisitCXXDestructuringExpansionSelectExpr( - const CXXDestructuringExpansionSelectExpr *E) { - VisitExpr(E); - VisitDecl(E->getDecompositionDecl()); -} - void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) { VisitExpr(E); } void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 453bcaa5de40f..a88d152c4c507 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1854,11 +1854,6 @@ void TextNodeDumper::VisitCXXDependentScopeMemberExpr( OS << " " << (Node->isArrow() ? "->" : ".") << Node->getMember(); } -void TextNodeDumper::VisitCXXDestructuringExpansionSelectExpr( - const CXXDestructuringExpansionSelectExpr *Node) { - dumpDeclRef(Node->getDecompositionDecl()); -} - void TextNodeDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) { OS << " selector="; Node->getSelector().print(OS); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 9c072fa07d1c4..53603b76011ae 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1288,8 +1288,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: case Expr::CXXParenListInitExprClass: - case Expr::CXXExpansionInitListSelectExprClass: - case Expr::CXXDestructuringExpansionSelectExprClass: + case Expr::CXXExpansionSelectExprClass: return canSubStmtsThrow(*this, S); case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 39afc5692b42f..df25b1701207f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9305,14 +9305,8 @@ StmtResult TreeTransform::TransformCXXExpansionStmtInstantiation( } template -ExprResult TreeTransform::TransformCXXExpansionInitListSelectExpr( - CXXExpansionInitListSelectExpr *E) { - llvm_unreachable("TOOD"); -} - -template -ExprResult TreeTransform::TransformCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *E) { +ExprResult TreeTransform::TransformCXXExpansionSelectExpr( + CXXExpansionSelectExpr *E) { llvm_unreachable("TOOD"); } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 9b91f56fa3ff6..5c65be8c594ef 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1752,20 +1752,13 @@ void ASTStmtReader::VisitCXXExpansionStmtInstantiation( S->setShouldApplyLifetimeExtensionToSharedStmts(Record.readBool()); } -void ASTStmtReader::VisitCXXExpansionInitListSelectExpr( - CXXExpansionInitListSelectExpr *E) { +void ASTStmtReader::VisitCXXExpansionSelectExpr( + CXXExpansionSelectExpr *E) { VisitExpr(E); E->setRangeExpr(cast(Record.readSubExpr())); E->setIndexExpr(Record.readSubExpr()); } -void ASTStmtReader::VisitCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *E) { - VisitExpr(E); - E->setDecompositionDecl(cast(Record.readDeclRef())); - E->setIndexExpr(Record.readSubExpr()); -} - void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { VisitStmt(S); S->KeywordLoc = readSourceLocation(); @@ -4493,12 +4486,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } - case EXPR_CXX_EXPANSION_INIT_LIST_SELECT: - S = new (Context) CXXExpansionInitListSelectExpr(Empty); - break; - - case EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT: - S = new (Context) CXXDestructuringExpansionSelectExpr(Empty); + case EXPR_CXX_EXPANSION_SELECT: + S = new (Context) CXXExpansionSelectExpr(Empty); break; case STMT_OPENACC_COMPUTE_CONSTRUCT: { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 8b36dea086427..2b223d1f15c53 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1729,20 +1729,12 @@ void ASTStmtWriter::VisitCXXExpansionStmtInstantiation( Code = serialization::STMT_CXX_EXPANSION_INSTANTIATION; } -void ASTStmtWriter::VisitCXXExpansionInitListSelectExpr( - CXXExpansionInitListSelectExpr *E) { +void ASTStmtWriter::VisitCXXExpansionSelectExpr( + CXXExpansionSelectExpr *E) { VisitExpr(E); Record.AddStmt(E->getRangeExpr()); Record.AddStmt(E->getIndexExpr()); - Code = serialization::EXPR_CXX_EXPANSION_INIT_LIST_SELECT; -} - -void ASTStmtWriter::VisitCXXDestructuringExpansionSelectExpr( - CXXDestructuringExpansionSelectExpr *E) { - VisitExpr(E); - Record.AddDeclRef(E->getDecompositionDecl()); - Record.AddStmt(E->getIndexExpr()); - Code = serialization::EXPR_CXX_DESTRUCTURING_EXPANSION_SELECT; + Code = serialization::EXPR_CXX_EXPANSION_SELECT; } void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 3e6f3a7b9090e..f7cf8c2b0b777 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1754,8 +1754,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SEHFinallyStmtClass: case Stmt::CXXExpansionStmtPatternClass: case Stmt::CXXExpansionStmtInstantiationClass: - case Stmt::CXXExpansionInitListSelectExprClass: - case Stmt::CXXDestructuringExpansionSelectExprClass: + case Stmt::CXXExpansionSelectExprClass: case Stmt::OMPCanonicalLoopClass: case Stmt::OMPParallelDirectiveClass: case Stmt::OMPSimdDirectiveClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 16e02f5a79e01..264a79f5d3a48 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -340,8 +340,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::EmbedExprClass: case Stmt::HLSLOutArgExprClass: case Stmt::OpenACCAsteriskSizeExprClass: - case Stmt::CXXExpansionInitListSelectExprClass: - case Stmt::CXXDestructuringExpansionSelectExprClass: + case Stmt::CXXExpansionSelectExprClass: K = CXCursor_UnexposedExpr; break;