Skip to content

Commit 8e22321

Browse files
committed
[Clang] [C++26] Expansion Statements (Part 10)
1 parent 0a945e6 commit 8e22321

File tree

7 files changed

+105
-0
lines changed

7 files changed

+105
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ def note_constexpr_assert_failed : Note<
167167
"assertion failed during evaluation of constant expression">;
168168
def err_expansion_size_expr_not_ice : Error<
169169
"expansion size is not a constant expression">;
170+
def err_expansion_too_big : Error<
171+
"expansion size %0 exceeds maximum configured size %1">;
172+
def note_use_fexpansion_limit : Note<
173+
"use -fexpansion-limit=N to adjust this limit">;
170174

171175
// Semantic analysis of constant literals.
172176
def ext_predef_outside_function : Warning<

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ LANGOPT(ConstexprCallDepth, 32, 512, Benign,
377377
"maximum constexpr call depth")
378378
LANGOPT(ConstexprStepLimit, 32, 1048576, Benign,
379379
"maximum constexpr evaluation steps")
380+
LANGOPT(MaxTemplateForExpansions, 32, 256, Benign, "maximum template for expansions")
380381
LANGOPT(EnableNewConstInterp, 1, 0, Benign,
381382
"enable the experimental new constant interpreter")
382383
LANGOPT(BracketDepth, 32, 256, Benign,

clang/include/clang/Options/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,6 +2054,10 @@ def fconstexpr_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>,
20542054
Visibility<[ClangOption, CC1Option]>,
20552055
HelpText<"Set the maximum number of steps in constexpr function evaluation (0 = no limit)">,
20562056
MarshallingInfoInt<LangOpts<"ConstexprStepLimit">, "1048576">;
2057+
def fexpansion_limit_EQ : Joined<["-"], "fexpansion-limit=">, Group<f_Group>,
2058+
Visibility<[ClangOption, CC1Option]>,
2059+
HelpText<"Set the maximum number of times a single expansion statement may be expanded (0 = no limit)">,
2060+
MarshallingInfoInt<LangOpts<"MaxTemplateForExpansions">, "256">;
20572061
def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-constant-interpreter">, Group<f_Group>,
20582062
HelpText<"Enable the experimental new constant interpreter">,
20592063
Visibility<[ClangOption, CC1Option]>,

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6358,6 +6358,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
63586358
Args.AddLastArg(CmdArgs, options::OPT_foperator_arrow_depth_EQ);
63596359
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
63606360
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
6361+
Args.AddLastArg(CmdArgs, options::OPT_fexpansion_limit_EQ);
63616362

63626363
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
63636364

clang/lib/Sema/SemaExpand.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ struct IterableExpansionStmtData {
4444
};
4545
} // namespace
4646

47+
static bool CheckExpansionSize(Sema &S, uint64_t NumInstantiations,
48+
SourceLocation Loc) {
49+
unsigned Max = S.LangOpts.MaxTemplateForExpansions;
50+
if (Max != 0 && NumInstantiations > Max) {
51+
S.Diag(Loc, diag::err_expansion_too_big) << NumInstantiations << Max;
52+
S.Diag(Loc, diag::note_use_fexpansion_limit);
53+
return true;
54+
}
55+
56+
return false;
57+
}
58+
4759
// Build a 'DeclRefExpr' designating the template parameter '__N'.
4860
static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) {
4961
return S.BuildDeclRefExpr(ESD->getIndexTemplateParm(),
@@ -216,6 +228,9 @@ static StmtResult BuildDestructuringCXXExpansionStmt(
216228
return StmtError();
217229
}
218230

231+
if (CheckExpansionSize(S, *Arity, ColonLoc))
232+
return StmtError();
233+
219234
QualType AutoRRef = S.Context.getAutoRRefDeductType();
220235
SmallVector<BindingDecl *> Bindings;
221236
for (unsigned I = 0; I < *Arity; ++I)
@@ -441,6 +456,9 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) {
441456
if (!NumInstantiations)
442457
return StmtError();
443458

459+
if (CheckExpansionSize(*this, *NumInstantiations, Expansion->getColonLoc()))
460+
return StmtError();
461+
444462
// Collect shared statements.
445463
SmallVector<Stmt *, 1> Shared;
446464
if (Expansion->getInit())
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify
2+
3+
void g(int);
4+
5+
template <__SIZE_TYPE__ size>
6+
struct String {
7+
char data[size];
8+
9+
template <__SIZE_TYPE__ n>
10+
constexpr String(const char (&str)[n]) { __builtin_memcpy(data, str, n); }
11+
12+
constexpr const char* begin() const { return data; }
13+
constexpr const char* end() const { return data + size - 1; }
14+
};
15+
16+
template <__SIZE_TYPE__ n>
17+
String(const char (&str)[n]) -> String<n>;
18+
19+
template <typename T, __SIZE_TYPE__ size>
20+
struct Array {
21+
T data[size]{};
22+
constexpr const T* begin() const { return data; }
23+
constexpr const T* end() const { return data + size; }
24+
};
25+
26+
void expansion_size() {
27+
static constexpr Array<int, 32> almost_too_big;
28+
template for (auto x : almost_too_big) g(x);
29+
template for (constexpr auto x : almost_too_big) g(x);
30+
31+
static constexpr Array<int, 33> too_big;
32+
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}}
33+
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}}
34+
35+
static constexpr String big{"1234567890123456789012345678901234567890234567890"};
36+
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}}
37+
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}}
38+
39+
template for (auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
40+
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
41+
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
42+
31, 32}) g(x);
43+
template for (constexpr auto x : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
44+
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
45+
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
46+
31, 32}) g(x);
47+
48+
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}}
49+
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
50+
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
51+
31, 32, 33}) g(x);
52+
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}}
53+
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
54+
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
55+
31, 32, 33}) g(x);
56+
57+
int huge[1'000'000'000];
58+
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}}
59+
}
60+
61+
void array_too_big() {
62+
int ok[32];
63+
int too_big[33];
64+
65+
template for (auto x : ok) {}
66+
template for (auto x : too_big) {} // expected-error {{expansion size 33 exceeds maximum configured size 32}} \
67+
expected-note {{use -fexpansion-limit=N to adjust this limit}}
68+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=0 -verify
2+
// expected-no-diagnostics
3+
4+
// Test that passing =0 disables the limit.
5+
6+
void big() {
7+
int ok[500];
8+
template for (auto x : ok) {}
9+
}

0 commit comments

Comments
 (0)