[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
Sirraide wrote: > > Iirc when I was testing this it did 1 million expansions w/o hitting any > > existing limits; that was w/ an empty expansion statement but that already > > took a few seconds. > > That's fine - the limits are there to avoid overwhelming the compiler, not > because something might be slow I’m more worried about it taking even longer and someone mistakenly thinking that we have a bug in Clang or that the compiler is hanging when the bug would really be in user code in this case; iirc @AaronBallman has said in the past that the `constexpr` steps limit exists for a similar reason, so I thought it’d make sense to implement something similar for this. (side note: I don’t believe 1 million expansions would ever not be a bug candidly...) https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
cor3ntin wrote: > Iirc when I was testing this it did 1 million expansions w/o hitting any > existing limits; that was w/ an empty expansion statement but that already > took a few seconds. That's fine - the limits are there to avoid overwhelming the compiler, not because something might be slow https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From a45da7e323957753a53ae50176782d6520032ad7 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 +
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 +
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 73 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 110 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d954715da1f2f..70422ba1de723 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion statement size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion statement size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def err_iterating_expansion_stmt_unsupported : Error<
"iterating expansion statements are currently not supported">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index dd4c5a653d38b..7da7851085130 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -386,6 +386,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 16384, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 412683fd968b0..6819a2b582b89 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2159,6 +2159,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 86b0a705c7fe9..e7b16101943ae 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6563,6 +6563,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 40d780e79866c..8cc25b9a01679 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -42,6 +42,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter that is used as
// the expansion index
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
@@ -248,6 +260,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Cont
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From b83e5e8e24c1844a1fd50893bbc7dfdec9969480 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 69 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 106 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 59ff2571b1445..19af396628fa1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion statement size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion statement size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def note_iterating_expansion_stmt_iterator_requires_minus : Note<
"while attempting to construct 'begin - begin' with iterator type %0">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index dd4c5a653d38b..7da7851085130 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -386,6 +386,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 16384, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 412683fd968b0..6819a2b582b89 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2159,6 +2159,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 86b0a705c7fe9..e7b16101943ae 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6563,6 +6563,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fc72d90283c1d..c93bf9fe0cefd 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -42,6 +42,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter that is used as
// the expansion index
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
@@ -297,6 +309,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
Qua
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From b83e5e8e24c1844a1fd50893bbc7dfdec9969480 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 69 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 106 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 59ff2571b1445..19af396628fa1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion statement size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion statement size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def note_iterating_expansion_stmt_iterator_requires_minus : Note<
"while attempting to construct 'begin - begin' with iterator type %0">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index dd4c5a653d38b..7da7851085130 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -386,6 +386,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 16384, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 412683fd968b0..6819a2b582b89 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2159,6 +2159,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 86b0a705c7fe9..e7b16101943ae 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6563,6 +6563,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fc72d90283c1d..c93bf9fe0cefd 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -42,6 +42,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter that is used as
// the expansion index
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
@@ -297,6 +309,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
Qua
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
Sirraide wrote: > Is an actual performance concern here? > > Unlike recursive things it's bound to terminate, and it's not adding > recursion in itself - the limit from the compiler perspective is the number > of instantiations / objects in the declaration context. > > I expect people will want to iterate over the member of `::` or `::std` and > expect that to somehow work. > > So i think this is fine for now but we will probably have to adjust with use > cases Iirc when I was testing this it did 1 million expansions w/o hitting any existing limits; that was w/ an empty expansion statement but that already took a few seconds. https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/cor3ntin commented: Is an actual performance concern here? Unlike recursive things it's bound to terminate, and it's not adding recursion in itself - the limit from the compiler perspective is the number of instantiations / objects in the declaration context. I expect people will want to iterate over the member of `::` or `::std` and expect that to somehow work. So i think this is fine for now but we will probably have to adjust with use cases https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
Sirraide wrote: > > Perhaps we should look at some other imp limits that reflection might > > observe (field limit/arg limit/etc?), and see what number would cover all > > of those? > > field/argument limits is a good idea; I’ll look at those The limit for parameters in a function definition is 256 and for data members in a class it’s 16384; I went w/ the latter since it’s a reasonable number I think https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
erichkeane wrote: > > How did we derive the 'max' limit default? Experimentally, based on another > > limit, or in implimits? > > I candidly didn’t derive it at all when I first implemented this. I just > picked 256 as a placeholder value and was hoping that we could discuss this > and figure out what a reasonable limit should be 👀 > > > 1 million instantiations takes about 3 seconds provided the body of the > > expansion statement is empty > > Apparently, I did run some testing locally though, so maybe 1 million (or the > closest power of 2, i.e. `1 << 20`) would be a good value? Perhaps not that high :) I could definitely see something like 1024 being reasonable, but I otherwise lack much of a preference. 256 feels a little small, but it isn't clear to me what a reason size will be, particularly with reflection. Perhaps we should look at some other imp limits that reflection might observe (field limit/arg limit/etc?), and see what number would cover all of those? https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From cc3c4ef806dd4fb2a7f129cd874fe381817e0225 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 69 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 106 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ee53b489fce35..04eacce5e06ff 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def note_iterating_expansion_stmt_iterator_requires_minus : Note<
"while attempting to construct 'begin - begin' with iterator type %0">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 2c93e60b48cc5..64359db337f73 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -382,6 +382,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 6fc52384a6d1d..a4d80caff91f7 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2139,6 +2139,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 3b852528d92c4..a7bf52950435e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6525,6 +6525,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 27878377f934f..19caa88789cf0 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -298,6 +310,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From cc3c4ef806dd4fb2a7f129cd874fe381817e0225 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 69 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 106 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ee53b489fce35..04eacce5e06ff 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def note_iterating_expansion_stmt_iterator_requires_minus : Note<
"while attempting to construct 'begin - begin' with iterator type %0">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 2c93e60b48cc5..64359db337f73 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -382,6 +382,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 6fc52384a6d1d..a4d80caff91f7 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2139,6 +2139,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 3b852528d92c4..a7bf52950435e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6525,6 +6525,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 27878377f934f..19caa88789cf0 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -298,6 +310,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
github-actions[bot] wrote: # :penguin: Linux x64 Test Results * 87004 tests passed * 1328 tests skipped * 1 test failed ## Failed Tests (click on a test name to see its output) ### Clang Clang.SemaTemplate/GH176155.cpp ``` Exit Code: 1 Command Output (stdout): -- # RUN: at line 1 /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 -internal-isystem /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/23/include -nostdsysteminc -std=c++20 -fsyntax-only -verify /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp # executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 -internal-isystem /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/23/include -nostdsysteminc -std=c++20 -fsyntax-only -verify /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp # .---command stderr # | error: 'expected-error' diagnostics expected but not seen: # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 11 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:12): variable 'i' cannot be implicitly captured in a lambda with no capture-default specified # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 11 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:15): variable 'i' cannot be implicitly captured in a lambda with no capture-default specified # | error: 'expected-note' diagnostics expected but not seen: # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:6): while substituting into a lambda expression here # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:7): capture 'i' by value # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:7): capture 'i' by value # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:8): capture 'i' by reference # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:8): capture 'i' by reference # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:9): default capture by value # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:9): default capture by value # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:10): default capture by reference # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:10): default capture by reference # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 11 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:13): 'i' declared here # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:14): lambda expression begins here # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 11 (directive at /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp:16): 'i' declared here # | File /home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaTemplate/GH176155.cpp Line 5 (directive at /home/gha/actions-runner/_work/llvm-project/llv
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
github-actions[bot] wrote: # :window: Windows x64 Test Results * 53296 tests passed * 1029 tests skipped * 1 test failed ## Failed Tests (click on a test name to see its output) ### Clang Clang.SemaTemplate/GH176155.cpp ``` Exit Code: 1 Command Output (stdout): -- # RUN: at line 1 c:\_work\llvm-project\llvm-project\build\bin\clang.exe -cc1 -internal-isystem C:\_work\llvm-project\llvm-project\build\lib\clang\23\include -nostdsysteminc -std=c++20 -fsyntax-only -verify C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp # executed command: 'c:\_work\llvm-project\llvm-project\build\bin\clang.exe' -cc1 -internal-isystem 'C:\_work\llvm-project\llvm-project\build\lib\clang\23\include' -nostdsysteminc -std=c++20 -fsyntax-only -verify 'C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp' # .---command stderr # | error: 'expected-error' diagnostics expected but not seen: # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 11 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:12): variable 'i' cannot be implicitly captured in a lambda with no capture-default specified # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 11 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:15): variable 'i' cannot be implicitly captured in a lambda with no capture-default specified # | error: 'expected-note' diagnostics expected but not seen: # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:6): while substituting into a lambda expression here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:7): capture 'i' by value # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:7): capture 'i' by value # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:8): capture 'i' by reference # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:8): capture 'i' by reference # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:9): default capture by value # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:9): default capture by value # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:10): default capture by reference # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:10): default capture by reference # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 11 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:13): 'i' declared here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:14): lambda expression begins here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 11 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:16): 'i' declared here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 5 (directive at C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp:17): lambda expression begins here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 23: in instantiation of default argument for 'f' required here # | File C:\_work\llvm-project\llvm-project\clang\test\SemaTemplate\GH176155.cpp Line 26: while substituting deduced template arguments into function template 'f' # | 17 errors generated. # `- # error: command failed with exit status: 1 -- ``` 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/169689 __
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 82dc239df882b70017dde8de3dedebdeabe50c50 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 69 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 106 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ee53b489fce35..04eacce5e06ff 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
def note_iterating_expansion_stmt_iterator_requires_minus : Note<
"while attempting to construct 'begin - begin' with iterator type %0">;
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 2c93e60b48cc5..64359db337f73 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -382,6 +382,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 6fc52384a6d1d..a4d80caff91f7 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2139,6 +2139,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 3b852528d92c4..a7bf52950435e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6525,6 +6525,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 231f6e657e55e..0d66c9ec1de6b 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -306,6 +318,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 4fa5064b267bca9100fe2ab9678df253cdfcdf4f Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH 1/2] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6994cd88fba21..71e4a178fe21d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index c6841937c8d39..8af98ec6afb50 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2064,6 +2064,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 0380568412e62..331a388eac573 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6369,6 +6369,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 6fa1ad9856783..8ca2b074acbea 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -245,6 +257,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductTyp
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 4fa5064b267bca9100fe2ab9678df253cdfcdf4f Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH 1/2] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6994cd88fba21..71e4a178fe21d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index c6841937c8d39..8af98ec6afb50 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2064,6 +2064,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index 0380568412e62..331a388eac573 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6369,6 +6369,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 6fa1ad9856783..8ca2b074acbea 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -245,6 +257,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductTyp
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From e2a41057242421f63f0c3ef200bd447a1288409d Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bf6d017e845fc..7b0e9be0484b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 6fa1ad9856783..8ca2b074acbea 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -245,6 +257,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From e2a41057242421f63f0c3ef200bd447a1288409d Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bf6d017e845fc..7b0e9be0484b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 6fa1ad9856783..8ca2b074acbea 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -245,6 +257,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 8e22321c5540419bde23f07f64164cf6685d0f64 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bf6d017e845fc..7b0e9be0484b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 532797c68b534..cb284cf08a03b 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -216,6 +228,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 8e22321c5540419bde23f07f64164cf6685d0f64 Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bf6d017e845fc..7b0e9be0484b9 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index 532797c68b534..cb284cf08a03b 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -216,6 +228,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 6b112812d9df5a60984a352906b9a18db40e2a1e Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5115c175849e1..222d587b48a0b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -169,6 +169,10 @@ def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
def err_expansion_size_negative : Error<
"expansion size must not be negative (was %0)">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fcc951503deb9..ad481df7e7d6a 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -198,6 +210,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVecto
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 6b112812d9df5a60984a352906b9a18db40e2a1e Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5115c175849e1..222d587b48a0b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -169,6 +169,10 @@ def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
def err_expansion_size_negative : Error<
"expansion size must not be negative (was %0)">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fcc951503deb9..ad481df7e7d6a 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -198,6 +210,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVecto
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide updated
https://github.com/llvm/llvm-project/pull/169689
>From 9a24859aeed9d3ad198d2d57b34c96b653d0fa0f Mon Sep 17 00:00:00 2001
From: Sirraide
Date: Wed, 26 Nov 2025 17:41:45 +0100
Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 10)
---
.../clang/Basic/DiagnosticSemaKinds.td| 4 ++
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td| 4 ++
clang/lib/Driver/ToolChains/Clang.cpp | 1 +
clang/lib/Sema/SemaExpand.cpp | 18 +
.../SemaCXX/cxx2c-expansion-stmts-limit.cpp | 68 +++
.../SemaCXX/cxx2c-fexpansion-statements.cpp | 9 +++
7 files changed, 105 insertions(+)
create mode 100644 clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
create mode 100644 clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5115c175849e1..222d587b48a0b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -169,6 +169,10 @@ def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
def err_expansion_size_negative : Error<
"expansion size must not be negative (was %0)">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fcc951503deb9..ad481df7e7d6a 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -198,6 +210,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVecto
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide ready_for_review https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
llvmbot wrote:
@llvm/pr-subscribers-clang-codegen
Author: None (Sirraide)
Changes
---
Full diff: https://github.com/llvm/llvm-project/pull/169689.diff
7 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
- (modified) clang/include/clang/Basic/LangOptions.def (+1)
- (modified) clang/include/clang/Options/Options.td (+4)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1)
- (modified) clang/lib/Sema/SemaExpand.cpp (+18)
- (added) clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp (+68)
- (added) clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp (+9)
``diff
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5115c175849e1..222d587b48a0b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -169,6 +169,10 @@ def err_expansion_size_expr_not_ice : Error<
"expansion size is not a constant expression">;
def err_expansion_size_negative : Error<
"expansion size must not be negative (was %0)">;
+def err_expansion_too_big : Error<
+ "expansion size %0 exceeds maximum configured size %1">;
+def note_use_fexpansion_limit : Note<
+ "use -fexpansion-limit=N to adjust this limit">;
// Semantic analysis of constant literals.
def ext_predef_outside_function : Warning<
diff --git a/clang/include/clang/Basic/LangOptions.def
b/clang/include/clang/Basic/LangOptions.def
index 40fc66ea12e34..315cb4dc5e1cf 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
"maximum constexpr call depth")
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
"maximum constexpr evaluation steps")
+LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for
expansions")
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
"enable the experimental new constant interpreter")
LANGOPT(BracketDepth, 32, 256, Benign,
diff --git a/clang/include/clang/Options/Options.td
b/clang/include/clang/Options/Options.td
index 0e88656c5e1bc..86867b4814eeb 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"],
"fconstexpr-steps=">, Group,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation
(0 = no limit)">,
MarshallingInfoInt, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may
be expanded (0 = no limit)">,
+ MarshallingInfoInt, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"],
"fexperimental-new-constant-interpreter">, Group,
HelpText<"Enable the experimental new constant interpreter">,
Visibility<[ClangOption, CC1Option]>,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp
b/clang/lib/Driver/ToolChains/Clang.cpp
index c5d40c9825fab..649d4c3e4ca97 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction
&JA,
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
+ Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp
index fcc951503deb9..ad481df7e7d6a 100644
--- a/clang/lib/Sema/SemaExpand.cpp
+++ b/clang/lib/Sema/SemaExpand.cpp
@@ -43,6 +43,18 @@ struct IterableExpansionStmtData {
};
} // namespace
+static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
+ SourceLocation Loc) {
+ unsigned Max = S.LangOpts.MaxTemplateForExpansions;
+ if (Max != 0 && NumInstantiations > Max) {
+S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
+S.Diag(Loc, diag::note_use_fexpansion_limit);
+return true;
+ }
+
+ return false;
+}
+
// Build a 'DeclRefExpr' designating the template parameter '__N'.
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -198,6 +210,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
return StmtError();
}
+ if (CheckExpansionSize(S, *Arity, ColonLoc))
+return StmtError();
+
QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVector Bindings;
for (unsigned I = 0; I < *Arity; ++I)
@@ -399,6 +414,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt
*Body) {
if (!NumInstantiations)
return StmtError();
+ if (CheckExpansionSize(*this, *NumInstant
[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10: Expansion Limit) (PR #169689)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/169689 ___ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
