re PR c++/89285 (ICE after casting the this pointer in the constructor in C++17 mode)
authorJakub Jelinek <jakub@redhat.com>
Thu, 21 Feb 2019 21:21:25 +0000 (22:21 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 21 Feb 2019 21:21:25 +0000 (22:21 +0100)
PR c++/89285
* builtins.c (fold_builtin_arith_overflow): If first two args are
INTEGER_CSTs, set intres and ovfres to constants rather than calls
to ifn.

* 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.  Test
!potential_constant_expression instead of !is_constant_expression.
(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.
* g++.dg/cpp0x/constexpr-arith-overflow.C (add, sub, mul): Ifdef out
for C++11.
(TEST_ADD, TEST_SUB, TEST_MUL): Define to Assert (true) for C++11.
* g++.dg/cpp0x/constexpr-arith-overflow2.C: New test.

From-SVN: r269078

12 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/lambda.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow.C
gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/constexpr-70265-2.C
gcc/testsuite/g++.dg/cpp1y/constexpr-84192.C
gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ubsan/vptr-4.C

index 82890730e1c75fb46ec942afd8a73bff9df93578..0946f79234acd055ac75e0524c8152179360c2ad 100644 (file)
@@ -1,3 +1,10 @@
+2019-02-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89285
+       * builtins.c (fold_builtin_arith_overflow): If first two args are
+       INTEGER_CSTs, set intres and ovfres to constants rather than calls
+       to ifn.
+
 2019-02-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/87412
index 6f266ad15d0afb6c7672fe2e262ec1d12e2d383f..c19ca308b1bd289fdb825a4c11a9406fc64fb783 100644 (file)
@@ -9302,8 +9302,7 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
                             tree arg0, tree arg1, tree arg2)
 {
   enum internal_fn ifn = IFN_LAST;
-  /* The code of the expression corresponding to the type-generic
-     built-in, or ERROR_MARK for the type-specific ones.  */
+  /* The code of the expression corresponding to the built-in.  */
   enum tree_code opcode = ERROR_MARK;
   bool ovf_only = false;
 
@@ -9313,42 +9312,39 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
       ovf_only = true;
       /* FALLTHRU */
     case BUILT_IN_ADD_OVERFLOW:
-      opcode = PLUS_EXPR;
-      /* FALLTHRU */
     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:
+      opcode = PLUS_EXPR;
       ifn = IFN_ADD_OVERFLOW;
       break;
     case BUILT_IN_SUB_OVERFLOW_P:
       ovf_only = true;
       /* FALLTHRU */
     case BUILT_IN_SUB_OVERFLOW:
-      opcode = MINUS_EXPR;
-      /* FALLTHRU */
     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:
+      opcode = MINUS_EXPR;
       ifn = IFN_SUB_OVERFLOW;
       break;
     case BUILT_IN_MUL_OVERFLOW_P:
       ovf_only = true;
       /* FALLTHRU */
     case BUILT_IN_MUL_OVERFLOW:
-      opcode = MULT_EXPR;
-      /* FALLTHRU */
     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:
+      opcode = MULT_EXPR;
       ifn = IFN_MUL_OVERFLOW;
       break;
     default:
@@ -9373,13 +9369,27 @@ fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode,
                                 ? boolean_true_node : boolean_false_node,
                                 arg2);
 
-  tree ctype = build_complex_type (type);
-  tree call = build_call_expr_internal_loc (loc, ifn, ctype,
-                                           2, arg0, arg1);
-  tree tgt = save_expr (call);
-  tree intres = build1_loc (loc, REALPART_EXPR, type, tgt);
-  tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
-  ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
+  tree intres, ovfres;
+  if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+    {
+      intres = fold_binary_loc (loc, opcode, type,
+                               fold_convert_loc (loc, type, arg0),
+                               fold_convert_loc (loc, type, arg1));
+      if (TREE_OVERFLOW (intres))
+       intres = drop_tree_overflow (intres);
+      ovfres = (arith_overflowed_p (opcode, type, arg0, arg1)
+               ? boolean_true_node : boolean_false_node);
+    }
+  else
+    {
+      tree ctype = build_complex_type (type);
+      tree call = build_call_expr_internal_loc (loc, ifn, ctype, 2,
+                                               arg0, arg1);
+      tree tgt = save_expr (call);
+      intres = build1_loc (loc, REALPART_EXPR, type, tgt);
+      ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt);
+      ovfres = fold_convert_loc (loc, boolean_type_node, ovfres);
+    }
 
   if (ovf_only)
     return omit_one_operand_loc (loc, boolean_type_node, ovfres, arg2);
index 89a1bcac80b3d1d36e191c07ce5ae871d142b8db..824d007d36cb3cff5fdadc24d870294177da15db 100644 (file)
@@ -1,3 +1,32 @@
+2019-02-21  Jakub Jelinek  <jakub@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.  Test
+       !potential_constant_expression instead of !is_constant_expression.
+       (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.
+
 2019-02-20  Jason Merrill  <jason@redhat.com>
 
        PR c++/88690 - C++17 ICE with empty base in aggregate.
index a9aa7d500412db394c32df9fe1b7ba1bef51b603..40080271c11e8109f8cc6ea8fc6164576180cb15 100644 (file)
@@ -139,6 +139,8 @@ ensure_literal_type_for_constexpr_object (tree decl)
 struct GTY((for_user)) constexpr_fundef {
   tree decl;
   tree body;
+  tree parms;
+  tree result;
 };
 
 struct constexpr_fundef_hasher : ggc_ptr_hash<constexpr_fundef>
@@ -176,11 +178,10 @@ constexpr_fundef_hasher::hash (constexpr_fundef *fundef)
 static constexpr_fundef *
 retrieve_constexpr_fundef (tree fun)
 {
-  constexpr_fundef fundef = { NULL, NULL };
   if (constexpr_fundef_table == NULL)
     return NULL;
 
-  fundef.decl = fun;
+  constexpr_fundef fundef = { fun, NULL, NULL, NULL };
   return constexpr_fundef_table->find (&fundef);
 }
 
@@ -897,8 +898,19 @@ register_constexpr_fundef (tree fun, tree body)
       = hash_table<constexpr_fundef_hasher>::create_ggc (101);
 
   entry.decl = fun;
-  entry.body = body;
+  tree saved_fn = current_function_decl;
+  bool clear_ctx = false;
+  current_function_decl = fun;
+  if (DECL_RESULT (fun) && DECL_CONTEXT (DECL_RESULT (fun)) == NULL_TREE)
+    {
+      clear_ctx = true;
+      DECL_CONTEXT (DECL_RESULT (fun)) = fun;
+    }
+  entry.body = copy_fn (fun, entry.parms, entry.result);
+  current_function_decl = saved_fn;
   slot = constexpr_fundef_table->find_slot (&entry, INSERT);
+  if (clear_ctx)
+    DECL_CONTEXT (DECL_RESULT (fun)) = NULL_TREE;
 
   gcc_assert (*slot == NULL);
   *slot = ggc_alloc<constexpr_fundef> ();
@@ -1114,27 +1126,40 @@ maybe_initialize_fundef_copies_table ()
    is parms, TYPE is result.  */
 
 static tree
-get_fundef_copy (tree fun)
+get_fundef_copy (constexpr_fundef *fundef)
 {
   maybe_initialize_fundef_copies_table ();
 
   tree copy;
   bool existed;
-  tree *slot = &fundef_copies_table->get_or_insert (fun, &existed);
+  tree *slot = &fundef_copies_table->get_or_insert (fundef->decl, &existed);
 
   if (!existed)
     {
       /* There is no cached function available, or in use.  We can use
         the function directly.  That the slot is now created records
         that this function is now in use.  */
-      copy = build_tree_list (DECL_SAVED_TREE (fun), DECL_ARGUMENTS (fun));
-      TREE_TYPE (copy) = DECL_RESULT (fun);
+      copy = build_tree_list (fundef->body, fundef->parms);
+      TREE_TYPE (copy) = fundef->result;
     }
   else if (*slot == NULL_TREE)
     {
       /* We've already used the function itself, so make a copy.  */
       copy = build_tree_list (NULL, NULL);
-      TREE_PURPOSE (copy) = copy_fn (fun, TREE_VALUE (copy), TREE_TYPE (copy));
+      tree saved_body = DECL_SAVED_TREE (fundef->decl);
+      tree saved_parms = DECL_ARGUMENTS (fundef->decl);
+      tree saved_result = DECL_RESULT (fundef->decl);
+      tree saved_fn = current_function_decl;
+      DECL_SAVED_TREE (fundef->decl) = fundef->body;
+      DECL_ARGUMENTS (fundef->decl) = fundef->parms;
+      DECL_RESULT (fundef->decl) = fundef->result;
+      current_function_decl = fundef->decl;
+      TREE_PURPOSE (copy) = copy_fn (fundef->decl, TREE_VALUE (copy),
+                                    TREE_TYPE (copy));
+      current_function_decl = saved_fn;
+      DECL_RESULT (fundef->decl) = saved_result;
+      DECL_ARGUMENTS (fundef->decl) = saved_parms;
+      DECL_SAVED_TREE (fundef->decl) = saved_body;
     }
   else
     {
@@ -1245,8 +1270,15 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
 
   bool save_ffbcp = force_folding_builtin_constant_p;
   force_folding_builtin_constant_p = true;
+  tree save_cur_fn = current_function_decl;
+  /* Return name of ctx->call->fundef->decl for __builtin_FUNCTION ().  */
+  if (fndecl_built_in_p (fun, BUILT_IN_FUNCTION)
+      && ctx->call
+      && ctx->call->fundef)
+    current_function_decl = ctx->call->fundef->decl;
   new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t),
                                      CALL_EXPR_FN (t), nargs, args);
+  current_function_decl = save_cur_fn;
   force_folding_builtin_constant_p = save_ffbcp;
   if (new_call == NULL)
     {
@@ -1269,7 +1301,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
       return t;
     }
 
-  if (!is_constant_expression (new_call))
+  if (!potential_constant_expression (new_call))
     {
       if (!*non_constant_p && !ctx->quiet)
        error ("%q+E is not a constant expression", new_call);
@@ -1341,7 +1373,7 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
 {
   const int nargs = call_expr_nargs (t);
   tree fun = new_call->fundef->decl;
-  tree parms = DECL_ARGUMENTS (fun);
+  tree parms = new_call->fundef->parms;
   int i;
   tree *p = &new_call->bindings;
   for (i = 0; i < nargs; ++i)
@@ -1358,6 +1390,9 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
          x = ctx->object;
          x = build_address (x);
        }
+      if (TREE_ADDRESSABLE (type))
+       /* Undo convert_for_arg_passing work here.  */
+       x = convert_from_reference (x);
       arg = cxx_eval_constant_expression (ctx, x, /*lval=*/false,
                                          non_constant_p, overflow_p);
       /* Don't VERIFY_CONSTANT here.  */
@@ -1761,7 +1796,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
          tree body, parms, res;
 
          /* Reuse or create a new unshared copy of this function's body.  */
-         tree copy = get_fundef_copy (fun);
+         tree copy = get_fundef_copy (new_call.fundef);
          body = TREE_PURPOSE (copy);
          parms = TREE_VALUE (copy);
          res = TREE_TYPE (copy);
@@ -2223,14 +2258,13 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
   VERIFY_CONSTANT (val);
   /* Don't VERIFY_CONSTANT the other operands.  */
   if (integer_zerop (val))
-    return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
-                                        lval,
-                                        non_constant_p, overflow_p,
-                                        jump_target);
-  return cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-                                      lval,
-                                      non_constant_p, overflow_p,
-                                      jump_target);
+    val = TREE_OPERAND (t, 2);
+  else
+    val = TREE_OPERAND (t, 1);
+  if (TREE_CODE (t) == IF_STMT && !val)
+    val = void_node;
+  return cxx_eval_constant_expression (ctx, val, lval, non_constant_p,
+                                      overflow_p, jump_target);
 }
 
 /* Subroutine of cxx_eval_constant_expression.
@@ -4059,6 +4093,12 @@ label_matches (const constexpr_ctx *ctx, tree *jump_target, tree stmt)
        }
       break;
 
+    case BREAK_STMT:
+    case CONTINUE_STMT:
+      /* These two are handled directly in cxx_eval_loop_expr by testing
+        breaks (jump_target) or continues (jump_target).  */
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -4119,20 +4159,84 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
 {
   constexpr_ctx new_ctx = *ctx;
 
-  tree body = TREE_OPERAND (t, 0);
+  tree body, cond = NULL_TREE, expr = NULL_TREE;
   int count = 0;
+  switch (TREE_CODE (t))
+    {
+    case LOOP_EXPR:
+      body = LOOP_EXPR_BODY (t);
+      break;
+    case DO_STMT:
+      body = DO_BODY (t);
+      cond = DO_COND (t);
+      break;
+    case WHILE_STMT:
+      body = WHILE_BODY (t);
+      cond = WHILE_COND (t);
+      count = -1;
+      break;
+    case FOR_STMT:
+      if (FOR_INIT_STMT (t))
+       cxx_eval_constant_expression (ctx, FOR_INIT_STMT (t), /*lval*/false,
+                                     non_constant_p, overflow_p, jump_target);
+      if (*non_constant_p)
+       return NULL_TREE;
+      body = FOR_BODY (t);
+      cond = FOR_COND (t);
+      expr = FOR_EXPR (t);
+      count = -1;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  hash_set<tree> save_exprs;
+  new_ctx.save_exprs = &save_exprs;
   do
     {
-      hash_set<tree> save_exprs;
-      new_ctx.save_exprs = &save_exprs;
+      if (count != -1)
+       {
+         if (body)
+           cxx_eval_constant_expression (&new_ctx, body, /*lval*/false,
+                                         non_constant_p, overflow_p,
+                                         jump_target);
+         if (breaks (jump_target))
+           {
+             *jump_target = NULL_TREE;
+             break;
+           }
 
-      cxx_eval_constant_expression (&new_ctx, body, /*lval*/false,
-                                   non_constant_p, overflow_p, jump_target);
+         if (TREE_CODE (t) != LOOP_EXPR && continues (jump_target))
+           *jump_target = NULL_TREE;
+
+         if (expr)
+           cxx_eval_constant_expression (&new_ctx, expr, /*lval*/false,
+                                         non_constant_p, overflow_p,
+                                         jump_target);
+       }
+
+      if (cond)
+       {
+         tree res
+           = cxx_eval_constant_expression (&new_ctx, cond, /*lval*/false,
+                                           non_constant_p, overflow_p,
+                                           jump_target);
+         if (res)
+           {
+             if (verify_constant (res, ctx->quiet, non_constant_p,
+                                  overflow_p))
+               break;
+             if (integer_zerop (res))
+               break;
+           }
+         else
+           gcc_assert (*jump_target);
+       }
 
       /* Forget saved values of SAVE_EXPRs.  */
       for (hash_set<tree>::iterator iter = save_exprs.begin();
           iter != save_exprs.end(); ++iter)
        new_ctx.values->remove (*iter);
+
       if (++count >= constexpr_loop_limit)
        {
          if (!ctx->quiet)
@@ -4146,11 +4250,14 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t,
     }
   while (!returns (jump_target)
         && !breaks (jump_target)
-        && !switches (jump_target)
+        && !continues (jump_target)
+        && (!switches (jump_target) || count == 0)
         && !*non_constant_p);
 
-  if (breaks (jump_target))
-    *jump_target = NULL_TREE;
+  /* Forget saved values of SAVE_EXPRs.  */
+  for (hash_set<tree>::iterator iter = save_exprs.begin();
+       iter != save_exprs.end(); ++iter)
+    new_ctx.values->remove (*iter);
 
   return NULL_TREE;
 }
@@ -4163,13 +4270,15 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t,
                      bool *non_constant_p, bool *overflow_p,
                      tree *jump_target)
 {
-  tree cond = SWITCH_COND (t);
+  tree cond
+    = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_COND (t) : SWITCH_COND (t);
   cond = cxx_eval_constant_expression (ctx, cond, false,
                                       non_constant_p, overflow_p);
   VERIFY_CONSTANT (cond);
   *jump_target = cond;
 
-  tree body = SWITCH_BODY (t);
+  tree body
+    = TREE_CODE (t) == SWITCH_STMT ? SWITCH_STMT_BODY (t) : SWITCH_BODY (t);
   constexpr_ctx new_ctx = *ctx;
   constexpr_switch_state css = css_default_not_seen;
   new_ctx.css_state = &css;
@@ -4245,6 +4354,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        case STATEMENT_LIST:
        case LOOP_EXPR:
        case COND_EXPR:
+       case IF_STMT:
+       case DO_STMT:
+       case WHILE_STMT:
+       case FOR_STMT:
          break;
        case LABEL_EXPR:
        case CASE_LABEL_EXPR:
@@ -4389,6 +4502,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case DECL_EXPR:
       {
        r = DECL_EXPR_DECL (t);
+       if (TREE_CODE (r) == USING_DECL)
+         {
+           r = void_node;
+           break;
+         }
        if (AGGREGATE_TYPE_P (TREE_TYPE (r))
            || VECTOR_TYPE_P (TREE_TYPE (r)))
          {
@@ -4476,6 +4594,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
                                          lval,
                                          non_constant_p, overflow_p);
+      /* FALLTHRU */
+    case BREAK_STMT:
+    case CONTINUE_STMT:
       if (jump_target)
        *jump_target = t;
       else
@@ -4526,6 +4647,17 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                      jump_target);
       break;
 
+    case CLEANUP_STMT:
+      r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval,
+                                       non_constant_p, overflow_p,
+                                       jump_target);
+      if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
+       /* Also evaluate the cleanup.  */
+       cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true,
+                                     non_constant_p, overflow_p,
+                                     jump_target);
+      break;
+
       /* These differ from cxx_eval_unary_expression in that this doesn't
         check for a constant operand or result; an address can be
         constant without its operand being, and vice versa.  */
@@ -4581,8 +4713,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case SIZEOF_EXPR:
-      r = fold_sizeof_expr (t);
-      VERIFY_CONSTANT (r);
+      r = cxx_eval_constant_expression (ctx, fold_sizeof_expr (t), lval,
+                                       non_constant_p, overflow_p,
+                                       jump_target);
       break;
 
     case COMPOUND_EXPR:
@@ -4702,16 +4835,18 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case COND_EXPR:
+    case IF_STMT:
       if (jump_target && *jump_target)
        {
          tree orig_jump = *jump_target;
+         tree arg = ((TREE_CODE (t) != IF_STMT || TREE_OPERAND (t, 1))
+                     ? TREE_OPERAND (t, 1) : void_node);
          /* When jumping to a label, the label might be either in the
             then or else blocks, so process then block first in skipping
             mode first, and if we are still in the skipping mode at its end,
             process the else block too.  */
-         r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1),
-                                           lval, non_constant_p, overflow_p,
-                                           jump_target);
+         r = cxx_eval_constant_expression (ctx, arg, lval, non_constant_p,
+                                           overflow_p, jump_target);
          /* It's possible that we found the label in the then block.  But
             it could have been followed by another jumping statement, e.g.
             say we're looking for case 1:
@@ -4725,9 +4860,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
             in which case we need not go looking to the else block.
             (goto is not allowed in a constexpr function.)  */
          if (*jump_target == orig_jump)
-           r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 2),
-                                             lval, non_constant_p, overflow_p,
-                                             jump_target);
+           {
+             arg = ((TREE_CODE (t) != IF_STMT || TREE_OPERAND (t, 2))
+                    ? TREE_OPERAND (t, 2) : void_node);
+             r = cxx_eval_constant_expression (ctx, arg, lval, non_constant_p,
+                                               overflow_p, jump_target);
+           }
          break;
        }
       r = cxx_eval_conditional_expression (ctx, t, lval,
@@ -4971,11 +5109,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case LOOP_EXPR:
+    case DO_STMT:
+    case WHILE_STMT:
+    case FOR_STMT:
       cxx_eval_loop_expr (ctx, t,
                          non_constant_p, overflow_p, jump_target);
       break;
 
     case SWITCH_EXPR:
+    case SWITCH_STMT:
       cxx_eval_switch_expr (ctx, t,
                            non_constant_p, overflow_p, jump_target);
       break;
index 791c8de6738075681ff0566e6e01531eaf768544..3b803ad86a6abcbbcf32639effb04eb6859c3f67 100644 (file)
@@ -1087,8 +1087,7 @@ maybe_add_lambda_conv_op (tree type)
   tree optype = TREE_TYPE (callop);
   tree fn_result = TREE_TYPE (optype);
 
-  tree thisarg = build_nop (TREE_TYPE (DECL_ARGUMENTS (callop)),
-                           null_pointer_node);
+  tree thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0);
   if (generic_lambda_p)
     {
       ++processing_template_decl;
index 0093df61df122e1cae78fbd4f3a29ec0167518de..78d9d2c82e47760e11258ec826c266b3882bfa39 100644 (file)
@@ -1,3 +1,16 @@
+2019-02-21  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/89285
+       * 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.
+       * g++.dg/cpp0x/constexpr-arith-overflow.C (add, sub, mul): Ifdef out
+       for C++11.
+       (TEST_ADD, TEST_SUB, TEST_MUL): Define to Assert (true) for C++11.
+       * g++.dg/cpp0x/constexpr-arith-overflow2.C: New test.
+
 2019-02-21  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/87412
index a63c0a1ef540d96ba82c8bcaa3963c3f7b3a91e7..f39a407da8519abceae7a82660a999086a882d58 100644 (file)
@@ -27,6 +27,7 @@
 
 #define Assert(expr) static_assert ((expr), #expr)
 
+#if __cplusplus >= 201402L
 template <class T>
 constexpr T add (T x, T y, T z = T ())
 {
@@ -48,6 +49,11 @@ constexpr T mul (T x, T y, T z = T ())
 #define TEST_ADD(T, x, y, z) Assert (z == add<T>(x, y))
 #define TEST_SUB(T, x, y, z) Assert (z == sub<T>(x, y))
 #define TEST_MUL(T, x, y, z) Assert (z == mul<T>(x, y))
+#else
+#define TEST_ADD(T, x, y, z) Assert (true)
+#define TEST_SUB(T, x, y, z) Assert (true)
+#define TEST_MUL(T, x, y, z) Assert (true)
+#endif
 
 
 TEST_ADD (signed char,  0,         0,         0);
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow2.C
new file mode 100644 (file)
index 0000000..a67b025
--- /dev/null
@@ -0,0 +1,31 @@
+// PR c++/70507 - integer overflow builtins not constant expressions
+// The constexpr-arith-overflow.C testcase covers this for C++14 and later.
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+#define Assert(expr) static_assert ((expr), #expr)
+
+template <class T>
+constexpr T add (T x, T y, T z = T ())
+{
+  return __builtin_add_overflow (x, y, &z) ? 0 : z;    // { dg-error "is not a constant expression" }
+}
+
+template <class T>
+constexpr T sub (T x, T y, T z = T ())
+{
+  return __builtin_sub_overflow (x, y, &z) ? 0 : z;    // { dg-error "is not a constant expression" }
+}
+
+template <class T>
+constexpr T mul (T x, T y, T z = T ())
+{
+  return __builtin_mul_overflow (x, y, &z) ? 0 : z;    // { dg-error "is not a constant expression" }
+}
+
+Assert (0 == add<int>(0, 0));  // { dg-error "non-constant condition for static assertion" }
+Assert (0 == sub<int>(0, 0));  // { dg-error "non-constant condition for static assertion" }
+Assert (0 == mul<int>(0, 0));  // { dg-error "non-constant condition for static assertion" }
+// { dg-message "expansion of" "" { target *-*-* } .-3 }
+// { dg-message "expansion of" "" { target *-*-* } .-3 }
+// { dg-message "expansion of" "" { target *-*-* } .-3 }
index 895870effe11759db3eee867cc695d8fb8108abf..6eb3c680eec86e5bc00aac0ed5d6ac0e97db43d6 100644 (file)
@@ -5,8 +5,8 @@ constexpr int
 foo (int p)
 {
   int t = 0;
-  while (1)
-    t = 0;  // { dg-error "count exceeds" }
+  while (1)  // { dg-error "count exceeds" }
+    t = 0;
   return t;
 }
 
index ad9458d238f8c371e816c36689af793ba82b0fd7..f7439d80b3967bc59d3c3db97bdc442446ab2bcc 100644 (file)
@@ -12,7 +12,7 @@ void
 f2 ()
 { 
   for (;;)
-    constexpr bool b = ({ break; false; }) && false;   // { dg-error "statement is not a constant expression" }
+    constexpr bool b = ({ break; false; }) && false;   // { dg-error "is not a constant expression" }
 }
 
 constexpr bool
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-89285.C
new file mode 100644 (file)
index 0000000..3809e1f
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/89285
+// { dg-do compile { target c++14 } }
+
+struct A {
+  int a {};
+};
+struct B {
+  int b {};
+  constexpr B (A *x) {
+    int *c = &x->a;
+    while (*c)
+      c = reinterpret_cast<int *>((reinterpret_cast<char *>(c) + *c));
+    *c = reinterpret_cast<char *>(this) - reinterpret_cast<char *>(c); // { dg-error "reinterpret_cast" }
+  }
+};
+struct C : A {
+  B bar {this};
+};
+
+constexpr C foo {};    // { dg-message "expansion of" }
index 1c037d047dd1c19045f9a445c4ada9500dd86d43..cf638e9b35f9d9225c2c10408a0f35db6652ec09 100644 (file)
@@ -15,11 +15,11 @@ struct T : S {
   int b;
   int g() { return 0; }
   virtual int v() { return 1; }
-  constexpr const T *foo() { return (const T *) reinterpret_cast<const S *> (this); }
+  constexpr const T *foo() { return (const T *) reinterpret_cast<const S *> (this); } // { dg-error "is not a constant expression" }
 };
 
 constexpr T t;
-constexpr const T *p = t.foo ();
+constexpr const T *p = t.foo ();       // { dg-message "expansion of" }
 
 template <typename U>
 struct V {
@@ -39,16 +39,17 @@ struct W : V<U> {
 };
 
 constexpr W<int> w;
-constexpr const W<int> *s = w.foo ();
+constexpr const W<int> *s = w.foo ();  // { dg-error "is not a constant expression" }
+// { dg-message "expansion of" "" { target *-*-* } .-1 }
 
 template <typename U>
 int foo (void)
 {
   static constexpr T t;
-  static constexpr const T *p = t.foo ();
+  static constexpr const T *p = t.foo ();      // { dg-message "expansion of" }
   static constexpr W<U> w;
-  static constexpr const W<U> *s = w.foo ();
-  return t.b + w.b;
+  static constexpr const W<U> *s = w.foo ();   // { dg-error "is not a constant expression" }
+  return t.b + w.b;                            // { dg-message "expansion of" "" { target *-*-* } .-1 }
 }
 
 int x = foo <char> ();