re PR c++/87481 (Endless loop with optimisation in C++17)
authorJakub Jelinek <jakub@redhat.com>
Fri, 22 Mar 2019 14:40:59 +0000 (15:40 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 22 Mar 2019 14:40:59 +0000 (15:40 +0100)
PR c++/87481
* doc/invoke.texi (-fconstexpr-ops-limit=): Document.

* c.opt (-fconstexpr-ops-limit=): New option.

* constexpr.c (struct constexpr_ctx): Add constexpr_ops_count member.
(cxx_eval_constant_expression): When not skipping, not constant class
or location wrapper, increment *ctx->constexpr_ops_count and if it is
above constexpr_loop_nest_limit, diagnose failure.
(cxx_eval_outermost_constant_expr): Add constexpr_ops_count and
initialize ctx.constexpr_ops_count to its address.
(is_sub_constant_expr): Likewise.

* g++.dg/cpp1y/constexpr-87481.C: New test.

From-SVN: r269874

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C [new file with mode: 0644]

index d85a8fcfba9b688dabf40083102e4dc9f72696ce..aa5530eb11f045062922b116ba4830835d9105d6 100644 (file)
@@ -1,3 +1,8 @@
+2019-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/87481
+       * doc/invoke.texi (-fconstexpr-ops-limit=): Document.
+
 2019-03-22  Bill Schmidt  <wschmidt@linux.ibm.com>
 
        * config/rs6000/mmintrin.h (_mm_sub_pi32): Fix typo.
index a597b12ce4cc978de28f554e6bc8457fa2c81b15..e10baba8a72ce8ab2efa7c62652857c4d4957256 100644 (file)
@@ -1,3 +1,8 @@
+2019-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/87481
+       * c.opt (-fconstexpr-ops-limit=): New option.
+
 2019-03-21  Jakub Jelinek  <jakub@redhat.com>
 
        * c-common.c (per_file_includes_t): Use false as Lazy in hash_set
index 962973ae6043875a3aa12b20123e676e8dcda6d2..0f39ebb3adaa77117bb626c9cd4cae9fcee5a7ba 100644 (file)
@@ -1416,6 +1416,10 @@ fconstexpr-loop-limit=
 C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) Init(262144)
 -fconstexpr-loop-limit=<number>        Specify maximum constexpr loop iteration count.
 
+fconstexpr-ops-limit=
+C++ ObjC++ Joined RejectNegative Host_Wide_Int Var(constexpr_ops_limit) Init(33554432)
+-fconstexpr-ops-limit=<number> Specify maximum number of constexpr operations during a single constexpr evaluation.
+
 fdebug-cpp
 C ObjC C++ ObjC++
 Emit debug annotations during preprocessing.
index 61cf384e732d06b1e5acb3d3f4a05f84077fcd89..71f9d67edbe76a38bb64e753afa52ff77e1447fd 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/87481
+       * constexpr.c (struct constexpr_ctx): Add constexpr_ops_count member.
+       (cxx_eval_constant_expression): When not skipping, not constant class
+       or location wrapper, increment *ctx->constexpr_ops_count and if it is
+       above constexpr_loop_nest_limit, diagnose failure.
+       (cxx_eval_outermost_constant_expr): Add constexpr_ops_count and
+       initialize ctx.constexpr_ops_count to its address.
+       (is_sub_constant_expr): Likewise.
+
 2019-03-21  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/71446
index 68e78d0cece2a619e119f67169a371ce8bf3a999..e92ec55317b6fcfbfb69429e70622806662d85a1 100644 (file)
@@ -1032,6 +1032,11 @@ struct constexpr_ctx {
   tree object;
   /* If inside SWITCH_EXPR.  */
   constexpr_switch_state *css_state;
+  /* Number of cxx_eval_constant_expression calls (except skipped ones,
+     on simple constants or location wrappers) encountered during current
+     cxx_eval_outermost_constant_expr call.  */
+  HOST_WIDE_INT *constexpr_ops_count;
+
   /* Whether we should error on a non-constant expression or fail quietly.  */
   bool quiet;
   /* Whether we are strictly conforming to constant expression rules or
@@ -4402,6 +4407,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
 
+  /* Avoid excessively long constexpr evaluations.  */
+  if (!location_wrapper_p (t)
+      && ++*ctx->constexpr_ops_count >= constexpr_ops_limit)
+    {
+      if (!ctx->quiet)
+       error_at (cp_expr_loc_or_loc (t, input_location),
+                 "%<constexpr%> evaluation operation count exceeds limit of "
+                 "%wd (use -fconstexpr-ops-limit= to increase the limit)",
+                 constexpr_ops_limit);
+      *ctx->constexpr_ops_count = INTTYPE_MINIMUM (HOST_WIDE_INT);
+      *non_constant_p = true;
+      return t;
+    }
+
   tree_code tcode = TREE_CODE (t);
   switch (tcode)
     {
@@ -5238,9 +5257,10 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
   bool non_constant_p = false;
   bool overflow_p = false;
   hash_map<tree,tree> map;
+  HOST_WIDE_INT constexpr_ctx_count = 0;
 
   constexpr_ctx ctx = { NULL, &map, NULL, NULL, NULL, NULL,
-                       allow_non_constant, strict,
+                       &constexpr_ctx_count, allow_non_constant, strict,
                        manifestly_const_eval || !allow_non_constant };
 
   tree type = initialized_type (t);
@@ -5382,9 +5402,11 @@ is_sub_constant_expr (tree t)
   bool non_constant_p = false;
   bool overflow_p = false;
   hash_map <tree, tree> map;
+  HOST_WIDE_INT constexpr_ops_count = 0;
 
   constexpr_ctx ctx
-    = { NULL, &map, NULL, NULL, NULL, NULL, true, true, false };
+    = { NULL, &map, NULL, NULL, NULL, NULL, &constexpr_ops_count,
+       true, true, false };
 
   instantiate_constexpr_fns (t);
   cxx_eval_constant_expression (&ctx, t, false, &non_constant_p,
index 0a941519dbc0ea76e6c63485900204da4a3efb5d..4735b0ab673794b971e44a3b25e2151c30997285 100644 (file)
@@ -210,7 +210,7 @@ in the following sections.
 @gccoptlist{-fabi-version=@var{n}  -fno-access-control @gol
 -faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new @gol
 -fconstexpr-depth=@var{n}  -fconstexpr-loop-limit=@var{n} @gol
--fno-elide-constructors @gol
+-fconstexpr-ops-limit=@var{n} -fno-elide-constructors @gol
 -fno-enforce-eh-specs @gol
 -fno-gnu-keywords @gol
 -fno-implicit-templates @gol
@@ -2525,6 +2525,16 @@ Set the maximum number of iterations for a loop in C++14 constexpr functions
 to @var{n}.  A limit is needed to detect infinite loops during
 constant expression evaluation.  The default is 262144 (1<<18).
 
+@item -fconstexpr-ops-limit=@var{n}
+@opindex fconstexpr-ops-limit
+Set the maximum number of operations during a single constexpr evaluation.
+Even when number of iterations of a single loop is limited with the above limit,
+if there are several nested loops and each of them has many iterations but still
+smaller than the above limit, or if in a body of some loop or even outside
+of a loop too many expressions need to be evaluated, the resulting constexpr
+evaluation might take too long.
+The default is 33554432 (1<<25).
+
 @item -fdeduce-init-list
 @opindex fdeduce-init-list
 Enable deduction of a template type parameter as
index 2fee0da53866d7cc26a97fa47476d6071a7ba696..febe7b3d863065bbd98e5b92aacb2e36aafb8bd9 100644 (file)
@@ -1,3 +1,8 @@
+2019-03-22  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/87481
+       * g++.dg/cpp1y/constexpr-87481.C: New test.
+
 2019-03-22  Simon Wright  <simon@pushface.org>
 
        PR ada/89583
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C
new file mode 100644 (file)
index 0000000..fc4decf
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/87481
+// { dg-do compile { target c++14 } }
+// { dg-options "-fconstexpr-loop-limit=98304 -fconstexpr-ops-limit=131072" } */
+
+constexpr unsigned
+foo ()
+{
+  unsigned int r = 0;
+  for (int i = 0; i < 65536; i++)
+    for (int j = 0; j < 65536; j++)
+      for (int k = 0; k < 65536; k++)  // { dg-error "'constexpr' evaluation operation count exceeds limit of 131072" "" { target *-*-* } 0 }
+       r += (i + j + k);
+  return r;
+}
+
+constexpr auto x = foo ();             // { dg-message "in 'constexpr' expansion of" }