c-common.c (max_constexpr_depth): New.
c-family/ * c-common.c (max_constexpr_depth): New. * c-common.h: Declare it. * c-opts.c (c_common_handle_option): Set it. * c.opt (fconstexpr-depth): New option. cp/ * semantics.c (push_cx_call_context): Return bool. (cxx_eval_call_expression): Handle excess depth. From-SVN: r171012
This commit is contained in:
parent
92d0652c1e
commit
17bc631c68
10 changed files with 85 additions and 33 deletions
|
@ -1,3 +1,10 @@
|
|||
2011-03-15 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c-common.c (max_constexpr_depth): New.
|
||||
* c-common.h: Declare it.
|
||||
* c-opts.c (c_common_handle_option): Set it.
|
||||
* c.opt (fconstexpr-depth): New option.
|
||||
|
||||
2011-03-11 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c-common.c (attribute_takes_identifier_p): Add missing const.
|
||||
|
|
|
@ -255,12 +255,15 @@ int flag_use_repository;
|
|||
enum cxx_dialect cxx_dialect = cxx98;
|
||||
|
||||
/* Maximum template instantiation depth. This limit exists to limit the
|
||||
time it takes to notice infinite template instantiations; the default
|
||||
value of 1024 is likely to be in the next C++ standard. */
|
||||
time it takes to notice excessively recursive template instantiations;
|
||||
the default value of 1024 is likely to be in the next C++ standard. */
|
||||
|
||||
int max_tinst_depth = 1024;
|
||||
|
||||
/* Likewise, for constexpr function call evaluations. N3225 specifies a
|
||||
minimum of 512. */
|
||||
|
||||
int max_constexpr_depth = 512;
|
||||
|
||||
/* The elements of `ridpointers' are identifier nodes for the reserved
|
||||
type names and storage classes. It is indexed by a RID_... value. */
|
||||
|
|
|
@ -619,10 +619,14 @@ extern enum cxx_dialect cxx_dialect;
|
|||
|
||||
/* Maximum template instantiation depth. This limit is rather
|
||||
arbitrary, but it exists to limit the time it takes to notice
|
||||
infinite template instantiations. */
|
||||
excessively recursive template instantiations. */
|
||||
|
||||
extern int max_tinst_depth;
|
||||
|
||||
/* Likewise, for constexpr function call evaluations. */
|
||||
|
||||
extern int max_constexpr_depth;
|
||||
|
||||
/* Nonzero means that we should not issue warnings about problems that
|
||||
occur when the code is executed, because the code being processed
|
||||
is not expected to be executed. This is set during parsing. This
|
||||
|
|
|
@ -568,6 +568,10 @@ c_common_handle_option (size_t scode, const char *arg, int value,
|
|||
disable_builtin_function (arg);
|
||||
break;
|
||||
|
||||
case OPT_fconstexpr_depth_:
|
||||
max_constexpr_depth = value;
|
||||
break;
|
||||
|
||||
case OPT_fdirectives_only:
|
||||
cpp_opts->directives_only = value;
|
||||
break;
|
||||
|
|
|
@ -719,6 +719,10 @@ fconstant-string-class=
|
|||
ObjC ObjC++ Joined MissingArgError(no class name specified with %qs)
|
||||
-fconst-string-class=<name> Use class <name> for constant strings
|
||||
|
||||
fconstexpr-depth=
|
||||
C++ ObjC++ Joined RejectNegative UInteger
|
||||
-constexpr-depth=<number> Specify maximum constexpr recursion depth
|
||||
|
||||
fdeduce-init-list
|
||||
C++ ObjC++ Var(flag_deduce_init_list) Init(1)
|
||||
-fno-deduce-init-list disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
2011-03-15 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* semantics.c (push_cx_call_context): Return bool.
|
||||
(cxx_eval_call_expression): Handle excess depth.
|
||||
|
||||
Core 1191
|
||||
* method.c (synthesized_method_walk): Cleanups don't affect the
|
||||
triviality of a constructor, but do affect deletion and exception
|
||||
|
|
|
@ -5922,17 +5922,21 @@ cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t,
|
|||
/* Variables and functions to manage constexpr call expansion context.
|
||||
These do not need to be marked for PCH or GC. */
|
||||
|
||||
/* FIXME remember and print actual constant arguments. */
|
||||
static VEC(tree,heap) *call_stack = NULL;
|
||||
static int call_stack_tick;
|
||||
static int last_cx_error_tick;
|
||||
|
||||
static void
|
||||
static bool
|
||||
push_cx_call_context (tree call)
|
||||
{
|
||||
++call_stack_tick;
|
||||
if (!EXPR_HAS_LOCATION (call))
|
||||
SET_EXPR_LOCATION (call, input_location);
|
||||
VEC_safe_push (tree, heap, call_stack, call);
|
||||
if (VEC_length (tree, call_stack) > (unsigned) max_constexpr_depth)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -5967,6 +5971,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
|
|||
tree result;
|
||||
constexpr_call new_call = { NULL, NULL, NULL, 0 };
|
||||
constexpr_call **slot;
|
||||
constexpr_call *entry;
|
||||
bool depth_ok;
|
||||
|
||||
if (TREE_CODE (fun) != FUNCTION_DECL)
|
||||
{
|
||||
/* Might be a constexpr function pointer. */
|
||||
|
@ -6029,7 +6036,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
|
|||
if (*non_constant_p)
|
||||
return t;
|
||||
|
||||
push_cx_call_context (t);
|
||||
depth_ok = push_cx_call_context (t);
|
||||
|
||||
new_call.hash
|
||||
= iterative_hash_template_arg (new_call.bindings,
|
||||
|
@ -6039,37 +6046,43 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
|
|||
maybe_initialize_constexpr_call_table ();
|
||||
slot = (constexpr_call **)
|
||||
htab_find_slot (constexpr_call_table, &new_call, INSERT);
|
||||
if (*slot != NULL)
|
||||
{
|
||||
/* Calls which are in progress have their result set to NULL
|
||||
so that we can detect circular dependencies. */
|
||||
if ((*slot)->result == NULL)
|
||||
{
|
||||
if (!allow_non_constant)
|
||||
error ("call has circular dependency");
|
||||
(*slot)->result = result = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = (*slot)->result;
|
||||
if (result == error_mark_node && !allow_non_constant)
|
||||
/* Re-evaluate to get the error. */
|
||||
cxx_eval_constant_expression (&new_call, new_call.fundef->body,
|
||||
allow_non_constant, addr,
|
||||
non_constant_p);
|
||||
}
|
||||
}
|
||||
else
|
||||
entry = *slot;
|
||||
if (entry == NULL)
|
||||
{
|
||||
/* We need to keep a pointer to the entry, not just the slot, as the
|
||||
slot can move in the call to cxx_eval_builtin_function_call. */
|
||||
constexpr_call *entry = ggc_alloc_constexpr_call ();
|
||||
*slot = entry = ggc_alloc_constexpr_call ();
|
||||
*entry = new_call;
|
||||
*slot = entry;
|
||||
result
|
||||
= cxx_eval_constant_expression (&new_call, new_call.fundef->body,
|
||||
allow_non_constant, addr,
|
||||
non_constant_p);
|
||||
}
|
||||
/* Calls which are in progress have their result set to NULL
|
||||
so that we can detect circular dependencies. */
|
||||
else if (entry->result == NULL)
|
||||
{
|
||||
if (!allow_non_constant)
|
||||
error ("call has circular dependency");
|
||||
*non_constant_p = true;
|
||||
entry->result = result = error_mark_node;
|
||||
}
|
||||
|
||||
if (!depth_ok)
|
||||
{
|
||||
if (!allow_non_constant)
|
||||
error ("constexpr evaluation depth exceeds maximum of %d (use "
|
||||
"-fconstexpr-depth= to increase the maximum)",
|
||||
max_constexpr_depth);
|
||||
*non_constant_p = true;
|
||||
entry->result = result = error_mark_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = entry->result;
|
||||
if (!result || (result == error_mark_node && !allow_non_constant))
|
||||
result = (cxx_eval_constant_expression
|
||||
(&new_call, new_call.fundef->body,
|
||||
allow_non_constant, addr,
|
||||
non_constant_p));
|
||||
if (result == error_mark_node)
|
||||
*non_constant_p = true;
|
||||
if (*non_constant_p)
|
||||
entry->result = result = error_mark_node;
|
||||
else
|
||||
|
|
|
@ -181,7 +181,7 @@ in the following sections.
|
|||
@item C++ Language Options
|
||||
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
|
||||
@gccoptlist{-fabi-version=@var{n} -fno-access-control -fcheck-new @gol
|
||||
-fconserve-space -ffriend-injection @gol
|
||||
-fconserve-space -fconstexpr-depth=@var{n} -ffriend-injection @gol
|
||||
-fno-elide-constructors @gol
|
||||
-fno-enforce-eh-specs @gol
|
||||
-ffor-scope -fno-for-scope -fno-gnu-keywords @gol
|
||||
|
@ -1881,6 +1881,13 @@ two definitions were merged.
|
|||
This option is no longer useful on most targets, now that support has
|
||||
been added for putting variables into BSS without making them common.
|
||||
|
||||
@item -fconstexpr-depth=@var{n}
|
||||
@opindex fconstexpr-depth
|
||||
Set the maximum nested evaluation depth for C++0x constexpr functions
|
||||
to @var{n}. A limit is needed to detect endless recursion during
|
||||
constant expression evaluation. The minimum specified by the standard
|
||||
is 512; G++ defaults to 1024.
|
||||
|
||||
@item -fno-deduce-init-list
|
||||
@opindex fno-deduce-init-list
|
||||
Disable deduction of a template type parameter as
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
2011-03-15 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/cpp0x/constexpr-recursion.C: New.
|
||||
|
||||
* g++.dg/cpp0x/implicit11.C: New.
|
||||
|
||||
2011-03-15 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
|
||||
|
|
5
gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C
Normal file
5
gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Test that we catch excessive recursion.
|
||||
// { dg-options "-std=c++0x -fconstexpr-depth=5" }
|
||||
// { dg-prune-output "in constexpr expansion" }
|
||||
constexpr int f (int i) { return f (i-1); }
|
||||
constexpr int i = f(42); // { dg-error "constexpr evaluation depth" }
|
Loading…
Add table
Reference in a new issue