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..e15f4dcd3a0bc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1247,14 +1247,16 @@ 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 { 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..d0fbbabe94aa2 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3343,6 +3343,136 @@ 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. +/// +/// 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) { +/// // ... +/// } +/// \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 +/// 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 +/// +/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes +/// as to why this node exist and how it is used. +/// +/// \see CXXExpansionStmtPattern +/// \see CXXExpansionStmtInstantiation +class CXXExpansionStmtDecl : public Decl, public DeclContext { + CXXExpansionStmtPattern *Expansion = nullptr; + NonTypeTemplateParmDecl *IndexNTTP = nullptr; + CXXExpansionStmtInstantiation *Instantiations = nullptr; + + CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, + NonTypeTemplateParmDecl *NTTP); + +public: + friend class ASTDeclReader; + + static CXXExpansionStmtDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, + NonTypeTemplateParmDecl *NTTP); + 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() { return IndexNTTP; } + const NonTypeTemplateParmDecl *getIndexTemplateParm() const { + return IndexNTTP; + } + + 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..a190a178bfce8 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -5499,6 +5499,178 @@ 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. +/// +/// \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..2ecb653126e5f 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,495 @@ 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 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; + } + + 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. 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 +/// +/// 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 +/// +/// 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 { + 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..225c573ecc042 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 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, + ToIndex)) + 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..a770112409486 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1717,6 +1717,9 @@ clang::getReplacedTemplateParameter(Decl *D, unsigned Index) { return getReplacedTemplateParameter( cast(D)->getTemplateSpecializationInfo()->getTemplate(), Index); + case Decl::Kind::CXXExpansionStmt: + assert(Index == 0 && "expansion stmts only have a single template param"); + return {cast(D)->getIndexTemplateParm(), {}}; default: llvm_unreachable("Unhandled templated declaration kind"); } @@ -1788,3 +1791,22 @@ const Decl &clang::adjustDeclToTemplate(const Decl &D) { // FIXME: Adjust alias templates? return D; } + +CXXExpansionStmtDecl::CXXExpansionStmtDecl(DeclContext *DC, SourceLocation Loc, + NonTypeTemplateParmDecl *NTTP) + : Decl(CXXExpansionStmt, DC, Loc), DeclContext(CXXExpansionStmt), + IndexNTTP(NTTP) {} + +CXXExpansionStmtDecl * +CXXExpansionStmtDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, + NonTypeTemplateParmDecl *NTTP) { + return new (C, DC) CXXExpansionStmtDecl(DC, Loc, NTTP); +} +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..f34c11d4eff39 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,154 @@ 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->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) {} + +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/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; 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..e8da8a3060904 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->IndexNTTP = cast(Record.readDeclRef()); +} + 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..c65c9f8fc581f 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.AddDeclRef(D->getIndexTemplateParm()); + 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;