[clang] [Clang] [C++26] Expansion Statements (Part 1) (PR #169680)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 26 09:12:59 PST 2025
https://github.com/Sirraide created https://github.com/llvm/llvm-project/pull/169680
None
>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] [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;
More information about the cfe-commits
mailing list