-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) #169682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Sirraide
wants to merge
1
commit into
users/Sirraide/expansion-stmts-2-parsing
Choose a base branch
from
users/Sirraide/expansion-stmts-3-enumerating
base: users/Sirraide/expansion-stmts-2-parsing
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[Clang] [C++26] Expansion Statements (Part 3: Enumerating Expansion Statements) #169682
Sirraide
wants to merge
1
commit into
users/Sirraide/expansion-stmts-2-parsing
from
users/Sirraide/expansion-stmts-3-enumerating
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
Author
This was referenced Nov 26, 2025
Member
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: None (Sirraide) ChangesPatch is 32.88 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169682.diff 9 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ca862316a2f27..d4783c1c9677d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5827,6 +5827,8 @@ def note_template_nsdmi_here : Note<
"in instantiation of default member initializer %q0 requested here">;
def note_template_type_alias_instantiation_here : Note<
"in instantiation of template type alias %0 requested here">;
+def note_expansion_stmt_instantiation_here : Note<
+ "in instantiation of expansion statement requested here">;
def note_template_exception_spec_instantiation_here : Note<
"in instantiation of exception specification for %0 requested here">;
def note_template_requirement_instantiation_here : Note<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 786e53a2e179a..4d25143cffaf4 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13176,6 +13176,9 @@ class Sema final : public SemaBase {
/// We are performing partial ordering for template template parameters.
PartialOrderingTTP,
+
+ /// We are instantiating an expansion statement.
+ ExpansionStmtInstantiation,
} Kind;
/// Whether we're substituting into constraints.
@@ -13371,6 +13374,12 @@ class Sema final : public SemaBase {
concepts::Requirement *Req,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are substituting the body of an expansion statement.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ CXXExpansionStmtPattern *ExpansionStmt,
+ ArrayRef<TemplateArgument> TArgs,
+ SourceRange InstantiationRange);
+
/// \brief Note that we are checking the satisfaction of the constraint
/// expression inside of a nested requirement.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -15643,6 +15652,19 @@ class Sema final : public SemaBase {
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps);
StmtResult FinishCXXExpansionStmt(Stmt *Expansion, Stmt *Body);
+
+ StmtResult BuildCXXEnumeratingExpansionStmtPattern(Decl *ESD, Stmt *Init,
+ Stmt *ExpansionVar,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation RParenLoc);
+
+ ExprResult
+ BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+ Expr *Idx);
+
+ std::optional<uint64_t>
+ ComputeExpansionSize(CXXExpansionStmtPattern *Expansion);
///@}
};
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index e0c1d304e8290..75d5a76c04a32 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -476,6 +476,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
return "TypeAliasTemplateInstantiation";
case CodeSynthesisContext::PartialOrderingTTP:
return "PartialOrderingTTP";
+ case CodeSynthesisContext::ExpansionStmtInstantiation:
+ return "ExpansionStmtInstantiation";
}
return "";
}
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index c74ed63d3295a..acb28d6bbdcfb 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -24,6 +24,23 @@
using namespace clang;
using namespace sema;
+// Build a 'DeclRefExpr' designating the template parameter '__N'.
+static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
+ return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
+ S.Context.getPointerDiffType(), VK_PRValue,
+ ESD->getBeginLoc());
+}
+
+static bool FinaliseExpansionVar(Sema &S, VarDecl *ExpansionVar,
+ ExprResult Initializer) {
+ if (Initializer.isInvalid()) {
+ S.ActOnInitializerError(ExpansionVar);
+ return true;
+ }
+
+ S.AddInitializerToDecl(ExpansionVar, Initializer.get(), /*DirectInit=*/false);
+ return ExpansionVar->isInvalidDecl();
+}
CXXExpansionStmtDecl *
Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth,
@@ -69,13 +86,147 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern(
Expr *ExpansionInitializer, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation RParenLoc,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) {
+ if (!ExpansionInitializer || !ExpansionVarStmt)
+ return StmtError();
+
+ assert(CurContext->isExpansionStmt());
+ auto *DS = cast<DeclStmt>(ExpansionVarStmt);
+ if (!DS->isSingleDecl()) {
+ Diag(DS->getBeginLoc(), diag::err_type_defined_in_for_range);
+ return StmtError();
+ }
+
+ VarDecl *ExpansionVar = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!ExpansionVar || ExpansionVar->isInvalidDecl() ||
+ ExpansionInitializer->containsErrors())
+ return StmtError();
+
+ // This is an enumerating expansion statement.
+ if (auto *ILE = dyn_cast<CXXExpansionInitListExpr>(ExpansionInitializer)) {
+ ExprResult Initializer =
+ BuildCXXExpansionInitListSelectExpr(ILE, BuildIndexDRE(*this, ESD));
+ if (FinaliseExpansionVar(*this, ExpansionVar, Initializer))
+ return StmtError();
+
+ // Note that lifetime extension only applies to destructuring expansion
+ // statements, so we just ignore 'LifetimeExtendedTemps' entirely for other
+ // types of expansion statements (this is CWG 3043).
+ return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc,
+ ColonLoc, RParenLoc);
+ }
+
Diag(ESD->getLocation(), diag::err_expansion_statements_todo);
return StmtError();
}
+StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern(
+ Decl *ESD, Stmt *Init, Stmt *ExpansionVar, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation RParenLoc) {
+ return new (Context) CXXEnumeratingExpansionStmtPattern(
+ cast<CXXExpansionStmtDecl>(ESD), Init, cast<DeclStmt>(ExpansionVar),
+ LParenLoc, ColonLoc, RParenLoc);
+}
+
StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
if (!Exp || !Body)
return StmtError();
+ auto *Expansion = cast<CXXExpansionStmtPattern>(Exp);
+ assert(!Expansion->getDecl()->getInstantiations() &&
+ "should not rebuild expansion statement after instantiation");
+
+ Expansion->setBody(Body);
+ if (Expansion->hasDependentSize())
+ return Expansion;
+
+ // This can fail if this is an iterating expansion statement.
+ std::optional<uint64_t> NumInstantiations = ComputeExpansionSize(Expansion);
+ if (!NumInstantiations)
+ return StmtError();
+
+ // Collect shared statements.
+ SmallVector<Stmt *, 1> Shared;
+ if (Expansion->getInit())
+ Shared.push_back(Expansion->getInit());
+
+ assert(isa<CXXEnumeratingExpansionStmtPattern>(Expansion) && "TODO");
+
+ // Return an empty statement if the range is empty.
+ if (*NumInstantiations == 0) {
+ Expansion->getDecl()->setInstantiations(
+ CXXExpansionStmtInstantiation::Create(
+ Context, Expansion->getBeginLoc(), Expansion->getEndLoc(),
+ /*Instantiations=*/{}, Shared,
+ isa<CXXDestructuringExpansionStmtPattern>(Expansion)));
+ return Expansion;
+ }
+
+ // Create a compound statement binding the expansion variable and body.
+ Stmt *VarAndBody[] = {Expansion->getExpansionVarStmt(), Body};
+ Stmt *CombinedBody =
+ CompoundStmt::Create(Context, VarAndBody, FPOptionsOverride(),
+ Body->getBeginLoc(), Body->getEndLoc());
+
+ // Expand the body for each instantiation.
+ SmallVector<Stmt *, 4> Instantiations;
+ CXXExpansionStmtDecl *ESD = Expansion->getDecl();
+ for (uint64_t I = 0; I < *NumInstantiations; ++I) {
+ // Now that we're expanding this, exit the context of the expansion stmt
+ // so that we no longer treat this as dependent.
+ ContextRAII CtxGuard(*this, CurContext->getParent(),
+ /*NewThis=*/false);
+
+ TemplateArgument Arg{Context, llvm::APSInt::get(I),
+ Context.getPointerDiffType()};
+ MultiLevelTemplateArgumentList MTArgList(ESD, Arg, true);
+ MTArgList.addOuterRetainedLevels(
+ Expansion->getDecl()->getIndexTemplateParm()->getDepth());
+
+ LocalInstantiationScope LIScope(*this, /*CombineWithOuterScope=*/true);
+ NonSFINAEContext _(*this);
+ InstantiatingTemplate Inst(*this, Body->getBeginLoc(), Expansion, Arg,
+ Body->getSourceRange());
+
+ StmtResult Instantiation = SubstStmt(CombinedBody, MTArgList);
+ if (Instantiation.isInvalid())
+ return StmtError();
+ Instantiations.push_back(Instantiation.get());
+ }
+
+ auto *InstantiationsStmt = CXXExpansionStmtInstantiation::Create(
+ Context, Expansion->getBeginLoc(), Expansion->getEndLoc(), Instantiations,
+ Shared, isa<CXXDestructuringExpansionStmtPattern>(Expansion));
+
+ Expansion->getDecl()->setInstantiations(InstantiationsStmt);
+ return Expansion;
+}
+
+ExprResult
+Sema::BuildCXXExpansionInitListSelectExpr(CXXExpansionInitListExpr *Range,
+ Expr *Idx) {
+ if (Range->containsPackExpansion() || Idx->isValueDependent())
+ return new (Context) CXXExpansionInitListSelectExpr(Context, Range, Idx);
+
+ // The index is a DRE to a template parameter; we should never
+ // fail to evaluate it.
+ Expr::EvalResult ER;
+ if (!Idx->EvaluateAsInt(ER, Context))
+ llvm_unreachable("Failed to evaluate expansion index");
+
+ uint64_t I = ER.Val.getInt().getZExtValue();
+ return Range->getExprs()[I];
+}
+
+std::optional<uint64_t>
+Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) {
+ assert(!Expansion->hasDependentSize());
+
+ if (isa<CXXEnumeratingExpansionStmtPattern>(Expansion))
+ return cast<CXXExpansionInitListSelectExpr>(
+ Expansion->getExpansionVariable()->getInit())
+ ->getRangeExpr()
+ ->getExprs()
+ .size();
+
llvm_unreachable("TODO");
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 35205f40cbcef..5957af710d38e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -573,6 +573,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case PriorTemplateArgumentSubstitution:
case ConstraintsCheck:
case NestedRequirementConstraintsCheck:
+ case ExpansionStmtInstantiation:
return true;
case RequirementInstantiation:
@@ -759,6 +760,15 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
/*Template=*/nullptr, /*TemplateArgs=*/{}) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ CXXExpansionStmtPattern *ExpansionStmt, ArrayRef<TemplateArgument> TArgs,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ExpansionStmtInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/TArgs) {}
+
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
concepts::NestedRequirement *Req, ConstraintsCheck,
@@ -1260,6 +1270,9 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
<< /*isTemplateTemplateParam=*/true
<< Active->InstantiationRange);
break;
+ case CodeSynthesisContext::ExpansionStmtInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_expansion_stmt_instantiation_here);
}
}
}
@@ -1894,6 +1907,12 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
maybeInstantiateFunctionParameterToScope(PVD))
return nullptr;
+ if (isa<CXXExpansionStmtDecl>(D)) {
+ assert(SemaRef.CurrentInstantiationScope);
+ return cast<Decl *>(
+ *SemaRef.CurrentInstantiationScope->findInstantiationOf(D));
+ }
+
return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
}
@@ -2288,9 +2307,13 @@ ExprResult
TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E,
ValueDecl *PD) {
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found
- = getSema().CurrentInstantiationScope->findInstantiationOf(PD);
- assert(Found && "no instantiation for parameter pack");
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found =
+ getSema().CurrentInstantiationScope->getInstantiationOfIfExists(PD);
+
+ // This can happen when instantiating an expansion statement that contains
+ // a pack (e.g. `template for (auto x : {{ts...}})`).
+ if (!Found)
+ return E;
Decl *TransformedDecl;
if (DeclArgumentPack *Pack = dyn_cast<DeclArgumentPack *>(*Found)) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f8136c3c24a52..f88ddcb40adf7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2089,7 +2089,37 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Decl *TemplateDeclInstantiator::VisitCXXExpansionStmtDecl(
CXXExpansionStmtDecl *OldESD) {
- llvm_unreachable("TODO");
+ Decl *Index = VisitNonTypeTemplateParmDecl(OldESD->getIndexTemplateParm());
+ CXXExpansionStmtDecl *NewESD = SemaRef.BuildCXXExpansionStmtDecl(
+ Owner, OldESD->getBeginLoc(), cast<NonTypeTemplateParmDecl>(Index));
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldESD, NewESD);
+
+ // If this was already expanded, only instantiate the expansion and
+ // don't touch the unexpanded expansion statement.
+ if (CXXExpansionStmtInstantiation *OldInst = OldESD->getInstantiations()) {
+ StmtResult NewInst = SemaRef.SubstStmt(OldInst, TemplateArgs);
+ if (NewInst.isInvalid())
+ return nullptr;
+
+ NewESD->setInstantiations(NewInst.getAs<CXXExpansionStmtInstantiation>());
+ NewESD->setExpansionPattern(OldESD->getExpansionPattern());
+ return NewESD;
+ }
+
+ // Enter the scope of this expansion statement; don't do this if we've
+ // already expanded it, as in that case we no longer want to treat its
+ // content as dependent.
+ Sema::ContextRAII Context(SemaRef, NewESD, /*NewThis=*/false);
+
+ StmtResult Expansion =
+ SemaRef.SubstStmt(OldESD->getExpansionPattern(), TemplateArgs);
+ if (Expansion.isInvalid())
+ return nullptr;
+
+ // The code that handles CXXExpansionStmtPattern takes care of calling
+ // setInstantiation() on the ESD if there was an expansion.
+ NewESD->setExpansionPattern(cast<CXXExpansionStmtPattern>(Expansion.get()));
+ return NewESD;
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
@@ -7093,6 +7123,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// anonymous unions in class templates).
}
+ if (CurrentInstantiationScope) {
+ if (auto Found = CurrentInstantiationScope->getInstantiationOfIfExists(D))
+ if (auto *FD = dyn_cast<NamedDecl>(cast<Decl *>(*Found)))
+ return FD;
+ }
+
if (!ParentDependsOnArgs)
return D;
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 5b1aad3fa8470..b61148bf95738 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -912,10 +912,14 @@ bool Sema::CheckParameterPacksForExpansion(
unsigned NewPackSize, PendingPackExpansionSize = 0;
if (IsVarDeclPack) {
// Figure out whether we're instantiating to an argument pack or not.
+ //
+ // The instantiation may not exist; this can happen when instantiating an
+ // expansion statement that contains a pack (e.g.
+ // `template for (auto x : {{ts...}})`).
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
- CurrentInstantiationScope->findInstantiationOf(
+ CurrentInstantiationScope->getInstantiationOfIfExists(
cast<NamedDecl *>(ParmPack.first));
- if (isa<DeclArgumentPack *>(*Instantiation)) {
+ if (Instantiation && isa<DeclArgumentPack *>(*Instantiation)) {
// We could expand this function parameter pack.
NewPackSize = cast<DeclArgumentPack *>(*Instantiation)->size();
} else {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f181d0abb5dfd..825660fe8174e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -67,6 +67,15 @@ struct UnexpandedInfo {
bool ExpandUnderForgetSubstitions = false;
};
+/// This contains the common parts that are instantiated for all expansion
+/// statement patterns.
+struct TransformCXXExpansionStmtPatternResult {
+ CXXExpansionStmtDecl *NewESD{};
+ Stmt *NewInit{};
+ DeclStmt *NewExpansionVarDecl{};
+ bool isValid() const { return NewESD != nullptr; }
+};
+
/// A semantic tree transformation that allows one to transform one
/// abstract syntax tree into another.
///
@@ -857,6 +866,9 @@ class TreeTransform {
StmtResult TransformOMPInformationalDirective(OMPExecutableDirective *S);
+ TransformCXXExpansionStmtPatternResult
+ TransformCXXExpansionStmtPatternCommonParts(CXXExpansionStmtPattern *S);
+
// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
// amount of stack usage with clang.
#define STMT(Node, Parent) \
@@ -9292,10 +9304,49 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
}
+template <typename Derived>
+TransformCXXExpansionStmtPatternResult
+TreeTransform<Derived>::TransformCXXExpansionStmtPatternCommonParts(
+ CXXExpansionStmtPattern *S) {
+ Decl *ESD =
+ getDerived().TransformDecl(S->getDecl()->getLocation(), S->getDecl());
+ if (!ESD || ESD->isInvalidDecl())
+ return {};
+
+ Stmt *Init = S->getInit();
+ if (Init) {
+ StmtResult SR = getDerived().TransformStmt(Init);
+ if (SR.isInvalid())
+ return {};
+ Init = SR.get();
+ }
+
+ StmtResult ExpansionVar =
+ getDerived().TransformStmt(S->getExpansionVarStmt());
+ if (ExpansionVar.isInvalid())
+ return {};
+
+ return {cast<CXXExpansionStmtDecl>(ESD), Init,
+ ExpansionVar.getAs<DeclStmt>()};
+}
+
template <typename Derived>
StmtResult TreeTransform<Derived>::TransformCXXEnumeratingExpansionStmtPattern(
CXXEnumeratingExpansionStmtPattern *S) {
- llvm_unreachable("TOOD");
+ TransformCXXExpansionStmtPatternResult Common =
+ TransformCXXExpansionStmtPatternCommonParts(S);
+ if (!Common.isValid())
+ return StmtError();
+
+ auto *Expansion = new (SemaRef.Context) CXXEnumeratingExpansionStmtPattern(
+ Common.NewESD, Common.NewInit, Common.NewExpansionVarDecl,
+ S->getLParenLoc(), S->getColonLoc(), S->getRParenLoc());
+
+ StmtResult Body = getDerived().TransformStmt(S->getBody());
+ if (Body.isInvalid())
+ return StmtError();
+
+ return SemaRef.FinishCXXExpansionStmt(Expansion, Body.get());
}
template <typename Derived>
@@ -9324,19 +9375,68 @@ TreeTransform<Derived>::TransformCXXDestructuringExpansionStmtPattern(
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformCXXExpansionInitListExpr(
CXXExpansionInitListExpr *E) {
- llvm_unreachable("TOOD");
+ bool ArgChanged = false;
+ SmallVector<Expr *> SubExprs;
+ if (getDerived().TransformExprs(E->getExprs().data(), E->getExprs().size(),
+ false, SubExprs, &ArgChanged))
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && !ArgChanged)
+ return E;
+
+ return CXXExpansionInitListExpr::Create(SemaRe...
[truncated]
|
🐧 Linux x64 Test Results
|
cd40ea9 to
c7cd02e
Compare
ad76ea8 to
c4c6899
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
c++26
clang:codegen
IR generation bugs: mangling, exceptions, etc.
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
clang
Clang issues not falling into any other category
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

This implements Sema and template instantiation for enumerating expansion statements, as well as expansion of expansion statements in general.