[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/cor3ntin approved this pull request. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169680
>From 5db185c78b21bd8f3aef98ab2aaaed3db554bf16 Mon Sep 17 00:00:00 2001
From: Sirraide
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/Decl.h| 6 +-
clang/include/clang/AST/DeclBase.h| 13 +
clang/include/clang/AST/DeclTemplate.h| 125
clang/include/clang/AST/ExprCXX.h | 44 ++
clang/include/clang/AST/RecursiveASTVisitor.h | 12 +
clang/include/clang/AST/StmtCXX.h | 583 ++
clang/include/clang/AST/TextNodeDumper.h | 3 +
clang/include/clang/Basic/DeclNodes.td| 1 +
clang/include/clang/Basic/StmtNodes.td| 8 +
clang/include/clang/Sema/Scope.h | 18 +
.../include/clang/Serialization/ASTBitCodes.h | 10 +
clang/lib/AST/ASTImporter.cpp | 119
clang/lib/AST/DeclBase.cpp| 14 +-
clang/lib/AST/DeclPrinter.cpp | 6 +
clang/lib/AST/DeclTemplate.cpp| 23 +
clang/lib/AST/Expr.cpp| 1 +
clang/lib/AST/ExprCXX.cpp | 12 +
clang/lib/AST/ExprClassification.cpp | 1 +
clang/lib/AST/ExprConstant.cpp| 1 +
clang/lib/AST/ItaniumMangle.cpp | 8 +-
clang/lib/AST/StmtCXX.cpp | 156 +
clang/lib/AST/StmtPrinter.cpp | 35 +-
clang/lib/AST/StmtProfile.cpp | 16 +
clang/lib/AST/TextNodeDumper.cpp | 32 +-
clang/lib/CodeGen/CGDecl.cpp | 3 +
clang/lib/CodeGen/CGStmt.cpp | 4 +
clang/lib/Sema/IdentifierResolver.cpp | 7 +-
clang/lib/Sema/Scope.cpp | 1 +
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 +-
clang/lib/Sema/SemaStmtAttr.cpp | 12 +
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +
clang/lib/Sema/TreeTransform.h| 18 +
clang/lib/Serialization/ASTCommon.cpp | 1 +
clang/lib/Serialization/ASTReaderDecl.cpp | 12 +
clang/lib/Serialization/ASTReaderStmt.cpp | 46 ++
clang/lib/Serialization/ASTWriterDecl.cpp | 9 +
clang/lib/Serialization/ASTWriterStmt.cpp | 32 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 +
clang/tools/libclang/CIndex.cpp | 1 +
clang/tools/libclang/CXCursor.cpp | 3 +
47 files changed, 1438 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h
b/clang/include/clang/AST/ASTNodeTraverser.h
index 3be24ff868c2d..c999b79c3b2a7 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -972,6 +972,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/Decl.h b/clang/include/clang/AST/Decl.h
index 076d9ba935583..0224cf5a3612b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1262,14 +1262,16 @@ class VarDecl : public DeclaratorDecl, public
Redeclarable {
/// Returns true for local variable declarations other than parameters.
/// Note that this includes static variables inside of functions. It also
- /// includes variables inside blocks.
+ /// includes variables inside blocks and expansion statements.
///
/// void foo() { int x; static int y; extern int z; }
bool isLocalVarDecl() const {
if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
return false;
if (const DeclContext *DC = getLexicalDeclContext())
- return DC->getRedeclContext()->isFunctionOrMethod();
+ return DC->getEnclosingNonExpansionStatementContext()
+ ->getRedeclContext()
+ ->isFunctionOrMethod();
return false;
}
diff --git a/clang/include/clang/AST/DeclBase.h
b/clang/include/clang/AST/DeclBase.h
index 5519787d71f88..71e6898f4c94d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -2195,6 +2195,10 @@ class DeclContext {
return getDeclKind() == Decl::RequiresExprBody;
}
+ bool isExpansionStmt() const {
+return getDeclKind()
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: @shafik This the first patch in the series; see https://github.com/llvm/llvm-project/pull/169680#issuecomment-3582367696 for a complete list https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169680
>From c41aa76173c252de8fc11413e07872ba96448856 Mon Sep 17 00:00:00 2001
From: Sirraide
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/Decl.h| 6 +-
clang/include/clang/AST/DeclBase.h| 13 +
clang/include/clang/AST/DeclTemplate.h| 125
clang/include/clang/AST/ExprCXX.h | 44 ++
clang/include/clang/AST/RecursiveASTVisitor.h | 12 +
clang/include/clang/AST/StmtCXX.h | 576 ++
clang/include/clang/AST/TextNodeDumper.h | 3 +
clang/include/clang/Basic/DeclNodes.td| 1 +
clang/include/clang/Basic/StmtNodes.td| 8 +
clang/include/clang/Sema/Scope.h | 18 +
.../include/clang/Serialization/ASTBitCodes.h | 10 +
clang/lib/AST/ASTImporter.cpp | 120
clang/lib/AST/DeclBase.cpp| 14 +-
clang/lib/AST/DeclPrinter.cpp | 6 +
clang/lib/AST/DeclTemplate.cpp| 23 +
clang/lib/AST/Expr.cpp| 1 +
clang/lib/AST/ExprCXX.cpp | 12 +
clang/lib/AST/ExprClassification.cpp | 1 +
clang/lib/AST/ExprConstant.cpp| 1 +
clang/lib/AST/ItaniumMangle.cpp | 8 +-
clang/lib/AST/StmtCXX.cpp | 157 +
clang/lib/AST/StmtPrinter.cpp | 35 +-
clang/lib/AST/StmtProfile.cpp | 16 +
clang/lib/AST/TextNodeDumper.cpp | 32 +-
clang/lib/CodeGen/CGDecl.cpp | 3 +
clang/lib/CodeGen/CGStmt.cpp | 4 +
clang/lib/Sema/IdentifierResolver.cpp | 7 +-
clang/lib/Sema/Scope.cpp | 1 +
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 +-
clang/lib/Sema/SemaStmtAttr.cpp | 12 +
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +
clang/lib/Sema/TreeTransform.h| 18 +
clang/lib/Serialization/ASTCommon.cpp | 1 +
clang/lib/Serialization/ASTReaderDecl.cpp | 12 +
clang/lib/Serialization/ASTReaderStmt.cpp | 47 ++
clang/lib/Serialization/ASTWriterDecl.cpp | 9 +
clang/lib/Serialization/ASTWriterStmt.cpp | 33 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 +
clang/tools/libclang/CIndex.cpp | 1 +
clang/tools/libclang/CXCursor.cpp | 3 +
47 files changed, 1435 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h
b/clang/include/clang/AST/ASTNodeTraverser.h
index 3be24ff868c2d..c999b79c3b2a7 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -972,6 +972,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/Decl.h b/clang/include/clang/AST/Decl.h
index 076d9ba935583..0224cf5a3612b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1262,14 +1262,16 @@ class VarDecl : public DeclaratorDecl, public
Redeclarable {
/// Returns true for local variable declarations other than parameters.
/// Note that this includes static variables inside of functions. It also
- /// includes variables inside blocks.
+ /// includes variables inside blocks and expansion statements.
///
/// void foo() { int x; static int y; extern int z; }
bool isLocalVarDecl() const {
if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
return false;
if (const DeclContext *DC = getLexicalDeclContext())
- return DC->getRedeclContext()->isFunctionOrMethod();
+ return DC->getEnclosingNonExpansionStatementContext()
+ ->getRedeclContext()
+ ->isFunctionOrMethod();
return false;
}
diff --git a/clang/include/clang/AST/DeclBase.h
b/clang/include/clang/AST/DeclBase.h
index 5519787d71f88..71e6898f4c94d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -2195,6 +2195,10 @@ class DeclContext {
return getDeclKind() == Decl::RequiresExprBody;
}
+ bool isExpansionStmt() const {
+return getDeclKind()
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -38,6 +38,18 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } + // CWG 3045: The innermost enclosing switch statement of a fallthrough + // statement S shall be contained in the innermost enclosing expansion + // statement (8.7 [stmt.expand]) of S, if any. Sirraide wrote: Makes sense; do you mind if we defer that to a follow-up patch? https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -38,6 +38,18 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } + // CWG 3045: The innermost enclosing switch statement of a fallthrough + // statement S shall be contained in the innermost enclosing expansion + // statement (8.7 [stmt.expand]) of S, if any. cor3ntin wrote: ideally we should have a dr test for everything so that reflects the completeness of your work https://clang.llvm.org/cxx_dr_status.html https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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() Sirraide wrote: I don’t think so; requires clauses can’t contain arbitrary statements afaik (unless it’s in a lambda, but in that case the enclosing decl context would be the lambda itself, which is probably what we want) https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,127 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// There are different kinds of expansion statements; see the comment on
+/// 'CXXExpansionStmtPattern' for more information.
+///
+/// As an example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl'
+/// stores, amongst other things, the declaration of the variable 'x' as well
+/// as the expansion-initializer 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e.
+/// those marked as 'Actual "CompoundStmt"' below) are actually present as
+/// 'CompoundStmt's in the AST; the outer braces that wrap everything do *not*
+/// correspond to an actual 'CompoundStmt' and are implicit in the sense that
we
+/// simply push a scope when evaluating or emitting IR for a
+/// 'CXXExpansionStmtInstantiation'.
+///
+/// \verbatim
+/// { // Not actually present in the AST.
+/// auto [__u0, __u1, __u2] = a;
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u0;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u1;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes
+/// as to why this node exist and how it is used.
+///
+/// \see CXXExpansionStmtPattern
+/// \see CXXExpansionStmtInstantiation
+class CXXExpansionStmtDecl : public Decl, public DeclContext {
+ CXXExpansionStmtPattern *Expansion = nullptr;
+ NonTypeTemplateParmDecl *IndexNTTP = nullptr;
Sirraide wrote:
There’s some documentation in that comment:
```
/// Additionally, there is a 'NonTypeTemplateParmDecl', which is a template
/// parameter that serves as the expansion index, e.g. during the N-th
/// expansion, it is set to 'N'. See the documentation of
/// 'CXXExpansionStmtPattern', for more information on how this is used.
```
and some more in the one on `CXXExpansionStmtPattern`; do you want me to add
more?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,131 @@ 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.
+/// 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.
+///
+/// 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.
+///
+/// Additionally, there is a 'NonTypeTemplateParmDecl', which is a template
+/// parameter that serves as the expansion index, e.g. during the N-th
+/// expansion, it is set to 'N'. See the documentation of
+/// 'CXXExpansionStmtPattern', for more information on how this is used.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// There are different kinds of expansion statements; see the comment on
+/// 'CXXExpansionStmtPattern' for more information.
+///
+/// As an example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl'
+/// stores, amongst other things, the declaration of the variable 'x' as well
+/// as the expansion-initializer 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e.
+/// those marked as 'Actual "CompoundStmt"' below) are actually present as
+/// 'CompoundStmt's in the AST; the outer braces that wrap everything do *not*
+/// correspond to an actual 'CompoundStmt' and are implicit in the sense that
we
+/// simply push a scope when evaluating or emitting IR for a
+/// 'CXXExpansionStmtInstantiation'.
+///
+/// \verbatim
+/// { // Not actually present in the AST.
+/// auto [__u0, __u1, __u2] = a;
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u0;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u1;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes
+/// as to why this node exist and how it is used.
+///
+/// \see CXXExpansionStmtPattern
+/// \see CXXExpansionStmtInstantiation
+class CXXExpansionStmtDecl : public Decl, public DeclContext {
+ CXXExpansionStmtPattern *Expansion = nullptr;
Sirraide wrote:
Done; I’ll wait a bit before I push the changes because github sends out 10
emails every time I do...
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -196,6 +196,16 @@ class Scope {
/// declared in this scope.
unsigned short PrototypeIndex;
+ /// IsExpansionStmtScope - This is the scope corresponding to a C++26
+ /// expansion statement.
+ ///
+ /// FIXME: This should be part of ScopeFlags, but we're out of bits, so we
+ /// need to update every place that uses 'unsigned' to hold scope flags. We
+ /// should probably redefine ScopeFlags as an 'enum class : uint64_t' and
+ /// use LLVM_MARK_AS_BITMASK_ENUM() and friends so we can continue to '|'
+ /// scope flags together.
+ bool IsExpansionStmtScope;
+
Sirraide wrote:
I mean, I can look into that I suppose, but not sure how much work that would
end up being
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -38,6 +38,18 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } + // CWG 3045: The innermost enclosing switch statement of a fallthrough + // statement S shall be contained in the innermost enclosing expansion + // statement (8.7 [stmt.expand]) of S, if any. Sirraide wrote: I wasn’t planning to add one but I do have a test for it in patch 9 I think https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,127 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// There are different kinds of expansion statements; see the comment on
+/// 'CXXExpansionStmtPattern' for more information.
+///
+/// As an example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl'
+/// stores, amongst other things, the declaration of the variable 'x' as well
+/// as the expansion-initializer 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e.
+/// those marked as 'Actual "CompoundStmt"' below) are actually present as
+/// 'CompoundStmt's in the AST; the outer braces that wrap everything do *not*
+/// correspond to an actual 'CompoundStmt' and are implicit in the sense that
we
+/// simply push a scope when evaluating or emitting IR for a
+/// 'CXXExpansionStmtInstantiation'.
+///
+/// \verbatim
+/// { // Not actually present in the AST.
+/// auto [__u0, __u1, __u2] = a;
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u0;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u1;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes
+/// as to why this node exist and how it is used.
+///
+/// \see CXXExpansionStmtPattern
+/// \see CXXExpansionStmtInstantiation
+class CXXExpansionStmtDecl : public Decl, public DeclContext {
+ CXXExpansionStmtPattern *Expansion = nullptr;
+ NonTypeTemplateParmDecl *IndexNTTP = nullptr;
cor3ntin wrote:
Maybe the suggestion is to document `IndexNTTP` - I certainly would agree with
that
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -196,6 +196,16 @@ class Scope {
/// declared in this scope.
unsigned short PrototypeIndex;
+ /// IsExpansionStmtScope - This is the scope corresponding to a C++26
+ /// expansion statement.
+ ///
+ /// FIXME: This should be part of ScopeFlags, but we're out of bits, so we
+ /// need to update every place that uses 'unsigned' to hold scope flags. We
+ /// should probably redefine ScopeFlags as an 'enum class : uint64_t' and
+ /// use LLVM_MARK_AS_BITMASK_ENUM() and friends so we can continue to '|'
+ /// scope flags together.
+ bool IsExpansionStmtScope;
+
cor3ntin wrote:
Can we do that _before_ this PR?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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() cor3ntin wrote: In a few places we skip over requires clause for similar reason. Can you have an expansion in a require clause, such that we need to skip both? https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -38,6 +38,18 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A, return nullptr; } + // CWG 3045: The innermost enclosing switch statement of a fallthrough + // statement S shall be contained in the innermost enclosing expansion + // statement (8.7 [stmt.expand]) of S, if any. cor3ntin wrote: Will this be covered by a DR test? https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,131 @@ 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.
+/// 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.
+///
+/// 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.
+///
+/// Additionally, there is a 'NonTypeTemplateParmDecl', which is a template
+/// parameter that serves as the expansion index, e.g. during the N-th
+/// expansion, it is set to 'N'. See the documentation of
+/// 'CXXExpansionStmtPattern', for more information on how this is used.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// There are different kinds of expansion statements; see the comment on
+/// 'CXXExpansionStmtPattern' for more information.
+///
+/// As an example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl'
+/// stores, amongst other things, the declaration of the variable 'x' as well
+/// as the expansion-initializer 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// is *equivalent* to the AST shown below. Note that only the inner '{}' (i.e.
+/// those marked as 'Actual "CompoundStmt"' below) are actually present as
+/// 'CompoundStmt's in the AST; the outer braces that wrap everything do *not*
+/// correspond to an actual 'CompoundStmt' and are implicit in the sense that
we
+/// simply push a scope when evaluating or emitting IR for a
+/// 'CXXExpansionStmtInstantiation'.
+///
+/// \verbatim
+/// { // Not actually present in the AST.
+/// auto [__u0, __u1, __u2] = a;
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u0;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u1;
+/// // ...
+/// }
+/// { // Actual 'CompoundStmt'.
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// See the documentation around 'CXXExpansionStmtInstantiation' for more notes
+/// as to why this node exist and how it is used.
+///
+/// \see CXXExpansionStmtPattern
+/// \see CXXExpansionStmtInstantiation
+class CXXExpansionStmtDecl : public Decl, public DeclContext {
+ CXXExpansionStmtPattern *Expansion = nullptr;
cor3ntin wrote:
Maybe it would be clearer to call the variable `Pattern` ?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,581 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range, i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged].
+///
+/// Specifically, let E denote the expansion-initializer; the expansion
+/// statement is iterating if the type of E is not an array type, and either
+///
+/// 2a. 'E.begin' and 'E.end' *exist* (irrespective of whether they're
+///accessible, deleted, or even callable), or
+///
+/// 2b. ADL for 'begin(E)' and 'end(E)' finds at least one viable function.
+///
+/// If neither A nor B apply to E (or if E is an array type), we treat this as
+/// a destructuring expansion statement instead (see case 3 below).
+///
+/// Notably, case 2a only checks whether the 'begin' and 'end' members exist
and
+/// does *not* perform proper overload resolution; this is because if there is
+/// a begin/end function, but it for some reason is not usable (e.g. because it
+/// is non-const but E is const), then we'd rather error and tell the user that
+/// their begin/end function is wrong rather than falling back to
destructuring.
+///
+/// Conversely, case 2b *does* perform overload resolution, simply because ADL
+/// may find quite a few begin/end overloads for unrelated types that happen to
+/// be in the same namespace. E.g. if the type of E is 'std::tuple', then there
+/// are quite a few begin/end pairs in the namespace 'std', but non of them can
+/// actually be used for a 'std::tuple', and we definitely want to destructure
a
+/// tuple rather than error about it not being iterable.
+///
+/// In either case, once we've decided that the expansion statement is indeed
+/// iterating, we *do* make sure that the expression 'E.begin()'/'begin(E)' is
+/// well-formed, but any error at that point is a hard error and does not make
+/// us switch to destructuring instead.
+///
+/// The result of this expression is stored in a variable 'begin', which is
then
+/// used to compute another variable 'iter' (which is just 'begin' + the
+/// expansion index) during expansion. During the N-th expansion, the expansion
+/// variable is then set to '*iter'. See [stmt.expand] for more information.
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion. See
Sema::ComputeExpansionSize()
+/// for more information about this.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "abcd";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Here, 'begin' is 'foo.begin()', and during e.g. the 0-th expansion, 'iter'
+/// is 'begin + 0', and thus '*iter' yields 'a', which results in 'x' being
+/// a variable of type 'char' with value 'a'.
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we t
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1512,6 +1516,30 @@ void clang::TextNodeDumper::VisitCoreturnStmt(const
CoreturnStmt *Node) {
OS << " implicit";
}
+void TextNodeDumper::VisitCXXExpansionStmtPattern(
+const CXXExpansionStmtPattern *Node) {
+ switch (Node->getKind()) {
+ case CXXExpansionStmtPattern::ExpansionStmtKind::Enumerating:
+OS << " enumerating";
+break;
+ case CXXExpansionStmtPattern::ExpansionStmtKind::Iterating:
+OS << " iterating";
+break;
+ case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring:
+OS << " destructuring";
+break;
+ case CXXExpansionStmtPattern::ExpansionStmtKind::Dependent:
+OS << " dependent";
+break;
+ }
shafik wrote:
llvm_unreachable?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -190,11 +192,6 @@ UnsignedOrNone clang::getStackIndexOfNearestEnclosingCaptureCapableLambda( return NoLambdaIsCaptureCapable; const unsigned IndexOfCaptureReadyLambda = *OptionalStackIndex; - assert(((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) || shafik wrote: Why this change? https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,127 @@ 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
shafik wrote:
Can you also expand upon `NonTypeTemplateParmDecl`.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -96,9 +96,10 @@ IdentifierResolver::~IdentifierResolver() {
delete IdDeclInfos;
}
-/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
-/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
-/// true if 'D' belongs to the given declaration context.
+/// isDeclInScope - If 'Ctx' is a function/method/expansion statement,
shafik wrote:
This is kind of hard to read, I don't have a suggestion other than not this.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,520 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged]).
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "1234";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we try,
+/// and if it doesn't work, the program is ill-formed).
+///
+/// This essentially involves treating the expansion-initializer as the
+/// initializer of a structured-binding declarations, with the number of
+/// bindings and expansion size determined by the usual means (array size,
+/// std::tuple_size, etc.).
+///
+/// Example:
+/// \verbatim
+/// std::array a {1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Sema wraps the initializer with a CXXExpansionSelectExpr, which selects a
+/// binding based on the current expansion index.
+///
+/// 4. Represents an expansion statement whose expansion-initializer is
+/// type-dependent.
+///
+/// This will be instantiated as either an iterating or destructuring expansion
+/// statement. Dependent expansion statements can never be enumerating, even if
+/// the expansion size is dependent because the expression-list contains a
pack.
+///
+/// Example:
+/// \verbatim
+/// template
+/// void f() {
+/// template for (auto x : T()) {
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// \see CXXExpansionStmtDecl for more documentation on expansion statements.
+class CXXExpansionStmtPattern final
+: public Stmt,
+ llvm::TrailingObjects {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+
+public:
+ enum class ExpansionStmtKind : uint8_t {
+Enumerating,
+Iterating,
+Destructuring,
+Dependent,
+ };
+
+private:
+ ExpansionStmtKind PatternKind;
+ SourceLocation LParenLoc;
+ SourceLocation ColonLoc;
+ SourceLocation RParenLoc;
+ CXXExpansionStmtDecl *ParentDecl;
+
+ enum SubStmt {
+INIT,
+VAR,
+BODY,
+FIRST_CHILD_STMT,
+COUNT_Enumerating = FIRST_CHILD_STMT,
+
+// Dependent expansion initializer.
+EXPANSION_INITIALIZER = FIRST_CHILD_STMT,
shafik wrote:
The use of `FIRST_CHILD_STMT` over again here deserves a detailed comment.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -524,6 +525,520 @@ class CoreturnStmt : public Stmt {
}
};
+/// CXXExpansionStmtPattern - Represents an unexpanded C++ expansion statement.
+///
+/// There are four kinds of expansion statements.
+///
+/// 1. Enumerating expansion statements.
+/// 2. Iterating expansion statements.
+/// 3. Destructuring expansion statements.
+/// 4. Dependent expansion statements.
+///
+/// 1. An 'enumerating' expansion statement is one whose expansion-initializer
+/// is a brace-enclosed expression-list; this list is syntactically similar to
+/// an initializer list, but it isn't actually an expression in and of itself
+/// (in that it is never evaluated or emitted) and instead is just treated as
+/// a group of expressions. The expansion initializer of this is always a
+/// syntactic-form 'InitListExpr'.
+///
+/// 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 an 'InitListExpr'. This node
+/// handles storing (and pack-expanding) the individual expressions.
+///
+/// Sema then wraps this with a 'CXXExpansionSelectExpr', which also
+/// contains a reference to an integral NTTP that is used as the expansion
+/// index; this index is either dependent (if the expansion-size is dependent),
+/// or set to a value of I in the I-th expansion during the expansion process.
+///
+/// The actual expansion is done by 'BuildCXXExpansionSelectExpr()': for
+/// example, during the 2nd expansion of '{ a, b, c }', I is equal to 1, and
+/// BuildCXXExpansionSelectExpr(), when called via TreeTransform,
+/// 'instantiates' the expression '{ a, b, c }' to just 'b'.
+///
+/// 2. Represents an unexpanded iterating expansion statement.
+///
+/// An 'iterating' expansion statement is one whose expansion-initializer is a
+/// a range (i.e. it has a corresponding 'begin()'/'end()' pair that is
+/// determined based on a number of conditions as stated in [stmt.expand] and
+/// [stmt.ranged]).
+///
+/// The expression used to compute the size of the expansion is not stored and
+/// is only created at the moment of expansion.
+///
+/// Example:
+/// \verbatim
+/// static constexpr std::string_view foo = "1234";
+/// template for (auto x : foo) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// 3. Represents an unexpanded destructuring expansion statement.
+///
+/// A 'destructuring' expansion statement is any expansion statement that is
+/// not enumerating or iterating (i.e. destructuring is the last thing we try,
+/// and if it doesn't work, the program is ill-formed).
+///
+/// This essentially involves treating the expansion-initializer as the
+/// initializer of a structured-binding declarations, with the number of
+/// bindings and expansion size determined by the usual means (array size,
+/// std::tuple_size, etc.).
+///
+/// Example:
+/// \verbatim
+/// std::array a {1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// Sema wraps the initializer with a CXXExpansionSelectExpr, which selects a
+/// binding based on the current expansion index.
+///
+/// 4. Represents an expansion statement whose expansion-initializer is
+/// type-dependent.
+///
+/// This will be instantiated as either an iterating or destructuring expansion
+/// statement. Dependent expansion statements can never be enumerating, even if
+/// the expansion size is dependent because the expression-list contains a
pack.
shafik wrote:
The details in the first case are really great and the last three are very
sparse.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,127 @@ 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
shafik wrote:
```suggestion
/// the 'template depth' is used to find instantiations of parameter variables.
/// A lambda enclosed within an expansion statement cannot compute its
```
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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() shafik wrote: I see you have throw these (`getEnclosingNonExpansionStatementContext`) in a bunch of places and it is not clear to me how we can ensure we did not miss spots that could blow up later on. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/shafik commented: I think I did a pretty complete run through but this is quite large, it is a bit daunting considering how many more there are. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -5554,6 +5554,52 @@ class CXXReflectExpr : public Expr {
}
};
+/// Helper that selects an expression from an InitListExpr depending
+/// on the current expansion index.
+///
+/// \see CXXExpansionStmtPattern
+class CXXExpansionSelectExpr : public Expr {
+ friend class ASTStmtReader;
+
+ enum SubExpr { RANGE, INDEX, COUNT };
shafik wrote:
INDEX here feels a little abstract but maybe later comments will help.
Ok looks like this is covered in `CXXExpansionStmtPattern` comment, maybe a
forward reference would be helpful, "if you want to know more see "
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -7645,7 +7645,6 @@ static void
CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) {
assert(!S.isUnevaluatedContext());
- assert(S.CurContext->isDependentContext());
shafik wrote:
Why this change?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/shafik edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: ping (Erich has already reviewed the patches, and Eli has looked at the codegen changes, but we’d still like some more people to take a look at it before merging) https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/erichkeane approved this pull request. I think I'm ok with this one. There's a lot of stuff in this patch, but I did as good of a review as I could, and it seems reasonable. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: ping https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1730,6 +1730,35 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
S->setBody(Record.readSubStmt());
}
+void ASTStmtReader::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
+ VisitStmt(S);
+ Record.skipInts(1); // Skip kind.
+ S->LParenLoc = readSourceLocation();
+ S->ColonLoc = readSourceLocation();
+ S->RParenLoc = readSourceLocation();
+ S->ParentDecl = cast(Record.readDeclRef());
+ for (Stmt *&SubStmt : S->children())
+SubStmt = Record.readSubStmt();
+}
+
+void ASTStmtReader::VisitCXXExpansionStmtInstantiation(
+CXXExpansionStmtInstantiation *S) {
+ VisitStmt(S);
+ Record.skipInts(2);
Sirraide wrote:
`CXXExpansionStmtInstantiation` uses `TrailingObjects`; the 2 integers store
how many elements of trailing data we need to allocate and are used when we
allocate the statement; we don’t need them here anymore so we just skip them.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1730,6 +1730,35 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
S->setBody(Record.readSubStmt());
}
+void ASTStmtReader::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
+ VisitStmt(S);
+ Record.skipInts(1); // Skip kind.
+ S->LParenLoc = readSourceLocation();
+ S->ColonLoc = readSourceLocation();
+ S->RParenLoc = readSourceLocation();
+ S->ParentDecl = cast(Record.readDeclRef());
+ for (Stmt *&SubStmt : S->children())
+SubStmt = Record.readSubStmt();
+}
+
+void ASTStmtReader::VisitCXXExpansionStmtInstantiation(
+CXXExpansionStmtInstantiation *S) {
+ VisitStmt(S);
+ Record.skipInts(2);
ChuanqiXu9 wrote:
Why do we always skip? If we can, why do we write it?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: ping https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: > First things first, your summary should list the paper number and ideally > have a link to it as well Alternatively, it could go in the title. Added a link to the pr summary https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/shafik edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/shafik commented: First things first, your summary should list the paper number and ideally have a link to it as well. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: Oh yeah, and `CXXExpansionInitListExpr` is also gone now and everything just uses `InitListExpr`. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
github-actions[bot] wrote:
:warning: C/C++ code formatter, clang-format found issues in your code.
:warning:
You can test this locally with the following command:
``bash
git-clang-format --diff origin/main HEAD --extensions h,cpp --
clang/include/clang/AST/ASTNodeTraverser.h clang/include/clang/AST/Decl.h
clang/include/clang/AST/DeclBase.h clang/include/clang/AST/DeclTemplate.h
clang/include/clang/AST/ExprCXX.h clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/StmtCXX.h clang/include/clang/AST/TextNodeDumper.h
clang/include/clang/Serialization/ASTBitCodes.h clang/lib/AST/ASTImporter.cpp
clang/lib/AST/DeclBase.cpp clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/DeclTemplate.cpp clang/lib/AST/Expr.cpp clang/lib/AST/ExprCXX.cpp
clang/lib/AST/ExprClassification.cpp clang/lib/AST/ExprConstant.cpp
clang/lib/AST/ItaniumMangle.cpp clang/lib/AST/StmtCXX.cpp
clang/lib/AST/StmtPrinter.cpp clang/lib/AST/StmtProfile.cpp
clang/lib/AST/TextNodeDumper.cpp clang/lib/CodeGen/CGDecl.cpp
clang/lib/CodeGen/CGStmt.cpp clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaExceptionSpec.cpp
clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaLambda.cpp clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTCommon.cpp clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp clang/tools/libclang/CIndex.cpp
clang/tools/libclang/CXCursor.cpp --diff_from_common_commit
``
:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:
View the diff from clang-format here.
``diff
diff --git a/clang/include/clang/AST/ExprCXX.h
b/clang/include/clang/AST/ExprCXX.h
index 083576c53..c6380f9b1 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -5513,9 +5513,7 @@ public:
CXXExpansionSelectExpr(EmptyShell Empty);
CXXExpansionSelectExpr(const ASTContext &C, InitListExpr *Range, Expr *Idx);
- InitListExpr *getRangeExpr() {
-return cast(SubExprs[RANGE]);
- }
+ InitListExpr *getRangeExpr() { return cast(SubExprs[RANGE]); }
const InitListExpr *getRangeExpr() const {
return cast(SubExprs[RANGE]);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 148a5b514..2b69262a0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -7483,8 +7483,8 @@ ExpectedStmt
ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
ToBody, ToForLoc, ToCoawaitLoc, ToColonLoc, ToRParenLoc);
}
-ExpectedStmt ASTNodeImporter::VisitCXXExpansionStmtPattern(
-CXXExpansionStmtPattern *S) {
+ExpectedStmt
+ASTNodeImporter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
Error Err = Error::success();
auto ToESD = importChecked(Err, S->getDecl());
auto ToInit = importChecked(Err, S->getInit());
@@ -9454,8 +9454,8 @@
ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
ToInitLoc, ToBeginLoc, ToEndLoc);
}
-ExpectedStmt ASTNodeImporter::VisitCXXExpansionSelectExpr(
-CXXExpansionSelectExpr *E) {
+ExpectedStmt
+ASTNodeImporter::VisitCXXExpansionSelectExpr(CXXExpansionSelectExpr *E) {
Error Err = Error::success();
auto ToRange = importChecked(Err, E->getRangeExpr());
auto ToIndex = importChecked(Err, E->getIndexExpr());
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 8898547e2..9ea8cd69f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -2024,8 +2024,8 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr
*Callee,
CXXExpansionSelectExpr::CXXExpansionSelectExpr(EmptyShell Empty)
: Expr(CXXExpansionSelectExprClass, Empty) {}
-CXXExpansionSelectExpr::CXXExpansionSelectExpr(
-const ASTContext &C, InitListExpr *Range, Expr *Idx)
+CXXExpansionSelectExpr::CXXExpansionSelectExpr(const ASTContext &C,
+ InitListExpr *Range, Expr *Idx)
: Expr(CXXExpansionSelectExprClass, C.DependentTy, VK_PRValue,
OK_Ordinary) {
setDependence(ExprDependence::TypeValueInstantiation);
diff --git a/clang/lib/AST/StmtCXX.cpp b/clang/lib/AST/StmtCXX.cpp
index 6f7cddd49..ffccd76d1 100644
--- a/clang/lib/AST/StmtCXX.cpp
+++ b/clang/lib/AST/StmtCXX.cpp
@@ -209,8 +209,7 @@ SourceLocation CXXExpansionStmtPattern::getBeginLoc() const
{
return ParentDecl->getLocation();
}
-DecompositionDecl *
-CXXExpansionStmtPattern::getDecompositionDecl() {
+DecompositionDecl *CXXExpansionStmtPattern::getDecompositionDecl() {
assert(i
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: Ok, I’ve merged all of the `CXXExpansionStmtPattern` classes into a single class (which is now rather huge as a result, but it ends up being less code overall), and I’ve merged the two select exprs into a single one by just synthesising an `InitListExpr` to store all of the bindings of a destructuring expansion statement. Including the Decl, we’re now down to 4 AST nodes in total, which is a lot less horrible. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -125,3 +126,155 @@
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
Args.ReturnStmtOnAllocFailure;
llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data()));
}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell
Empty)
+: Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt
*ExpansionVar,
+
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+ RParenLoc(RParenLoc) {
+ setInit(Init);
+ setExpansionVarStmt(ExpansionVar);
+ setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+EmptyShell Empty)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty)
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+ Init, ExpansionVar, LParenLoc, ColonLoc,
+ RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+ return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+ Decl *LV = cast(getExpansionVarStmt())->getSingleDecl();
+ assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+ return cast(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+ if (isa(this))
+return cast(
+ getExpansionVariable()->getInit())
+->getRangeExpr()
+->containsPackExpansion();
+
+ if (auto *Iterating = dyn_cast(this)) {
+const Expr *Begin = Iterating->getBeginVar()->getInit();
+const Expr *End = Iterating->getBeginVar()->getInit();
+return Begin->isTypeDependent() || Begin->isValueDependent() ||
Sirraide wrote:
Instantiation dependent worked fine
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
Sirraide wrote:
I decided not to put everything in one place after all, but I’ve added a
paragraph that explains the compount statement situation to both the decl and
the instantiation stmt and overall added some more explanatory notes. Hopefully
this makes everything a bit clearer.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: Because I was just asked about this, here’s a link that shows the entire diff for the patch series in case anyone prefers to look at all of it at once: https://github.com/llvm/llvm-project/compare/llvm:llvm-project:main...llvm:llvm-project:users/Sirraide/expansion-stmts-11-final-touches-and-ast-tests https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
+///
+/// \verbatim
+/// {
+/// auto [__u0, __u1, __u2] = a;
+/// {
+/// auto x = __u0;
+/// // ...
+/// }
+/// {
+/// auto x = __u1;
+/// // ...
+/// }
+/// {
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// The outer braces shown above are implicit; we don't actually create another
Sirraide wrote:
We _do_ create the inner ones, but not the big outer one that wraps everything
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
+///
+/// \verbatim
+/// {
+/// auto [__u0, __u1, __u2] = a;
+/// {
+/// auto x = __u0;
+/// // ...
+/// }
+/// {
+/// auto x = __u1;
+/// // ...
+/// }
+/// {
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// The outer braces shown above are implicit; we don't actually create another
erichkeane wrote:
Yeah, though this says we don't create a compound stmt, though I'm sure I saw
one?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
erichkeane wrote:
IMO, we SHOULD be putting more of that sorta stuff into the internals manual.
These comments get lost/stale/tough to figure out WHERE they are when you need
them.So I think it makes sense to be there.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -125,3 +126,155 @@
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
Args.ReturnStmtOnAllocFailure;
llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data()));
}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell
Empty)
+: Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt
*ExpansionVar,
+
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+ RParenLoc(RParenLoc) {
+ setInit(Init);
+ setExpansionVarStmt(ExpansionVar);
+ setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+EmptyShell Empty)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty)
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+ Init, ExpansionVar, LParenLoc, ColonLoc,
+ RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+ return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+ Decl *LV = cast(getExpansionVarStmt())->getSingleDecl();
+ assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+ return cast(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+ if (isa(this))
+return cast(
+ getExpansionVariable()->getInit())
+->getRangeExpr()
+->containsPackExpansion();
+
+ if (auto *Iterating = dyn_cast(this)) {
+const Expr *Begin = Iterating->getBeginVar()->getInit();
+const Expr *End = Iterating->getBeginVar()->getInit();
+return Begin->isTypeDependent() || Begin->isValueDependent() ||
Sirraide wrote:
I’ll try instantiation dependent and see if that affects any tests
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
+///
+/// \verbatim
+/// {
+/// auto [__u0, __u1, __u2] = a;
+/// {
+/// auto x = __u0;
+/// // ...
+/// }
+/// {
+/// auto x = __u1;
+/// // ...
+/// }
+/// {
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// The outer braces shown above are implicit; we don't actually create another
Sirraide wrote:
Did the comments starting at
https://github.com/llvm/llvm-project/pull/169680#discussion_r2577466941 address
what you were confused about here or is this something else?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
Sirraide wrote:
> I like the idea of having it all in 1 place, but would also like each node to
> have a quick summary of its participation too.
I’ll see if I can figure out a way to make that work
> I DO wonder if the 'big' comment has hit the "should be in the internals
> manual" though.
It is getting rather huge yeah... but at the same time, a large portion of the
big comment(s) is just ‘this is how expansion statements work’, so not sure if
that belongs in the internals manuall since those parts aren’t really
Clang-specific
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -125,3 +126,155 @@
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
Args.ReturnStmtOnAllocFailure;
llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data()));
}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell
Empty)
+: Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt
*ExpansionVar,
+
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+ RParenLoc(RParenLoc) {
+ setInit(Init);
+ setExpansionVarStmt(ExpansionVar);
+ setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+EmptyShell Empty)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty)
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+ Init, ExpansionVar, LParenLoc, ColonLoc,
+ RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+ return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+ Decl *LV = cast(getExpansionVarStmt())->getSingleDecl();
+ assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+ return cast(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+ if (isa(this))
+return cast(
+ getExpansionVariable()->getInit())
+->getRangeExpr()
+->containsPackExpansion();
+
+ if (auto *Iterating = dyn_cast(this)) {
+const Expr *Begin = Iterating->getBeginVar()->getInit();
+const Expr *End = Iterating->getBeginVar()->getInit();
+return Begin->isTypeDependent() || Begin->isValueDependent() ||
erichkeane wrote:
>Not in the general case I believe (e.g. sizeof(T)` is not type-dependent
>afaik, only value-dependent), but here yeah, you’re probably right, and I
>think we only care about type-dependence here.
Right, you can be JUST value dependent, but you can't be JUST type dependent.
>Shouldn’t we check for type dependence specifically? Because as I understand
>it it’s possible for this to be instantiation-dependent even if the type is
>known (and potentially the value too), in which case we still want to
>instantiate it? Maybe I’m just overthinking this and those are hypothetical
>scenarios that we don’t care too much about though...
It depends on how much we CARE about the individual situations. We often just
do `instantiation dependent` and figure we'll lose a few early errors, at the
guarantee of making sure we get it 'right'.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
Sirraide wrote:
Yes, definitely
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: I mean I guess; I’ll update the comment. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -125,3 +126,155 @@
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
Args.ReturnStmtOnAllocFailure;
llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data()));
}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell
Empty)
+: Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt
*ExpansionVar,
+
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+ RParenLoc(RParenLoc) {
+ setInit(Init);
+ setExpansionVarStmt(ExpansionVar);
+ setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+EmptyShell Empty)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty)
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+ Init, ExpansionVar, LParenLoc, ColonLoc,
+ RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+ return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+ Decl *LV = cast(getExpansionVarStmt())->getSingleDecl();
+ assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+ return cast(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+ if (isa(this))
+return cast(
+ getExpansionVariable()->getInit())
+->getRangeExpr()
+->containsPackExpansion();
+
+ if (auto *Iterating = dyn_cast(this)) {
+const Expr *Begin = Iterating->getBeginVar()->getInit();
+const Expr *End = Iterating->getBeginVar()->getInit();
+return Begin->isTypeDependent() || Begin->isValueDependent() ||
Sirraide wrote:
> If it is Type dependent, it is ALSO value dependent)
Not in the general case I believe (e.g. sizeof(T)` is not type-dependent afaik,
only value-dependent), but here yeah, you’re probably right, and I think we
only care about type-dependence here.
> You probably just want isInstantiationDependent which covers all dependent
> cases.
Shouldn’t we check for type dependence specifically? Because as I understand it
it’s possible for this to be instantiation-dependent even if the type is known
(and potentially the value too), in which case we still want to instantiate it?
Maybe I’m just overthinking this and those are hypothetical scenarios that we
don’t care too much about though...
> Also, what is going on? Aren't `Begin` and `End` the same thing here?
Goddamn copy-paste errors; thanks for spotting that.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
Code = serialization::STMT_CXX_FOR_RANGE;
}
+void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
erichkeane wrote:
Yep, understood! Just making sure you know about it/have them somewher.e
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -204,6 +204,13 @@ void CodeGenFunction::EmitStmt(const Stmt *S,
ArrayRef Attrs) {
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast(*S), Attrs);
break;
+ case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+ case Stmt::CXXIteratingExpansionStmtPatternClass:
+ case Stmt::CXXDestructuringExpansionStmtPatternClass:
+ case Stmt::CXXDependentExpansionStmtPatternClass:
+llvm_unreachable("unexpanded expansion statements should not be emitted");
+ case Stmt::CXXExpansionStmtInstantiationClass:
+llvm_unreachable("Todo");
Sirraide wrote:
That too is replaced later in this stack, so this is just temporary code that
won’t ever make it to trunk
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
Code = serialization::STMT_CXX_FOR_RANGE;
}
+void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
Sirraide wrote:
I didn’t include those tests in this patch because creating these nodes kind of
requires Sema and everything else to be implemented...
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
Code = serialization::STMT_CXX_FOR_RANGE;
}
+void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
Sirraide wrote:
I _should_ have AST dump tests somewhere; I think they’re in the last patch in
the stack and they should have both serialisation and non-serialisation tests
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final } }; +/// Represents an expansion-init-list of an enumerating expansion statement. erichkeane wrote: Ooof, thats an awful name. Yeah, a quick example would be lovely. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
erichkeane wrote:
I like the idea of having it all in 1 place, but would also like each node to
have a quick summary of its participation too.
I DO wonder if the 'big' comment has hit the "should be in the internals
manual" though.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -9292,6 +9292,59 @@
TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
}
+template
+StmtResult TreeTransform::TransformCXXEnumeratingExpansionStmtPattern(
+CXXEnumeratingExpansionStmtPattern *S) {
+ llvm_unreachable("TOOD");
Sirraide wrote:
Ha, I misspelt TODO again.
Yes, all of the ‘TODO’s etc. are replaced later on in the stack.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final } }; +/// Represents an expansion-init-list of an enumerating expansion statement. Sirraide wrote: _expansion-init-list_ is a production in the [grammar](https://eel.is/c++draft/stmt.expand#1), but I can add an example here if that helps https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
Sirraide wrote:
I should update this comment to indicate that the outer compound statement is
‘not actually there’; I don’t remember why I didn’t explain that here (and
perhaps some of the documentation needs to be deduplicated, and this section
here should just say ‘see the comment on `CXXExpansionStmtInstantiation` for
more information on the AST we produce for the expansions’).
Alternatively, as you (or Corentin, I don’t remember?) suggested, I can move
all of the expansion statement documentation into one big comment here, and
then all the other nodes just have a comment that says ‘see
`CXXExpansionStmtDecl` for documentation on this’, which might be easier to
work w/ than having it all fragmented across 6-odd AST nodes...
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
erichkeane wrote:
sensible, i think that is reasonable. Can we put that in the comment?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
Sirraide wrote:
Ok, so that is explained in more detail in the `CXXExpansionStmtInstantiation`
documentation I believe, but the *outermost* compound statement explicitly
_does not exist_ in the AST (only the inner ones shown here do); it pretty much
is already as you’re describing (i.e. we handle the outer scope in codegen).
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
erichkeane wrote: Its a bit subtle that it looks through a 'scope'. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
Sirraide wrote:
We need custom codegen to handle `break`/`continue` in expansion statements
properly, so it can’t just be a compound statement or list of statements w/ no
special handling; additionally, the expansions are created after both the
pattern and the `CXXExpansionStmtDecl`, so we can’t just store them as trailing
data in either of those nodes. The only other option I can think of is to just
throw them into the `ASTContext` allocator and store an `ArrayRef` in
the `ExpansionStmtDecl*`, but that feels like more of a hack than just making
that its own AST node.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
Sirraide wrote:
It only contains one parameter; as to why we’re storing a template parameter
list, er, the fork was using one, and I kind of assumed that we needed to have
one because it feels a bit weird to have a template parameter just on its own,
but if storing just the parameter works, then I’ll do that instead; I’ll take a
look at that
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: I mean, I feel like that variables in expansion statements are also just local variables, so I’m not sure we’d have to document that, but I can if you want me to. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -204,6 +204,13 @@ void CodeGenFunction::EmitStmt(const Stmt *S,
ArrayRef Attrs) {
case Stmt::CXXForRangeStmtClass:
EmitCXXForRangeStmt(cast(*S), Attrs);
break;
+ case Stmt::CXXEnumeratingExpansionStmtPatternClass:
+ case Stmt::CXXIteratingExpansionStmtPatternClass:
+ case Stmt::CXXDestructuringExpansionStmtPatternClass:
+ case Stmt::CXXDependentExpansionStmtPatternClass:
+llvm_unreachable("unexpanded expansion statements should not be emitted");
+ case Stmt::CXXExpansionStmtInstantiationClass:
+llvm_unreachable("Todo");
erichkeane wrote:
I think we have an error mechanism for this? Also, it should be `TODO`,
capital makes these sorts of things greppable.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
erichkeane wrote:
Why is the latter not a collection of any sort then?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -1704,6 +1704,85 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt
*S) {
Code = serialization::STMT_CXX_FOR_RANGE;
}
+void ASTStmtWriter::VisitCXXExpansionStmtPattern(CXXExpansionStmtPattern *S) {
erichkeane wrote:
At one point we should make sure we have tests for all of this. You can use
PCH (I do it a bunch for the -ast tests in OpenACC if you need an example) and
dump-ast together to make sure the AST is the same before and after.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -5499,6 +5499,165 @@ class BuiltinBitCastExpr final } }; +/// Represents an expansion-init-list of an enumerating expansion statement. erichkeane wrote: I don't quite get what this means, can you expand on this? https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -125,3 +126,155 @@
CoroutineBodyStmt::CoroutineBodyStmt(CoroutineBodyStmt::CtorArgs const &Args)
Args.ReturnStmtOnAllocFailure;
llvm::copy(Args.ParamMoves, const_cast(getParamMoves().data()));
}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(StmtClass SC, EmptyShell
Empty)
+: Stmt(SC, Empty) {}
+
+CXXExpansionStmtPattern::CXXExpansionStmtPattern(
+StmtClass SC, CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt
*ExpansionVar,
+
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: Stmt(SC), ParentDecl(ESD), LParenLoc(LParenLoc), ColonLoc(ColonLoc),
+ RParenLoc(RParenLoc) {
+ setInit(Init);
+ setExpansionVarStmt(ExpansionVar);
+ setBody(nullptr);
+}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+EmptyShell Empty)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, Empty)
{}
+
+CXXEnumeratingExpansionStmtPattern::CXXEnumeratingExpansionStmtPattern(
+CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVar,
+SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation
RParenLoc)
+: CXXExpansionStmtPattern(CXXEnumeratingExpansionStmtPatternClass, ESD,
+ Init, ExpansionVar, LParenLoc, ColonLoc,
+ RParenLoc) {}
+
+SourceLocation CXXExpansionStmtPattern::getBeginLoc() const {
+ return ParentDecl->getLocation();
+}
+
+VarDecl *CXXExpansionStmtPattern::getExpansionVariable() {
+ Decl *LV = cast(getExpansionVarStmt())->getSingleDecl();
+ assert(LV && "No expansion variable in CXXExpansionStmtPattern");
+ return cast(LV);
+}
+
+bool CXXExpansionStmtPattern::hasDependentSize() const {
+ if (isa(this))
+return cast(
+ getExpansionVariable()->getInit())
+->getRangeExpr()
+->containsPackExpansion();
+
+ if (auto *Iterating = dyn_cast(this)) {
+const Expr *Begin = Iterating->getBeginVar()->getInit();
+const Expr *End = Iterating->getBeginVar()->getInit();
+return Begin->isTypeDependent() || Begin->isValueDependent() ||
erichkeane wrote:
This is all pretty redundant (If it is Type dependent, it is ALSO value
dependent) :) Also, what is going on? Aren't `Begin` and `End` the same thing
here?
You probably just want `isInstantiationDependent` which covers all dependent
cases.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
erichkeane wrote:
Oh, huh so it is ALL of the statements wrapped in a compound stmt...
I rather wonder if we're better off NOT doing the compound statement and having
code-gen just emit these scopes right. Are there any other advantages to the
compound statement?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -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
erichkeane wrote:
What else does the list contain? And why a list instead of a single template
parameter if that is the only thing in the list?
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -9292,6 +9292,59 @@
TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
}
+template
+StmtResult TreeTransform::TransformCXXEnumeratingExpansionStmtPattern(
+CXXEnumeratingExpansionStmtPattern *S) {
+ llvm_unreachable("TOOD");
erichkeane wrote:
Who is TOOD?
That said, we probably dont' want `unreachable`, right? Though I presume these
are all just replaced later in the stack? If that is true, disregard.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
erichkeane wrote: Can we update this comment too? It seems sensible that `getLocalVarDecl` document that it looks through expansion statements. https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
@@ -3343,6 +3343,120 @@ class TemplateParamObjectDecl : public ValueDecl,
static bool classofKind(Kind K) { return K == TemplateParamObject; }
};
+/// Represents a C++26 expansion statement declaration.
+///
+/// This is a bit of a hack, since expansion statements shouldn't really be
+/// 'declarations' per se (they don't declare anything). Nevertheless, we *do*
+/// need them to be declaration *contexts*, because the DeclContext is used to
+/// compute the 'template depth' of entities enclosed therein. In particular,
+/// the 'template depth' is used to find instantiations of parameter variables,
+/// and a lambda enclosed within an expansion statement cannot compute its
+/// template depth without a pointer to the enclosing expansion statement.
+///
+/// For the remainder of this comment, let 'expanding' an expansion statement
+/// refer to the process of performing template substitution on its body N
+/// times, where N is the expansion size (how this size is determined depends
on
+/// the kind of expansion statement); by contrast we may sometimes
'instantiate'
+/// an expansion statement (because it happens to be in a template). This is
+/// just regular template instantiation.
+///
+/// Apart from a template parameter list that contains a template parameter
used
+/// as the expansion index, this node contains a 'CXXExpansionStmtPattern' as
+/// well as a 'CXXExpansionStmtInstantiation'. These two members correspond to
+/// distinct representations of the expansion statement: the former is used
+/// prior to expansion and contains all the parts needed to perform expansion;
+/// the latter holds the expanded/desugared AST nodes that result from the
+/// expansion.
+///
+/// After expansion, the 'CXXExpansionStmtPattern' is no longer updated and
left
+/// as-is; this also means that, if an already-expanded expansion statement is
+/// inside a template, and that template is then instantiated, the
+/// 'CXXExpansionStmtPattern' is *not* instantiated; only the
+/// 'CXXExpansionStmtInstantiation' is. The latter is also what's used for
+/// codegen and constant evaluation.
+///
+/// For example, if the user writes the following expansion statement:
+/// \verbatim
+/// std::tuple a{1, 2, 3};
+/// template for (auto x : a) {
+/// // ...
+/// }
+/// \endverbatim
+///
+/// The 'CXXExpansionStmtPattern' of this particular 'CXXExpansionStmtDecl' is
a
+/// 'CXXDestructuringExpansionStmtPattern', which stores, amongst other things,
+/// the declaration of the variable 'x' as well as the expansion-initializer
+/// 'a'.
+///
+/// After expansion, we end up with a 'CXXExpansionStmtInstantiation' that
+/// contains a DecompositionDecl and 3 CompoundStmts, one for each expansion:
+///
+/// \verbatim
+/// {
+/// auto [__u0, __u1, __u2] = a;
+/// {
+/// auto x = __u0;
+/// // ...
+/// }
+/// {
+/// auto x = __u1;
+/// // ...
+/// }
+/// {
+/// auto x = __u2;
+/// // ...
+/// }
+/// }
+/// \endverbatim
+///
+/// The outer braces shown above are implicit; we don't actually create another
erichkeane wrote:
Oh, I see... So I'm back to confused, maybe it'll get better as I read further.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
Sirraide wrote: Sorry for wreaking havoc on everyone’s inbox w/ these, but hopefully reviewing this is somewhat more manageable now... https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
llvmbot wrote:
@llvm/pr-subscribers-clang-codegen
Author: None (Sirraide)
Changes
---
Patch is 98.90 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/169680.diff
43 Files Affected:
- (modified) clang/include/clang/AST/ASTNodeTraverser.h (+6)
- (modified) clang/include/clang/AST/ComputeDependence.h (+3)
- (modified) clang/include/clang/AST/Decl.h (+3-1)
- (modified) clang/include/clang/AST/DeclBase.h (+13)
- (modified) clang/include/clang/AST/DeclTemplate.h (+114)
- (modified) clang/include/clang/AST/ExprCXX.h (+159)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+17)
- (modified) clang/include/clang/AST/StmtCXX.h (+478)
- (modified) clang/include/clang/AST/TextNodeDumper.h (+5)
- (modified) clang/include/clang/Basic/DeclNodes.td (+1)
- (modified) clang/include/clang/Basic/StmtNodes.td (+14)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+31-10)
- (modified) clang/lib/AST/ASTImporter.cpp (+174)
- (modified) clang/lib/AST/ComputeDependence.cpp (+7)
- (modified) clang/lib/AST/DeclBase.cpp (+13-1)
- (modified) clang/lib/AST/DeclPrinter.cpp (+6)
- (modified) clang/lib/AST/DeclTemplate.cpp (+23)
- (modified) clang/lib/AST/Expr.cpp (+3)
- (modified) clang/lib/AST/ExprCXX.cpp (+58)
- (modified) clang/lib/AST/ExprClassification.cpp (+3)
- (modified) clang/lib/AST/ExprConstant.cpp (+3)
- (modified) clang/lib/AST/ItaniumMangle.cpp (+9-1)
- (modified) clang/lib/AST/StmtCXX.cpp (+153)
- (modified) clang/lib/AST/StmtPrinter.cpp (+61-1)
- (modified) clang/lib/AST/StmtProfile.cpp (+47)
- (modified) clang/lib/AST/TextNodeDumper.cpp (+22-1)
- (modified) clang/lib/Sema/Sema.cpp (+4-3)
- (modified) clang/lib/Sema/SemaDecl.cpp (+2-2)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+8)
- (modified) clang/lib/Sema/SemaExpr.cpp (+3-2)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (-1)
- (modified) clang/lib/Sema/SemaLambda.cpp (+15-13)
- (modified) clang/lib/Sema/SemaLookup.cpp (+3-1)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+5)
- (modified) clang/lib/Sema/TreeTransform.h (+53)
- (modified) clang/lib/Serialization/ASTCommon.cpp (+1)
- (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+12)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+107)
- (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+9)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+79)
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+8)
- (modified) clang/tools/libclang/CIndex.cpp (+1)
- (modified) clang/tools/libclang/CXCursor.cpp (+8)
``diff
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h
b/clang/include/clang/AST/ASTNodeTraverser.h
index e74bb72571d64..fd64d86f83bfd 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -959,6 +959,12 @@ class ASTNodeTraverser
}
}
+ void VisitCXXExpansionStmtDecl(const CXXExpansionStmtDecl *Node) {
+Visit(Node->getExpansionPattern());
+if (Traversal != TK_IgnoreUnlessSpelledInSource)
+ Visit(Node->getInstantiations());
+ }
+
void VisitCallExpr(const CallExpr *Node) {
for (const auto *Child :
make_filter_range(Node->children(), [this](const Stmt *Child) {
diff --git a/clang/include/clang/AST/ComputeDependence.h
b/clang/include/clang/AST/ComputeDependence.h
index c298f2620f211..792f45bea5aeb 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -94,6 +94,7 @@ class DesignatedInitExpr;
class ParenListExpr;
class PseudoObjectExpr;
class AtomicExpr;
+class CXXExpansionInitListExpr;
class ArraySectionExpr;
class OMPArrayShapingExpr;
class OMPIteratorExpr;
@@ -191,6 +192,8 @@ ExprDependence computeDependence(ParenListExpr *E);
ExprDependence computeDependence(PseudoObjectExpr *E);
ExprDependence computeDependence(AtomicExpr *E);
+ExprDependence computeDependence(CXXExpansionInitListExpr *E);
+
ExprDependence computeDependence(ArraySectionExpr *E);
ExprDependence computeDependence(OMPArrayShapingExpr *E);
ExprDependence computeDependence(OMPIteratorExpr *E);
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index ee2321dd158d4..b8f8e002ebcce 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1254,7 +1254,9 @@ class VarDecl : public DeclaratorDecl, public
Redeclarable {
if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
return false;
if (const DeclContext *DC = getLexicalDeclContext())
- return DC->getRedeclContext()->isFunctionOrMethod();
+ return DC->getEnclosingNonExpansionStatementContext()
+ ->getRedeclContext()
+ ->isFunctionOrMethod();
return false;
}
diff --git a/clang/include/clang/AST/DeclBase.h
b/clang/include/clang/AST/DeclBase.h
index 5519787d71f88..71e6898f4c94d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide ready_for_review https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
github-actions[bot] wrote:
# :penguin: Linux x64 Test Results
* 3053 tests passed
* 7 tests skipped
All tests passed but another part of the build **failed**. Click on a failure
below to see the details.
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o
```
FAILED: tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o
sccache /opt/llvm/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG
-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/lib/CodeGen
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt
-fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror
-Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra
-Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers
-pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough
-Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor
-Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion
-Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported
-fdiagnostics-color -ffunction-sections -fdata-sections -fno-common
-Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17
-fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o -MF
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o.d -o
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGDecl.cpp.o -c
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGDecl.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGDecl.cpp:53:11:
error: enumeration value 'CXXExpansionStmt' not handled in switch
[-Werror,-Wswitch]
53 | switch (D.getKind()) {
| ^~~
1 error generated.
```
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o
```
FAILED: tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o
sccache /opt/llvm/bin/clang++ -DCLANG_EXPORTS -DGTEST_HAS_RTTI=0 -D_DEBUG
-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/lib/CodeGen
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/clang/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include
-I/home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/include -gmlt
-fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror
-Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra
-Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers
-pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough
-Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor
-Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion
-Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported
-fdiagnostics-color -ffunction-sections -fdata-sections -fno-common
-Woverloaded-virtual -Wno-nested-anon-types -O3 -DNDEBUG -std=c++17
-fno-exceptions -funwind-tables -fno-rtti -UNDEBUG -MD -MT
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o -MF
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o.d -o
tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CGStmt.cpp.o -c
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGStmt.cpp
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/lib/CodeGen/CGStmt.cpp:100:11:
error: 5 enumeration values not handled in switch:
'CXXIteratingExpansionStmtPatternClass',
'CXXEnumeratingExpansionStmtPatternClass',
'CXXDestructuringExpansionStmtPatternClass'... [-Werror,-Wswitch]
100 | switch (S->getStmtClass()) {
| ^
1 error generated.
```
If these failures are unrelated to your changes (for example tests are broken
or flaky at HEAD), please open an issue at
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.
https://github.com/llvm/llvm-project/pull/169680
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] [C++26] Expansion Statements (Part 1: AST) (PR #169680)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169680 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
