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