From 5ec2cd9f666a8d26ce62ee7ef6383948fafb1b35 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 25 Jul 2016 14:32:13 -0400 Subject: [PATCH] PR c++/65970 - constexpr infinite loop gcc/c-family/ * c.opt (fconstexpr-loop-limit): New. gcc/cp/ * constexpr.c (cxx_eval_loop_expr): Count iterations. * cp-gimplify.c (genericize_cp_loop): Use start_locus even for infinite loops. From-SVN: r238730 --- gcc/c-family/ChangeLog | 5 +++++ gcc/c-family/c.opt | 4 ++++ gcc/cp/ChangeLog | 5 +++++ gcc/cp/constexpr.c | 11 +++++++++++ gcc/cp/cp-gimplify.c | 9 +-------- gcc/doc/invoke.texi | 9 ++++++++- gcc/testsuite/g++.dg/cpp1y/constexpr-loop6.C | 11 +++++++++++ 7 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-loop6.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 5c193051824..72ccd035c99 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2016-07-25 Jason Merrill + + PR c++/65970 + * c.opt (fconstexpr-loop-limit): New. + 2016-07-22 Martin Sebor PR c++/71675 diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 8c701523c38..a5358ededb3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1174,6 +1174,10 @@ fconstexpr-depth= C++ ObjC++ Joined RejectNegative UInteger Var(max_constexpr_depth) Init(512) -fconstexpr-depth= Specify maximum constexpr recursion depth. +fconstexpr-loop-limit= +C++ ObjC++ Joined RejectNegative UInteger Var(constexpr_loop_limit) Init(262144) +-fconstexpr-loop-limit= Specify maximum constexpr loop iteration count. + fdebug-cpp C ObjC C++ ObjC++ Emit debug annotations during preprocessing. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a540d31133b..5854205b3b7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,10 @@ 2016-07-25 Jason Merrill + PR c++/65970 + * constexpr.c (cxx_eval_loop_expr): Count iterations. + * cp-gimplify.c (genericize_cp_loop): Use start_locus even for + infinite loops. + PR c++/71972 * constexpr.c (cxx_eval_array_reference): Handle looking for the value of an element we're currently modifying. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 47fb39b4243..6bcb41ae825 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3468,6 +3468,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, constexpr_ctx new_ctx = *ctx; tree body = TREE_OPERAND (t, 0); + int count = 0; do { hash_set save_exprs; @@ -3480,6 +3481,16 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, for (hash_set::iterator iter = save_exprs.begin(); iter != save_exprs.end(); ++iter) new_ctx.values->remove (*iter); + if (++count >= constexpr_loop_limit) + { + if (!ctx->quiet) + error_at (EXPR_LOC_OR_LOC (t, input_location), + "constexpr loop iteration count exceeds limit of %d " + "(use -fconstexpr-loop-limit= to increase the limit)", + constexpr_loop_limit); + *non_constant_p = true; + break; + } } while (!returns (jump_target) && !breaks (jump_target) && !*non_constant_p); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 59953a6ee04..d9f7ceaed50 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -264,14 +264,7 @@ genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body, loop = stmt_list; } else - { - location_t loc = start_locus; - if (!cond || integer_nonzerop (cond)) - loc = EXPR_LOCATION (expr_first (body)); - if (loc == UNKNOWN_LOCATION) - loc = start_locus; - loop = build1_loc (loc, LOOP_EXPR, void_type_node, stmt_list); - } + loop = build1_loc (start_locus, LOOP_EXPR, void_type_node, stmt_list); stmt_list = NULL; append_to_statement_list (loop, &stmt_list); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9e0f07eb542..79c842df6b3 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -191,7 +191,8 @@ in the following sections. @xref{C++ Dialect Options,,Options Controlling C++ Dialect}. @gccoptlist{-fabi-version=@var{n} -fno-access-control @gol -fargs-in-order=@var{n} -fcheck-new @gol --fconstexpr-depth=@var{n} -ffriend-injection @gol +-fconstexpr-depth=@var{n} -fconstexpr-loop-limit=@var{n} @gol +-ffriend-injection @gol -fno-elide-constructors @gol -fno-enforce-eh-specs @gol -ffor-scope -fno-for-scope -fno-gnu-keywords @gol @@ -2265,6 +2266,12 @@ to @var{n}. A limit is needed to detect endless recursion during constant expression evaluation. The minimum specified by the standard is 512. +@item -fconstexpr-loop-limit=@var{n} +@opindex fconstexpr-loop-limit +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 -fdeduce-init-list @opindex fdeduce-init-list Enable deduction of a template type parameter as diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-loop6.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop6.C new file mode 100644 index 00000000000..e49e53193d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-loop6.C @@ -0,0 +1,11 @@ +// PR c++/65970 +// { dg-do compile { target c++14 } } +// { dg-options -fconstexpr-loop-limit=5 } + +constexpr int foo() { + while (true) // { dg-error "-fconstexpr-loop-limit" } + ; + return 0; +} + +constexpr int i = foo(); // { dg-message "" } -- 2.30.2