On 2/18/19 12:45 PM, Jakub Jelinek wrote:
Hi!

As mentioned in the PR, we've regressed on the trunk in diagnostics of some
invalid constexpr evaluations.  The problem is that the constexpr evaluation
is effectively done on post-cp_fold_function bodies/arguments and cp_fold
optimizes away some important trees for constexpr diagnostics, either
itself, or through using GENERIC match.pd (on the testcase in particular
diagnostics about reinterpret_cast).
While we save on constexpr call hash table bodies of the functions
pre-cp_fold_function, due to sharing and cp_fold_r the STATEMENT_LIST
statements etc. are modified directly and genericization modifies it as
well.

The following patch uses copy_fn which we have been using before the the
recursive constexpr cases also to make a copy of the constexpr function
before cp_fold_function clobbers it.
I had to implement cxx_eval_conditional_expression handling of various
C++ FE statements that are replaced during genericization.

Bootstrapped/regtested on x86_64-linux and i686-linux (98,11,14,17,2a), ok
for trunk?

2019-02-18  Jakub Jelinek  <ja...@redhat.com>

        PR c++/89285
        * constexpr.c (struct constexpr_fundef): Add parms and result members.
        (retrieve_constexpr_fundef): Adjust for the above change.
        (register_constexpr_fundef): Save constexpr body with copy_fn,
        temporarily set DECL_CONTEXT on DECL_RESULT before that.
        (get_fundef_copy): Change FUN argument to FUNDEF with
        constexpr_fundef * type, grab body and parms/result out of
        constexpr_fundef struct and temporarily change it for copy_fn calls
        too.
        (cxx_eval_builtin_function_call): For __builtin_FUNCTION temporarily
        adjust current_function_decl from ctx->call context.  For arith
        overflow builtins, don't test is_constant_expression on the result,
        instead test if arguments are suitable constant expressions.
        (cxx_bind_parameters_in_call): Grab parameters from new_call.  Undo
        convert_for_arg_passing changes for TREE_ADDRESSABLE type passing.
        (cxx_eval_call_expression): Adjust get_fundef_copy caller.
        (cxx_eval_conditional_expression): For IF_STMT, allow then or else
        operands to be NULL.
        (label_matches): Handle BREAK_STMT and CONTINUE_STMT.
        (cxx_eval_loop_expr): Add support for FOR_STMT, WHILE_STMT and DO_STMT.
        (cxx_eval_switch_expr): Add support for SWITCH_STMT.
        (cxx_eval_constant_expression): Handle IF_STMT, FOR_STMT, WHILE_STMT,
        DO_STMT, CONTINUE_STMT, SWITCH_STMT, BREAK_STMT and CONTINUE_STMT.
        For SIZEOF_EXPR, recurse on the result of fold_sizeof_expr.  Ignore
        DECL_EXPR with USING_DECL operand.
        * lambda.c (maybe_add_lambda_conv_op): Build thisarg using
        build_int_cst to make it a valid constant expression.

        * g++.dg/ubsan/vptr-4.C: Expect reinterpret_cast errors.
        * g++.dg/cpp1y/constexpr-84192.C (f2): Adjust expected diagnostics.
        * g++.dg/cpp1y/constexpr-70265-2.C (foo): Adjust expected line of
        diagnostics.
        * g++.dg/cpp1y/constexpr-89285.C: New test.

--- gcc/cp/constexpr.c.jj       2019-02-17 17:09:47.113351897 +0100
+++ gcc/cp/constexpr.c  2019-02-18 19:34:57.995136395 +0100
@@ -1269,6 +1301,49 @@ cxx_eval_builtin_function_call (const co
        return t;
      }
+ if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
+    switch (DECL_FUNCTION_CODE (fun))
+      {
+      case BUILT_IN_ADD_OVERFLOW:
+      case BUILT_IN_SADD_OVERFLOW:
+      case BUILT_IN_SADDL_OVERFLOW:
+      case BUILT_IN_SADDLL_OVERFLOW:
+      case BUILT_IN_UADD_OVERFLOW:
+      case BUILT_IN_UADDL_OVERFLOW:
+      case BUILT_IN_UADDLL_OVERFLOW:
+      case BUILT_IN_SUB_OVERFLOW:
+      case BUILT_IN_SSUB_OVERFLOW:
+      case BUILT_IN_SSUBL_OVERFLOW:
+      case BUILT_IN_SSUBLL_OVERFLOW:
+      case BUILT_IN_USUB_OVERFLOW:
+      case BUILT_IN_USUBL_OVERFLOW:
+      case BUILT_IN_USUBLL_OVERFLOW:
+      case BUILT_IN_MUL_OVERFLOW:
+      case BUILT_IN_SMUL_OVERFLOW:
+      case BUILT_IN_SMULL_OVERFLOW:
+      case BUILT_IN_SMULLL_OVERFLOW:
+      case BUILT_IN_UMUL_OVERFLOW:
+      case BUILT_IN_UMULL_OVERFLOW:
+      case BUILT_IN_UMULLL_OVERFLOW:
+       /* These builtins will fold into
+          (cast)
+            ((something = __real__ SAVE_EXPR <.???_OVERFLOW (cst1, cst2)>),
+             __imag__ SAVE_EXPR <.???_OVERFLOW (cst1, cst2)>)
+          which fails is_constant_expression.  */
+       if (TREE_CODE (args[0]) != INTEGER_CST
+           || TREE_CODE (args[1]) != INTEGER_CST
+           || !potential_constant_expression (args[2]))
+         {
+           if (!*non_constant_p && !ctx->quiet)
+             error ("%q+E is not a constant expression", new_call);
+           *non_constant_p = true;
+           return t;
+         }
+       return cxx_eval_constant_expression (&new_ctx, new_call, lval,
+                                            non_constant_p, overflow_p);
+      default:
+       break;
+      }

What is this for? Won't this recursive cxx_eval_constant_expression come back to this function again? If the expression is constant, shouldn't it have been folded by fold_builtin_call_array?

@@ -1358,6 +1433,9 @@ cxx_bind_parameters_in_call (const const
          x = ctx->object;
          x = build_address (x);
        }
+      if (TREE_ADDRESSABLE (type) && TYPE_REF_P (TREE_TYPE (x)))
+       /* Undo convert_for_arg_passing work here.  */
+       x = build_fold_indirect_ref_loc (EXPR_LOCATION (x), x);

Not convert_from_reference?

@@ -4036,6 +4113,10 @@ label_matches (const constexpr_ctx *ctx,
        }
        break;
+ case BREAK_STMT:
+    case CONTINUE_STMT:
+      break;
+

Let's add a comment that these are handled directly in cxx_eval_loop_expr.

Jason

Reply via email to