Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Options/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2064,6 +2064,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]>,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaExpand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -245,6 +257,9 @@ static StmtResult BuildDestructuringDecompositionDecl(
return StmtError();
}

if (CheckExpansionSize(S, *Arity, ColonLoc))
return StmtError();

QualType AutoRRef = S.Context.getAutoRRefDeductType();
SmallVector<BindingDecl *> Bindings;
for (unsigned I = 0; I < *Arity; ++I)
Expand Down Expand Up @@ -481,6 +496,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())
Expand Down
69 changes: 69 additions & 0 deletions clang/test/SemaCXX/cxx2c-expansion-stmts-limit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify
// RUN: %clang_cc1 %s -std=c++2c -fsyntax-only -fexpansion-limit=32 -verify -fexperimental-new-constant-interpreter

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}}
}
9 changes: 9 additions & 0 deletions clang/test/SemaCXX/cxx2c-fexpansion-statements.cpp
Original file line number Diff line number Diff line change
@@ -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) {}
}
Loading