c-common.c (max_constexpr_depth): New.
authorJason Merrill <jason@redhat.com>
Tue, 15 Mar 2011 18:29:00 +0000 (14:29 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 15 Mar 2011 18:29:00 +0000 (14:29 -0400)
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

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-opts.c
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C [new file with mode: 0644]

index 6b5fd91b0b6a1202537c4a584dc45a53c6585471..a0268fd5b5bfd8a8281113e412fd05ed6e5df747 100644 (file)
@@ -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.
index 4da9a2da0cadb28b2d5fc59d599969baff5d8ac9..6674c58ffabe343a1537621559f65d90714a204f 100644 (file)
@@ -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.  */
index 406def96e16fb59e2c35c14e164ed1688f52cad3..b6fcee9e2d60c72f7d6104d6e89fdc879d73582d 100644 (file)
@@ -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
index 8d6e6e7e24355cc9f2d12b6a91d5f7381a294e30..8d2a08bad9f9c7536dc1d8457627da5d35c547e4 100644 (file)
@@ -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;
index bb928fa914618e6a4d606ee14e95ffc8e84d8a43..f791190f9e810218f80917ca4630de5bbea4ffdf 100644 (file)
@@ -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
index 910a7e2bd9483e2f4582ecf732984ff0bbaadfb7..09ab014df09710d0e82c2ac6181cdbb0f6d39fd1 100644 (file)
@@ -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
index a0f48c0ed4559fceeecf2c8b9cf2e7590212b337..53497f39876b42aafb5964c16bda96347819a37b 100644 (file)
@@ -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
index aff5a0589567ff12bcb786a944c60be4cb4ab899..b498eaccc60f0674449eb26b62c745bb9a809fdf 100644 (file)
@@ -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
index 3d75d5ebb140931cb0d6e0a1851553b52e0231ab..09bdda97c5cebdd77e3348fef1a11a7c39309c7e 100644 (file)
@@ -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>
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-recursion.C
new file mode 100644 (file)
index 0000000..2f9b488
--- /dev/null
@@ -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" }