Commit 17bc631c by Jason Merrill Committed by Jason Merrill

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
parent 92d0652c
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> 2011-03-11 Jason Merrill <jason@redhat.com>
* c-common.c (attribute_takes_identifier_p): Add missing const. * c-common.c (attribute_takes_identifier_p): Add missing const.
......
...@@ -255,12 +255,15 @@ int flag_use_repository; ...@@ -255,12 +255,15 @@ int flag_use_repository;
enum cxx_dialect cxx_dialect = cxx98; enum cxx_dialect cxx_dialect = cxx98;
/* Maximum template instantiation depth. This limit exists to limit the /* Maximum template instantiation depth. This limit exists to limit the
time it takes to notice infinite template instantiations; the default time it takes to notice excessively recursive template instantiations;
value of 1024 is likely to be in the next C++ standard. */ the default value of 1024 is likely to be in the next C++ standard. */
int max_tinst_depth = 1024; 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 /* The elements of `ridpointers' are identifier nodes for the reserved
type names and storage classes. It is indexed by a RID_... value. */ type names and storage classes. It is indexed by a RID_... value. */
......
...@@ -619,10 +619,14 @@ extern enum cxx_dialect cxx_dialect; ...@@ -619,10 +619,14 @@ extern enum cxx_dialect cxx_dialect;
/* Maximum template instantiation depth. This limit is rather /* Maximum template instantiation depth. This limit is rather
arbitrary, but it exists to limit the time it takes to notice arbitrary, but it exists to limit the time it takes to notice
infinite template instantiations. */ excessively recursive template instantiations. */
extern int max_tinst_depth; 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 /* Nonzero means that we should not issue warnings about problems that
occur when the code is executed, because the code being processed occur when the code is executed, because the code being processed
is not expected to be executed. This is set during parsing. This 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, ...@@ -568,6 +568,10 @@ c_common_handle_option (size_t scode, const char *arg, int value,
disable_builtin_function (arg); disable_builtin_function (arg);
break; break;
case OPT_fconstexpr_depth_:
max_constexpr_depth = value;
break;
case OPT_fdirectives_only: case OPT_fdirectives_only:
cpp_opts->directives_only = value; cpp_opts->directives_only = value;
break; break;
......
...@@ -719,6 +719,10 @@ fconstant-string-class= ...@@ -719,6 +719,10 @@ fconstant-string-class=
ObjC ObjC++ Joined MissingArgError(no class name specified with %qs) ObjC ObjC++ Joined MissingArgError(no class name specified with %qs)
-fconst-string-class=<name> Use class <name> for constant strings -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 fdeduce-init-list
C++ ObjC++ Var(flag_deduce_init_list) Init(1) 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 -fno-deduce-init-list disable deduction of std::initializer_list for a template type parameter from a brace-enclosed initializer-list
......
2011-03-15 Jason Merrill <jason@redhat.com> 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 Core 1191
* method.c (synthesized_method_walk): Cleanups don't affect the * method.c (synthesized_method_walk): Cleanups don't affect the
triviality of a constructor, but do affect deletion and exception 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, ...@@ -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. /* Variables and functions to manage constexpr call expansion context.
These do not need to be marked for PCH or GC. */ 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 VEC(tree,heap) *call_stack = NULL;
static int call_stack_tick; static int call_stack_tick;
static int last_cx_error_tick; static int last_cx_error_tick;
static void static bool
push_cx_call_context (tree call) push_cx_call_context (tree call)
{ {
++call_stack_tick; ++call_stack_tick;
if (!EXPR_HAS_LOCATION (call)) if (!EXPR_HAS_LOCATION (call))
SET_EXPR_LOCATION (call, input_location); SET_EXPR_LOCATION (call, input_location);
VEC_safe_push (tree, heap, call_stack, call); VEC_safe_push (tree, heap, call_stack, call);
if (VEC_length (tree, call_stack) > (unsigned) max_constexpr_depth)
return false;
return true;
} }
static void static void
...@@ -5967,6 +5971,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -5967,6 +5971,9 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
tree result; tree result;
constexpr_call new_call = { NULL, NULL, NULL, 0 }; constexpr_call new_call = { NULL, NULL, NULL, 0 };
constexpr_call **slot; constexpr_call **slot;
constexpr_call *entry;
bool depth_ok;
if (TREE_CODE (fun) != FUNCTION_DECL) if (TREE_CODE (fun) != FUNCTION_DECL)
{ {
/* Might be a constexpr function pointer. */ /* Might be a constexpr function pointer. */
...@@ -6029,7 +6036,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6029,7 +6036,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
if (*non_constant_p) if (*non_constant_p)
return t; return t;
push_cx_call_context (t); depth_ok = push_cx_call_context (t);
new_call.hash new_call.hash
= iterative_hash_template_arg (new_call.bindings, = iterative_hash_template_arg (new_call.bindings,
...@@ -6039,37 +6046,43 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t, ...@@ -6039,37 +6046,43 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
maybe_initialize_constexpr_call_table (); maybe_initialize_constexpr_call_table ();
slot = (constexpr_call **) slot = (constexpr_call **)
htab_find_slot (constexpr_call_table, &new_call, INSERT); htab_find_slot (constexpr_call_table, &new_call, INSERT);
if (*slot != NULL) entry = *slot;
{ if (entry == 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
{ {
/* We need to keep a pointer to the entry, not just the slot, as the /* 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. */ 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; *entry = new_call;
*slot = entry; }
result /* Calls which are in progress have their result set to NULL
= cxx_eval_constant_expression (&new_call, new_call.fundef->body, so that we can detect circular dependencies. */
allow_non_constant, addr, else if (entry->result == NULL)
non_constant_p); {
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) if (*non_constant_p)
entry->result = result = error_mark_node; entry->result = result = error_mark_node;
else else
......
...@@ -181,7 +181,7 @@ in the following sections. ...@@ -181,7 +181,7 @@ in the following sections.
@item C++ Language Options @item C++ Language Options
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}. @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
@gccoptlist{-fabi-version=@var{n} -fno-access-control -fcheck-new @gol @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-elide-constructors @gol
-fno-enforce-eh-specs @gol -fno-enforce-eh-specs @gol
-ffor-scope -fno-for-scope -fno-gnu-keywords @gol -ffor-scope -fno-for-scope -fno-gnu-keywords @gol
...@@ -1881,6 +1881,13 @@ two definitions were merged. ...@@ -1881,6 +1881,13 @@ two definitions were merged.
This option is no longer useful on most targets, now that support has This option is no longer useful on most targets, now that support has
been added for putting variables into BSS without making them common. 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 @item -fno-deduce-init-list
@opindex fno-deduce-init-list @opindex fno-deduce-init-list
Disable deduction of a template type parameter as Disable deduction of a template type parameter as
......
2011-03-15 Jason Merrill <jason@redhat.com> 2011-03-15 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/constexpr-recursion.C: New.
* g++.dg/cpp0x/implicit11.C: New. * g++.dg/cpp0x/implicit11.C: New.
2011-03-15 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com> 2011-03-15 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
......
// 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" }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment