From a15ffa22b5b541a385e509649dc39db59492bcdb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 22 Mar 2019 15:40:59 +0100 Subject: [PATCH] re PR c++/87481 (Endless loop with optimisation in C++17) 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 | 5 ++++ gcc/c-family/ChangeLog | 5 ++++ gcc/c-family/c.opt | 4 +++ gcc/cp/ChangeLog | 11 +++++++++ gcc/cp/constexpr.c | 26 ++++++++++++++++++-- gcc/doc/invoke.texi | 12 ++++++++- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C | 16 ++++++++++++ 8 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d85a8fcfba9..aa5530eb11f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2019-03-22 Jakub Jelinek + + PR c++/87481 + * doc/invoke.texi (-fconstexpr-ops-limit=): Document. + 2019-03-22 Bill Schmidt * config/rs6000/mmintrin.h (_mm_sub_pi32): Fix typo. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a597b12ce4c..e10baba8a72 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2019-03-22 Jakub Jelinek + + PR c++/87481 + * c.opt (-fconstexpr-ops-limit=): New option. + 2019-03-21 Jakub Jelinek * c-common.c (per_file_includes_t): Use false as Lazy in hash_set diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 962973ae604..0f39ebb3ada 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1416,6 +1416,10 @@ fconstexpr-loop-limit= C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) Init(262144) -fconstexpr-loop-limit= 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= Specify maximum number of constexpr operations during a single constexpr evaluation. + fdebug-cpp C ObjC C++ ObjC++ Emit debug annotations during preprocessing. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 61cf384e732..71f9d67edbe 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2019-03-22 Jakub Jelinek + + 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 PR c++/71446 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 68e78d0cece..e92ec55317b 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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), + "% 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 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 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, diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 0a941519dbc..4735b0ab673 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2fee0da5386..febe7b3d863 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-03-22 Jakub Jelinek + + PR c++/87481 + * g++.dg/cpp1y/constexpr-87481.C: New test. + 2019-03-22 Simon Wright 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 index 00000000000..fc4decf12bc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-87481.C @@ -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" } -- 2.30.2