[llvm-branch-commits] [clang] [Clang] [C++26] Expansion Statements (Part 10) (PR #169689)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Nov 26 09:13:17 PST 2025
https://github.com/Sirraide created https://github.com/llvm/llvm-project/pull/169689
None
>From 7314e796fbe132dcac2692f06705bdbd96b27b73 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
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<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the maximum number of steps in constexpr function evaluation (0 = no limit)">,
MarshallingInfoInt<LangOpts<"ConstexprStepLimit">, "1048576">;
+def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group<f_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set the maximum number of times a single expansion statement may be expanded (0 = no limit)">,
+ MarshallingInfoInt<LangOpts<"MaxTemplateForExpansions">, "256">;
def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-constant-interpreter">, Group<f_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<BindingDecl *> 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, *NumInstantiations, Expansion->getColonLoc()))
+ return StmtError();
+
// Collect shared statements.
SmallVector<Stmt *, 1> Shared;
if (Expansion->getInit())
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
new file mode 100644
index 0000000000000..8411d6987565c
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify
+
+void g(int);
+
+template <__SIZE_TYPE__ size>
+struct String {
+ char data[size];
+
+ template <__SIZE_TYPE__ n>
+ constexpr String(const char (&str)[n]) { __builtin_memcpy(data, str, n); }
+
+ constexpr const char* begin() const { return data; }
+ constexpr const char* end() const { return data + size - 1; }
+};
+
+template <__SIZE_TYPE__ n>
+String(const char (&str)[n]) -> String<n>;
+
+template <typename T, __SIZE_TYPE__ size>
+struct Array {
+ T data[size]{};
+ constexpr const T* begin() const { return data; }
+ constexpr const T* end() const { return data + size; }
+};
+
+void expansion_size() {
+ static constexpr Array<int, 32> almost_too_big;
+ template for (auto x : almost_too_big) g(x);
+ template for (constexpr auto x : almost_too_big) g(x);
+
+ static constexpr Array<int, 33> too_big;
+ template for (auto x : too_big) g(x); // expected-error {{expansion size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+ template for (constexpr auto x : too_big) g(x); // expected-error {{expansion size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+
+ static constexpr String big{"1234567890123456789012345678901234567890234567890"};
+ template for (auto x : big) g(x); // expected-error {{expansion size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+ template for (constexpr auto x : big) g(x); // expected-error {{expansion size 49 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+
+ template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32}) g(x);
+ template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32}) g(x);
+
+ template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33}) g(x);
+ template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // expected-error {{expansion size 33 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33}) g(x);
+
+ int huge[1'000'000'000];
+ template for (auto x : huge) {} // expected-error {{expansion size 1000000000 exceeds maximum configured size 32}} expected-note {{use -fexpansion-limit=N to adjust this limit}}
+}
+
+void array_too_big() {
+ int ok[32];
+ int too_big[33];
+
+ template for (auto x : ok) {}
+ template for (auto x : too_big) {} // expected-error {{expansion size 33 exceeds maximum configured size 32}} \
+ expected-note {{use -fexpansion-limit=N to adjust this limit}}
+}
diff --git a/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp b/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
new file mode 100644
index 0000000000000..2c80c392e400d
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=0 -verify
+// expected-no-diagnostics
+
+// Test that passing =0 disables the limit.
+
+void big() {
+ int ok[500];
+ template for (auto x : ok) {}
+}
More information about the llvm-branch-commits
mailing list