Upstream-Status: Inappropriate [Backport] From 21e7558c6e06c35620e80478f4e6b5ccd1c78aa9 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 29 Mar 2011 14:24:42 +0000 Subject: [PATCH 025/200] c-family/ * c.opt (fconstexpr-depth): New option. cp/ * semantics.c (push_cx_call_context): Return bool. (cxx_eval_call_expression): Handle excess depth. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@171666 138bc75d-0d04-0410-961f-82ee72b054a4 index fe746e2..4c4727f 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -719,6 +719,10 @@ fconstant-string-class= ObjC ObjC++ Joined MissingArgError(no class name specified with %qs) -fconst-string-class= Use class for constant strings +fconstexpr-depth= +C++ ObjC++ Joined RejectNegative UInteger Var(max_constexpr_depth) Init(512) +-fconstexpr-depth= 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 index 5fe1414..3213483 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 5478f79..4bcf83a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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. + @item -fno-deduce-init-list @opindex fno-deduce-init-list Disable deduction of a template type parameter as new file mode 100644 index 0000000..2f9b488 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C @@ -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" } -- 1.7.0.4