re PR c/7652 (-Wswitch-break : Warn if a switch case falls through)
[platform/upstream/gcc.git] / gcc / cp / cp-gimplify.c
index 2dc53ae..6d514d0 100644 (file)
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
+#include "cp-cilkplus.h"
 
 /* Forward declarations.  */
 
@@ -98,7 +99,7 @@ cilk_cp_gimplify_call_params_in_spawned_fn (tree *expr_p, gimple_seq *pre_p,
 {
   int ii = 0;
 
-  cilk_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);  
+  cilk_gimplify_call_params_in_spawned_fn (expr_p, pre_p);
   if (TREE_CODE (*expr_p) == AGGR_INIT_EXPR)
     for (ii = 0; ii < aggr_init_expr_nargs (*expr_p); ii++)
       gimplify_expr (&AGGR_INIT_EXPR_ARG (*expr_p, ii), pre_p, post_p,
@@ -361,7 +362,7 @@ genericize_continue_stmt (tree *stmt_p)
   tree label = get_bc_label (bc_continue);
   location_t location = EXPR_LOCATION (*stmt_p);
   tree jump = build1_loc (location, GOTO_EXPR, void_type_node, label);
-  append_to_statement_list (pred, &stmt_list);
+  append_to_statement_list_force (pred, &stmt_list);
   append_to_statement_list (jump, &stmt_list);
   *stmt_p = stmt_list;
 }
@@ -386,7 +387,8 @@ genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data)
   tree clab = begin_bc_block (bc_continue, locus);
 
   cp_walk_tree (&OMP_FOR_BODY (stmt), cp_genericize_r, data, NULL);
-  cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL);
+  if (TREE_CODE (stmt) != OMP_TASKLOOP)
+    cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_genericize_r, data, NULL);
   cp_walk_tree (&OMP_FOR_INIT (stmt), cp_genericize_r, data, NULL);
   cp_walk_tree (&OMP_FOR_COND (stmt), cp_genericize_r, data, NULL);
   cp_walk_tree (&OMP_FOR_INCR (stmt), cp_genericize_r, data, NULL);
@@ -557,12 +559,40 @@ simple_empty_class_p (tree type, tree op)
     && is_really_empty_class (type);
 }
 
+/* Returns true if evaluating E as an lvalue has side-effects;
+   specifically, a volatile lvalue has TREE_SIDE_EFFECTS, but it doesn't really
+   have side-effects until there is a read or write through it.  */
+
+static bool
+lvalue_has_side_effects (tree e)
+{
+  if (!TREE_SIDE_EFFECTS (e))
+    return false;
+  while (handled_component_p (e))
+    {
+      if (TREE_CODE (e) == ARRAY_REF
+         && TREE_SIDE_EFFECTS (TREE_OPERAND (e, 1)))
+       return true;
+      e = TREE_OPERAND (e, 0);
+    }
+  if (DECL_P (e))
+    /* Just naming a variable has no side-effects.  */
+    return false;
+  else if (INDIRECT_REF_P (e))
+    /* Similarly, indirection has no side-effects.  */
+    return TREE_SIDE_EFFECTS (TREE_OPERAND (e, 0));
+  else
+    /* For anything else, trust TREE_SIDE_EFFECTS.  */
+    return TREE_SIDE_EFFECTS (e);
+}
+
 /* Do C++-specific gimplification.  Args are as for gimplify_expr.  */
 
 int
 cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 {
   int saved_stmts_are_full_exprs_p = 0;
+  location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
   enum tree_code code = TREE_CODE (*expr_p);
   enum gimplify_status ret;
 
@@ -575,11 +605,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
   switch (code)
     {
-    case PTRMEM_CST:
-      *expr_p = cplus_expand_constant (*expr_p);
-      ret = GS_OK;
-      break;
-
     case AGGR_INIT_EXPR:
       simplify_aggr_init_expr (expr_p);
       ret = GS_OK;
@@ -596,6 +621,8 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
                                  init, VEC_INIT_EXPR_VALUE_INIT (*expr_p),
                                  from_array,
                                  tf_warning_or_error);
+       hash_set<tree> pset;
+       cp_walk_tree (expr_p, cp_fold_r, &pset, NULL);
        cp_genericize_tree (expr_p);
        ret = GS_OK;
        input_location = loc;
@@ -619,7 +646,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
     case INIT_EXPR:
       if (fn_contains_cilk_spawn_p (cfun))
        {
-         if (cilk_detect_spawn_and_unwrap (expr_p))
+         if (cilk_cp_detect_spawn_and_unwrap (expr_p))
            {
              cilk_cp_gimplify_call_params_in_spawned_fn (expr_p,
                                                          pre_p, post_p);
@@ -632,12 +659,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
       cp_gimplify_init_expr (expr_p);
       if (TREE_CODE (*expr_p) != INIT_EXPR)
        return GS_OK;
-      /* Otherwise fall through.  */
+      /* Fall through.  */
     case MODIFY_EXPR:
     modify_expr_case:
       {
        if (fn_contains_cilk_spawn_p (cfun)
-           && cilk_detect_spawn_and_unwrap (expr_p)
+           && cilk_cp_detect_spawn_and_unwrap (expr_p)
            && !seen_error ())
          {
            cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
@@ -661,8 +688,6 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
            /* Remove any copies of empty classes.  Also drop volatile
               variables on the RHS to avoid infinite recursion from
               gimplify_expr trying to load the value.  */
-           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-                          is_gimple_lvalue, fb_lvalue);
            if (TREE_SIDE_EFFECTS (op1))
              {
                if (TREE_THIS_VOLATILE (op1)
@@ -671,8 +696,29 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
                gimplify_and_add (op1, pre_p);
              }
+           gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+                          is_gimple_lvalue, fb_lvalue);
            *expr_p = TREE_OPERAND (*expr_p, 0);
          }
+       /* P0145 says that the RHS is sequenced before the LHS.
+          gimplify_modify_expr gimplifies the RHS before the LHS, but that
+          isn't quite strong enough in two cases:
+
+          1) gimplify.c wants to leave a CALL_EXPR on the RHS, which would
+          mean it's evaluated after the LHS.
+
+          2) the value calculation of the RHS is also sequenced before the
+          LHS, so for scalar assignment we need to preevaluate if the
+          RHS could be affected by LHS side-effects even if it has no
+          side-effects of its own.  We don't need this for classes because
+          class assignment takes its RHS by reference.  */
+       else if (flag_strong_eval_order > 1
+                && TREE_CODE (*expr_p) == MODIFY_EXPR
+                && lvalue_has_side_effects (op0)
+               && (TREE_CODE (op1) == CALL_EXPR
+                   || (SCALAR_TYPE_P (TREE_TYPE (op1))
+                       && !TREE_CONSTANT (op1))))
+        TREE_OPERAND (*expr_p, 1) = get_formal_tmp_var (op1, pre_p);
       }
       ret = GS_OK;
       break;
@@ -738,7 +784,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
     case CILK_SPAWN_STMT:
       gcc_assert(fn_contains_cilk_spawn_p (cfun)
-                && cilk_detect_spawn_and_unwrap (expr_p));
+                && cilk_cp_detect_spawn_and_unwrap (expr_p));
 
       if (!seen_error ())
        {
@@ -749,24 +795,32 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 
     case CALL_EXPR:
       if (fn_contains_cilk_spawn_p (cfun)
-         && cilk_detect_spawn_and_unwrap (expr_p)
+         && cilk_cp_detect_spawn_and_unwrap (expr_p)
          && !seen_error ())
        {
          cilk_cp_gimplify_call_params_in_spawned_fn (expr_p, pre_p, post_p);
          return (enum gimplify_status) gimplify_cilk_spawn (expr_p);
        }
-      /* DR 1030 says that we need to evaluate the elements of an
-        initializer-list in forward order even when it's used as arguments to
-        a constructor.  So if the target wants to evaluate them in reverse
-        order and there's more than one argument other than 'this', gimplify
-        them in order.  */
       ret = GS_OK;
-      if (PUSH_ARGS_REVERSED && CALL_EXPR_LIST_INIT_P (*expr_p)
-         && call_expr_nargs (*expr_p) > 2)
+      if (!CALL_EXPR_FN (*expr_p))
+       /* Internal function call.  */;
+      else if (CALL_EXPR_REVERSE_ARGS (*expr_p))
        {
-         int nargs = call_expr_nargs (*expr_p);
-         location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
-         for (int i = 1; i < nargs; ++i)
+         /* This is a call to a (compound) assignment operator that used
+            the operator syntax; gimplify the RHS first.  */
+         gcc_assert (call_expr_nargs (*expr_p) == 2);
+         gcc_assert (!CALL_EXPR_ORDERED_ARGS (*expr_p));
+         enum gimplify_status t
+           = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 1), pre_p, loc);
+         if (t == GS_ERROR)
+           ret = GS_ERROR;
+       }
+      else if (CALL_EXPR_ORDERED_ARGS (*expr_p))
+       {
+         /* Leave the last argument for gimplify_call_expr, to avoid problems
+            with __builtin_va_arg_pack().  */
+         int nargs = call_expr_nargs (*expr_p) - 1;
+         for (int i = 0; i < nargs; ++i)
            {
              enum gimplify_status t
                = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, loc);
@@ -774,6 +828,21 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
                ret = GS_ERROR;
            }
        }
+      else if (flag_strong_eval_order
+              && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p))
+       {
+         /* If flag_strong_eval_order, evaluate the object argument first.  */
+         tree fntype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
+         if (POINTER_TYPE_P (fntype))
+           fntype = TREE_TYPE (fntype);
+         if (TREE_CODE (fntype) == METHOD_TYPE)
+           {
+             enum gimplify_status t
+               = gimplify_arg (&CALL_EXPR_ARG (*expr_p, 0), pre_p, loc);
+             if (t == GS_ERROR)
+               ret = GS_ERROR;
+           }
+       }
       break;
 
     case RETURN_EXPR:
@@ -943,6 +1012,17 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 
   *stmt_p = stmt = cp_fold (*stmt_p);
 
+  if (((hash_set<tree> *) data)->add (stmt))
+    {
+      /* Don't walk subtrees of stmts we've already walked once, otherwise
+        we can have exponential complexity with e.g. lots of nested
+        SAVE_EXPRs or TARGET_EXPRs.  cp_fold uses a cache and will return
+        always the same tree, which the first time cp_fold_r has been
+        called on it had the subtrees walked.  */
+      *walk_subtrees = 0;
+      return NULL;
+    }
+
   code = TREE_CODE (stmt);
   if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
       || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD
@@ -1000,7 +1080,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 void
 cp_fold_function (tree fndecl)
 {
-  cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, NULL, NULL);
+  hash_set<tree> pset;
+  cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &pset, NULL);
 }
 
 /* Perform any pre-gimplification lowering of C++ front end trees to
@@ -1021,10 +1102,16 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       && omp_var_to_track (stmt))
     omp_cxx_notice_variable (wtd->omp_ctx, stmt);
 
-  if (is_invisiref_parm (stmt)
-      /* Don't dereference parms in a thunk, pass the references through. */
-      && !(DECL_THUNK_P (current_function_decl)
-          && TREE_CODE (stmt) == PARM_DECL))
+  /* Don't dereference parms in a thunk, pass the references through. */
+  if ((TREE_CODE (stmt) == CALL_EXPR && CALL_FROM_THUNK_P (stmt))
+      || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt)))
+    {
+      *walk_subtrees = 0;
+      return NULL;
+    }
+
+  /* Otherwise, do dereference invisible reference parms.  */
+  if (is_invisiref_parm (stmt))
     {
       *stmt_p = convert_from_reference (stmt);
       *walk_subtrees = 0;
@@ -1266,7 +1353,9 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       if (TREE_CODE (d) == VAR_DECL)
        gcc_assert (CP_DECL_THREAD_LOCAL_P (d) == DECL_THREAD_LOCAL_P (d));
     }
-  else if (TREE_CODE (stmt) == OMP_PARALLEL || TREE_CODE (stmt) == OMP_TASK)
+  else if (TREE_CODE (stmt) == OMP_PARALLEL
+          || TREE_CODE (stmt) == OMP_TASK
+          || TREE_CODE (stmt) == OMP_TASKLOOP)
     {
       struct cp_genericize_omp_taskreg omp_ctx;
       tree c, decl;
@@ -1306,7 +1395,10 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
          default:
            break;
          }
-      cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL);
+      if (TREE_CODE (stmt) == OMP_TASKLOOP)
+       genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+      else
+       cp_walk_tree (&OMP_BODY (stmt), cp_genericize_r, data, NULL);
       wtd->omp_ctx = omp_ctx.outer;
       splay_tree_delete (omp_ctx.variables);
     }
@@ -1374,9 +1466,15 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
     genericize_break_stmt (stmt_p);
   else if (TREE_CODE (stmt) == OMP_FOR
           || TREE_CODE (stmt) == OMP_SIMD
-          || TREE_CODE (stmt) == OMP_DISTRIBUTE
-          || TREE_CODE (stmt) == OMP_TASKLOOP)
+          || TREE_CODE (stmt) == OMP_DISTRIBUTE)
     genericize_omp_for_stmt (stmt_p, walk_subtrees, data);
+  else if (TREE_CODE (stmt) == PTRMEM_CST)
+    {
+      /* By the time we get here we're handing off to the back end, so we don't
+        need or want to preserve PTRMEM_CST anymore.  */
+      *stmt_p = cplus_expand_constant (stmt);
+      *walk_subtrees = 0;
+    }
   else if ((flag_sanitize
            & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))
           && !wtd->no_sanitize_p)
@@ -1534,6 +1632,13 @@ cp_genericize (tree fndecl)
   if (DECL_CLONED_FUNCTION_P (fndecl))
     return;
 
+  /* Allow cp_genericize calls to be nested.  */
+  tree save_bc_label[2];
+  save_bc_label[bc_break] = bc_label[bc_break];
+  save_bc_label[bc_continue] = bc_label[bc_continue];
+  bc_label[bc_break] = NULL_TREE;
+  bc_label[bc_continue] = NULL_TREE;
+
   /* Expand all the array notations here.  */
   if (flag_cilkplus 
       && contains_array_notation_expr (DECL_SAVED_TREE (fndecl)))
@@ -1553,6 +1658,8 @@ cp_genericize (tree fndecl)
 
   gcc_assert (bc_label[bc_break] == NULL);
   gcc_assert (bc_label[bc_continue] == NULL);
+  bc_label[bc_break] = save_bc_label[bc_break];
+  bc_label[bc_continue] = save_bc_label[bc_continue];
 }
 \f
 /* Build code to apply FN to each member of ARG1 and ARG2.  FN may be
@@ -1856,6 +1963,12 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 tree
 cp_fully_fold (tree x)
 {
+  if (processing_template_decl)
+    return x;
+  /* FIXME cp_fold ought to be a superset of maybe_constant_value so we don't
+     have to call both.  */
+  if (cxx_dialect >= cxx11)
+    x = maybe_constant_value (x);
   return cp_fold (x);
 }
 
@@ -1864,13 +1977,21 @@ cp_fully_fold (tree x)
 static tree
 cp_fold_maybe_rvalue (tree x, bool rval)
 {
-  if (rval && DECL_P (x))
+  while (true)
     {
-      tree v = decl_constant_value (x);
-      if (v != error_mark_node)
-       x = v;
+      x = cp_fold (x);
+      if (rval && DECL_P (x))
+       {
+         tree v = decl_constant_value (x);
+         if (v != x && v != error_mark_node)
+           {
+             x = v;
+             continue;
+           }
+       }
+      break;
     }
-  return cp_fold (x);
+  return x;
 }
 
 /* Fold expression X which is used as an rvalue.  */
@@ -1894,7 +2015,16 @@ c_fully_fold (tree x, bool /*in_init*/, bool */*maybe_const*/)
   return cp_fold_rvalue (x);
 }
 
-static GTY((cache, deletable)) cache_map fold_cache;
+static GTY((deletable)) hash_map<tree, tree> *fold_cache;
+
+/* Dispose of the whole FOLD_CACHE.  */
+
+void
+clear_fold_cache (void)
+{
+  if (fold_cache != NULL)
+    fold_cache->empty ();
+}
 
 /*  This function tries to fold an expression X.
     To avoid combinatorial explosion, folding results are kept in fold_cache.
@@ -1923,8 +2053,11 @@ cp_fold (tree x)
   if (DECL_P (x) || CONSTANT_CLASS_P (x))
     return x;
 
-  if (tree cached = fold_cache.get (x))
-    return cached;
+  if (fold_cache == NULL)
+    fold_cache = hash_map<tree, tree>::create_ggc (101);
+
+  if (tree *cached = fold_cache->get (x))
+    return *cached;
 
   code = TREE_CODE (x);
   switch (code)
@@ -1935,6 +2068,7 @@ cp_fold (tree x)
 
     case VIEW_CONVERT_EXPR:
       rval_ops = false;
+      /* FALLTHRU */
     case CONVERT_EXPR:
     case NOP_EXPR:
     case NON_LVALUE_EXPR:
@@ -1945,8 +2079,19 @@ cp_fold (tree x)
       loc = EXPR_LOCATION (x);
       op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops);
 
-      if (op0 != TREE_OPERAND (x, 0))
-        x = fold_build1_loc (loc, code, TREE_TYPE (x), op0);
+      if (code == CONVERT_EXPR
+         && SCALAR_TYPE_P (TREE_TYPE (x))
+         && op0 != void_node)
+       /* During parsing we used convert_to_*_nofold; re-convert now using the
+          folding variants, since fold() doesn't do those transformations.  */
+       x = fold (convert (TREE_TYPE (x), op0));
+      else if (op0 != TREE_OPERAND (x, 0))
+       {
+         if (op0 == error_mark_node)
+           x = error_mark_node;
+         else
+           x = fold_build1_loc (loc, code, TREE_TYPE (x), op0);
+       }
       else
        x = fold (x);
 
@@ -1959,10 +2104,20 @@ cp_fold (tree x)
 
       break;
 
+    case INDIRECT_REF:
+      /* We don't need the decltype(auto) obfuscation anymore.  */
+      if (REF_PARENTHESIZED_P (x))
+       {
+         tree p = maybe_undo_parenthesized_ref (x);
+         return cp_fold (p);
+       }
+      goto unary;
+
     case ADDR_EXPR:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
       rval_ops = false;
+      /* FALLTHRU */
     case CONJ_EXPR:
     case FIX_TRUNC_EXPR:
     case FLOAT_EXPR:
@@ -1971,14 +2126,27 @@ cp_fold (tree x)
     case BIT_NOT_EXPR:
     case TRUTH_NOT_EXPR:
     case FIXED_CONVERT_EXPR:
-    case UNARY_PLUS_EXPR:
-    case INDIRECT_REF:
+    unary:
 
       loc = EXPR_LOCATION (x);
       op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops);
 
       if (op0 != TREE_OPERAND (x, 0))
-        x = fold_build1_loc (loc, code, TREE_TYPE (x), op0);
+       {
+         if (op0 == error_mark_node)
+           x = error_mark_node;
+         else
+           {
+             x = fold_build1_loc (loc, code, TREE_TYPE (x), op0);
+             if (code == INDIRECT_REF
+                 && (INDIRECT_REF_P (x) || TREE_CODE (x) == MEM_REF))
+               {
+                 TREE_READONLY (x) = TREE_READONLY (org_x);
+                 TREE_SIDE_EFFECTS (x) = TREE_SIDE_EFFECTS (org_x);
+                 TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x);
+               }
+           }
+       }
       else
        x = fold (x);
 
@@ -1986,6 +2154,14 @@ cp_fold (tree x)
                  || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))));
       break;
 
+    case UNARY_PLUS_EXPR:
+      op0 = cp_fold_rvalue (TREE_OPERAND (x, 0));
+      if (op0 == error_mark_node)
+       x = error_mark_node;
+      else
+       x = fold_convert (TREE_TYPE (x), op0);
+      break;
+
     case POSTDECREMENT_EXPR:
     case POSTINCREMENT_EXPR:
     case INIT_EXPR:
@@ -1994,6 +2170,7 @@ cp_fold (tree x)
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
       rval_ops = false;
+      /* FALLTHRU */
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -2035,10 +2212,34 @@ cp_fold (tree x)
       op1 = cp_fold_rvalue (TREE_OPERAND (x, 1));
 
       if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
-       x = fold_build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+       {
+         if (op0 == error_mark_node || op1 == error_mark_node)
+           x = error_mark_node;
+         else
+           x = fold_build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+       }
       else
        x = fold (x);
 
+      if (TREE_NO_WARNING (org_x)
+         && warn_nonnull_compare
+         && COMPARISON_CLASS_P (org_x))
+       {
+         if (x == error_mark_node || TREE_CODE (x) == INTEGER_CST)
+           ;
+         else if (COMPARISON_CLASS_P (x))
+           TREE_NO_WARNING (x) = 1;
+         /* Otherwise give up on optimizing these, let GIMPLE folders
+            optimize those later on.  */
+         else if (op0 != TREE_OPERAND (org_x, 0)
+                  || op1 != TREE_OPERAND (org_x, 1))
+           {
+             x = build2_loc (loc, code, TREE_TYPE (org_x), op0, op1);
+             TREE_NO_WARNING (x) = 1;
+           }
+         else
+           x = org_x;
+       }
       break;
 
     case VEC_COND_EXPR:
@@ -2058,10 +2259,23 @@ cp_fold (tree x)
       if (op0 != TREE_OPERAND (x, 0)
          || op1 != TREE_OPERAND (x, 1)
          || op2 != TREE_OPERAND (x, 2))
-       x = fold_build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+       {
+         if (op0 == error_mark_node
+             || op1 == error_mark_node
+             || op2 == error_mark_node)
+           x = error_mark_node;
+         else
+           x = fold_build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+       }
       else
        x = fold (x);
 
+      /* A COND_EXPR might have incompatible types in branches if one or both
+        arms are bitfields.  If folding exposed such a branch, fix it up.  */
+      if (TREE_CODE (x) != code)
+       if (tree type = is_bitfield_expr_with_lowered_type (x))
+         x = fold_convert (type, x);
+
       break;
 
     case CALL_EXPR:
@@ -2085,9 +2299,18 @@ cp_fold (tree x)
          {
            r = cp_fold (CALL_EXPR_ARG (x, i));
            if (r != CALL_EXPR_ARG (x, i))
-             changed = 1;
+             {
+               if (r == error_mark_node)
+                 {
+                   x = error_mark_node;
+                   break;
+                 }
+               changed = 1;
+             }
            CALL_EXPR_ARG (x, i) = r;
          }
+       if (x == error_mark_node)
+         break;
 
        optimize = nw;
        r = fold (x);
@@ -2106,7 +2329,8 @@ cp_fold (tree x)
           TODO:
           Do constexpr expansion of expressions where the call itself is not
           constant, but the call followed by an INDIRECT_REF is.  */
-       if (callee && DECL_DECLARED_CONSTEXPR_P (callee))
+       if (callee && DECL_DECLARED_CONSTEXPR_P (callee)
+           && !flag_no_inline)
           r = maybe_constant_value (x);
        optimize = sv;
 
@@ -2125,9 +2349,30 @@ cp_fold (tree x)
       {
        unsigned i;
        constructor_elt *p;
+       bool changed = false;
        vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x);
+       vec<constructor_elt, va_gc> *nelts = NULL;
+       vec_safe_reserve (nelts, vec_safe_length (elts));
        FOR_EACH_VEC_SAFE_ELT (elts, i, p)
-         p->value = cp_fold (p->value);
+         {
+           tree op = cp_fold (p->value);
+           constructor_elt e = { p->index, op };
+           nelts->quick_push (e);
+           if (op != p->value)
+             {
+               if (op == error_mark_node)
+                 {
+                   x = error_mark_node;
+                   changed = false;
+                   break;
+                 }
+               changed = true;
+             }
+         }
+       if (changed)
+         x = build_constructor (TREE_TYPE (x), nelts);
+       else
+         vec_free (nelts);
        break;
       }
     case TREE_VEC:
@@ -2167,9 +2412,24 @@ cp_fold (tree x)
       op2 = cp_fold (TREE_OPERAND (x, 2));
       op3 = cp_fold (TREE_OPERAND (x, 3));
 
-      if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)
-         || op2 != TREE_OPERAND (x, 2) || op3 != TREE_OPERAND (x, 3))
-       x = build4_loc (loc, code, TREE_TYPE (x), op0, op1, op2, op3);
+      if (op0 != TREE_OPERAND (x, 0)
+         || op1 != TREE_OPERAND (x, 1)
+         || op2 != TREE_OPERAND (x, 2)
+         || op3 != TREE_OPERAND (x, 3))
+       {
+         if (op0 == error_mark_node
+             || op1 == error_mark_node
+             || op2 == error_mark_node
+             || op3 == error_mark_node)
+           x = error_mark_node;
+         else
+           {
+             x = build4_loc (loc, code, TREE_TYPE (x), op0, op1, op2, op3);
+             TREE_READONLY (x) = TREE_READONLY (org_x);
+             TREE_SIDE_EFFECTS (x) = TREE_SIDE_EFFECTS (org_x);
+             TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (org_x);
+           }
+       }
 
       x = fold (x);
       break;
@@ -2178,10 +2438,10 @@ cp_fold (tree x)
       return org_x;
     }
 
-  fold_cache.put (org_x, x);
+  fold_cache->put (org_x, x);
   /* Prevent that we try to fold an already folded result again.  */
   if (x != org_x)
-    fold_cache.put (x, x);
+    fold_cache->put (x, x);
 
   return x;
 }