public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: C++ delayed folding merge
@ 2015-11-09  6:31 ` Jason Merrill
  2015-11-09  9:08   ` Richard Biener
                     ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Jason Merrill @ 2015-11-09  6:31 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches List, Marek Polacek

[-- Attachment #1: Type: text/plain, Size: 731 bytes --]

I'm planning to merge the C++ delayed folding branch this week, but I 
need to get approval of the back end changes (the first patch attached). 
  Most of these are the introduction of non-folding variants of 
convert_to_*, but there are a few others.

One question: The branch changes 'convert' to not fold its result, and 
it's not clear to me whether that's part of the expected behavior of a 
front end 'convert' function or not.

Also, I'm a bit uncertain about merging this at the end of stage 1, 
since it's a large internal change with relatively small user impact; it 
just improves handling of constant expression corner cases.  I'm 
inclined to go ahead with it at this point, but I'm interested in 
contrary opinions.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: df-back.patch --]
[-- Type: text/x-patch; name="df-back.patch", Size: 124111 bytes --]

diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index ae16cfc..d8c7faf 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -930,8 +930,9 @@ interpret_float (const cpp_token *token, unsigned int flags,
   value = build_real (const_type, real);
   if (flags & CPP_N_IMAGINARY)
     {
-      value = build_complex (NULL_TREE, convert (const_type,
-						 integer_zero_node), value);
+      value = build_complex (NULL_TREE,
+			     fold_convert (const_type,
+					   integer_zero_node), value);
       if (type != const_type)
 	{
 	  const_type = TREE_TYPE (value);
diff --git a/gcc/convert.c b/gcc/convert.c
index 113c11f..298d1e4 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -34,12 +34,20 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "ubsan.h"
 
+#define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
+  ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR)	     \
+   : build1_loc (LOC, CODE, TYPE, EXPR))
+#define maybe_fold_build2_loc(FOLD_P, LOC, CODE, TYPE, EXPR1, EXPR2) \
+  ((FOLD_P) ? fold_build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2)	     \
+   : build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2))
+
 /* Convert EXPR to some pointer or reference type TYPE.
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
-   in other cases error is called.  */
+   in other cases error is called.  If FOLD_P is true, try to fold the
+   expression.  */
 
-tree
-convert_to_pointer (tree type, tree expr)
+static tree
+convert_to_pointer_1 (tree type, tree expr, bool fold_p)
 {
   location_t loc = EXPR_LOCATION (expr);
   if (TREE_TYPE (expr) == type)
@@ -56,9 +64,10 @@ convert_to_pointer (tree type, tree expr)
 	addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
 
 	if (to_as == from_as)
-	  return fold_build1_loc (loc, NOP_EXPR, type, expr);
+	  return maybe_fold_build1_loc (fold_p, loc, NOP_EXPR, type, expr);
 	else
-	  return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr);
+	  return maybe_fold_build1_loc (fold_p, loc, ADDR_SPACE_CONVERT_EXPR,
+					type, expr);
       }
 
     case INTEGER_TYPE:
@@ -72,35 +81,54 @@ convert_to_pointer (tree type, tree expr)
 	unsigned int pprec = TYPE_PRECISION (type);
 	unsigned int eprec = TYPE_PRECISION (TREE_TYPE (expr));
 
- 	if (eprec != pprec)
-	  expr = fold_build1_loc (loc, NOP_EXPR,
-			      lang_hooks.types.type_for_size (pprec, 0),
-			      expr);
+	if (eprec != pprec)
+	  expr
+	    = maybe_fold_build1_loc (fold_p, loc, NOP_EXPR,
+				     lang_hooks.types.type_for_size (pprec, 0),
+				     expr);
       }
-
-      return fold_build1_loc (loc, CONVERT_EXPR, type, expr);
+      return maybe_fold_build1_loc (fold_p, loc, CONVERT_EXPR, type, expr);
 
     default:
       error ("cannot convert to a pointer type");
-      return convert_to_pointer (type, integer_zero_node);
+      return convert_to_pointer_1 (type, integer_zero_node, fold_p);
     }
 }
 
+/* A wrapper around convert_to_pointer_1 that always folds the
+   expression.  */
+
+tree
+convert_to_pointer (tree type, tree expr)
+{
+  return convert_to_pointer_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_pointer_1 that only folds the
+   expression if it is CONSTANT_CLASS_P.  */
+
+tree
+convert_to_pointer_nofold (tree type, tree expr)
+{
+  return convert_to_pointer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
 
 /* Convert EXPR to some floating-point type TYPE.
 
    EXPR must be float, fixed-point, integer, or enumeral;
-   in other cases error is called.  */
+   in other cases error is called.  If FOLD_P is true, try to fold
+   the expression.  */
 
-tree
-convert_to_real (tree type, tree expr)
+static tree
+convert_to_real_1 (tree type, tree expr, bool fold_p)
 {
   enum built_in_function fcode = builtin_mathfn_code (expr);
   tree itype = TREE_TYPE (expr);
+  location_t loc = EXPR_LOCATION (expr);
 
   if (TREE_CODE (expr) == COMPOUND_EXPR)
     {
-      tree t = convert_to_real (type, TREE_OPERAND (expr, 1));
+      tree t = convert_to_real_1 (type, TREE_OPERAND (expr, 1), fold_p);
       if (t == TREE_OPERAND (expr, 1))
 	return expr;
       return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -208,14 +236,13 @@ convert_to_real (tree type, tree expr)
 		      || TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
 		{
 		  tree fn = mathfn_built_in (newtype, fcode);
-
 		  if (fn)
-		  {
-		    tree arg = fold (convert_to_real (newtype, arg0));
-		    expr = build_call_expr (fn, 1, arg);
-		    if (newtype == type)
-		      return expr;
-		  }
+		    {
+		      tree arg = convert_to_real_1 (newtype, arg0, fold_p);
+		      expr = build_call_expr (fn, 1, arg);
+		      if (newtype == type)
+			return expr;
+		    }
 		}
 	    }
 	default:
@@ -234,9 +261,11 @@ convert_to_real (tree type, tree expr)
 	  if (!flag_rounding_math
 	      && FLOAT_TYPE_P (itype)
 	      && TYPE_PRECISION (type) < TYPE_PRECISION (itype))
-	    return build1 (TREE_CODE (expr), type,
-			   fold (convert_to_real (type,
-						  TREE_OPERAND (expr, 0))));
+	    {
+	      tree arg = convert_to_real_1 (type, TREE_OPERAND (expr, 0),
+					    fold_p);
+	      return build1 (TREE_CODE (expr), type, arg);
+	    }
 	  break;
 	/* Convert (outertype)((innertype0)a+(innertype1)b)
 	   into ((newtype)a+(newtype)b) where newtype
@@ -272,8 +301,10 @@ convert_to_real (tree type, tree expr)
 		      || newtype == dfloat128_type_node)
 		    {
 		      expr = build2 (TREE_CODE (expr), newtype,
-				     fold (convert_to_real (newtype, arg0)),
-				     fold (convert_to_real (newtype, arg1)));
+				     convert_to_real_1 (newtype, arg0,
+							fold_p),
+				     convert_to_real_1 (newtype, arg1,
+							fold_p));
 		      if (newtype == type)
 			return expr;
 		      break;
@@ -312,8 +343,10 @@ convert_to_real (tree type, tree expr)
 			      && !excess_precision_type (newtype))))
 		    {
 		      expr = build2 (TREE_CODE (expr), newtype,
-				     fold (convert_to_real (newtype, arg0)),
-				     fold (convert_to_real (newtype, arg1)));
+				     convert_to_real_1 (newtype, arg0,
+							fold_p),
+				     convert_to_real_1 (newtype, arg1,
+							fold_p));
 		      if (newtype == type)
 			return expr;
 		    }
@@ -344,30 +377,51 @@ convert_to_real (tree type, tree expr)
 
     case COMPLEX_TYPE:
       return convert (type,
-		      fold_build1 (REALPART_EXPR,
-				   TREE_TYPE (TREE_TYPE (expr)), expr));
+		      maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+					     TREE_TYPE (TREE_TYPE (expr)),
+					     expr));
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       error ("pointer value used where a floating point value was expected");
-      return convert_to_real (type, integer_zero_node);
+      return convert_to_real_1 (type, integer_zero_node, fold_p);
 
     default:
       error ("aggregate value used where a float was expected");
-      return convert_to_real (type, integer_zero_node);
+      return convert_to_real_1 (type, integer_zero_node, fold_p);
     }
 }
 
+/* A wrapper around convert_to_real_1 that always folds the
+   expression.  */
+
+tree
+convert_to_real (tree type, tree expr)
+{
+  return convert_to_real_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_real_1 that only folds the
+   expression if it is CONSTANT_CLASS_P.  */
+
+tree
+convert_to_real_nofold (tree type, tree expr)
+{
+  return convert_to_real_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
 /* Convert EXPR to some integer (or enum) type TYPE.
 
    EXPR must be pointer, integer, discrete (enum, char, or bool), float,
    fixed-point or vector; in other cases error is called.
 
+   If DOFOLD is TRUE, we try to simplify newly-created patterns by folding.
+
    The result of this is always supposed to be a newly created tree node
    not in use in any existing structure.  */
 
-tree
-convert_to_integer (tree type, tree expr)
+static tree
+convert_to_integer_1 (tree type, tree expr, bool dofold)
 {
   enum tree_code ex_form = TREE_CODE (expr);
   tree intype = TREE_TYPE (expr);
@@ -385,7 +439,7 @@ convert_to_integer (tree type, tree expr)
 
   if (ex_form == COMPOUND_EXPR)
     {
-      tree t = convert_to_integer (type, TREE_OPERAND (expr, 1));
+      tree t = convert_to_integer_1 (type, TREE_OPERAND (expr, 1), dofold);
       if (t == TREE_OPERAND (expr, 1))
 	return expr;
       return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -479,7 +533,7 @@ convert_to_integer (tree type, tree expr)
 	  break;
 
 	CASE_FLT_FN (BUILT_IN_TRUNC):
-	  return convert_to_integer (type, CALL_EXPR_ARG (s_expr, 0));
+	  return convert_to_integer_1 (type, CALL_EXPR_ARG (s_expr, 0), dofold);
 
 	default:
 	  break;
@@ -488,7 +542,7 @@ convert_to_integer (tree type, tree expr)
       if (fn)
         {
 	  tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
-	  return convert_to_integer (type, newexpr);
+	  return convert_to_integer_1 (type, newexpr, dofold);
 	}
     }
 
@@ -519,7 +573,7 @@ convert_to_integer (tree type, tree expr)
       if (fn)
         {
 	  tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
-	  return convert_to_integer (type, newexpr);
+	  return convert_to_integer_1 (type, newexpr, dofold);
 	}
     }
 
@@ -534,6 +588,8 @@ convert_to_integer (tree type, tree expr)
 	 there widen/truncate to the required type.  Some targets support the
 	 coexistence of multiple valid pointer sizes, so fetch the one we need
 	 from the type.  */
+      if (!dofold)
+	return build1 (CONVERT_EXPR, type, expr);
       expr = fold_build1 (CONVERT_EXPR,
 			  lang_hooks.types.type_for_size
 			    (TYPE_PRECISION (intype), 0),
@@ -578,6 +634,8 @@ convert_to_integer (tree type, tree expr)
 	  else
 	    code = NOP_EXPR;
 
+	  if (!dofold)
+	    return build1 (code, type, expr);
 	  return fold_build1 (code, type, expr);
 	}
 
@@ -784,10 +842,17 @@ convert_to_integer (tree type, tree expr)
 			if (TYPE_UNSIGNED (typex))
 			  typex = signed_type_for (typex);
 		      }
-		    return convert (type,
-				    fold_build2 (ex_form, typex,
-						 convert (typex, arg0),
-						 convert (typex, arg1)));
+		    /* We should do away with all this once we have a proper
+		       type promotion/demotion pass, see PR45397.  */
+		    if (dofold)
+		      return convert (type,
+				      fold_build2 (ex_form, typex,
+						   convert (typex, arg0),
+						   convert (typex, arg1)));
+		    arg0 = build1 (CONVERT_EXPR, typex, arg0);
+		    arg1 = build1 (CONVERT_EXPR, typex, arg1);
+		    expr = build2 (ex_form, typex, arg0, arg1);
+		    return build1 (CONVERT_EXPR, type, expr);
 		  }
 	      }
 	  }
@@ -798,6 +863,9 @@ convert_to_integer (tree type, tree expr)
 	  /* This is not correct for ABS_EXPR,
 	     since we must test the sign before truncation.  */
 	  {
+	    if (!dofold)
+	      break;
+
 	    /* Do the arithmetic in type TYPEX,
 	       then convert result to TYPE.  */
 	    tree typex = type;
@@ -813,7 +881,7 @@ convert_to_integer (tree type, tree expr)
 	      typex = unsigned_type_for (typex);
 	    return convert (type,
 			    fold_build1 (ex_form, typex,
-					 convert (typex,
+					  convert (typex,
 						  TREE_OPERAND (expr, 0))));
 	  }
 
@@ -833,13 +901,15 @@ convert_to_integer (tree type, tree expr)
 	     the conditional and never loses.  A COND_EXPR may have a throw
 	     as one operand, which then has void type.  Just leave void
 	     operands as they are.  */
-	  return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
-			      VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
-			      ? TREE_OPERAND (expr, 1)
-			      : convert (type, TREE_OPERAND (expr, 1)),
-			      VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
-			      ? TREE_OPERAND (expr, 2)
-			      : convert (type, TREE_OPERAND (expr, 2)));
+	  if (dofold)
+	    return
+	      fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
+			   VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
+			   ? TREE_OPERAND (expr, 1)
+			   : convert (type, TREE_OPERAND (expr, 1)),
+			   VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
+			   ? TREE_OPERAND (expr, 2)
+			   : convert (type, TREE_OPERAND (expr, 2)));
 
 	default:
 	  break;
@@ -860,6 +930,8 @@ convert_to_integer (tree type, tree expr)
 	  expr = build1 (FIX_TRUNC_EXPR, type, expr);
 	  if (check == NULL)
 	    return expr;
+	  if (!dofold)
+	    return build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
 	  return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
 	}
       else
@@ -869,6 +941,10 @@ convert_to_integer (tree type, tree expr)
       return build1 (FIXED_CONVERT_EXPR, type, expr);
 
     case COMPLEX_TYPE:
+      if (!dofold)
+	return convert (type,
+			build1 (REALPART_EXPR,
+				TREE_TYPE (TREE_TYPE (expr)), expr));
       return convert (type,
 		      fold_build1 (REALPART_EXPR,
 				   TREE_TYPE (TREE_TYPE (expr)), expr));
@@ -889,11 +965,42 @@ convert_to_integer (tree type, tree expr)
     }
 }
 
-/* Convert EXPR to the complex type TYPE in the usual ways.  */
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+   EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+   fixed-point or vector; in other cases error is called.
+
+   The result of this is always supposed to be a newly created tree node
+   not in use in any existing structure.  */
 
 tree
-convert_to_complex (tree type, tree expr)
+convert_to_integer (tree type, tree expr)
+{
+  return convert_to_integer_1 (type, expr, true);
+}
+
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+   EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+   fixed-point or vector; in other cases error is called.
+
+   The result of this is always supposed to be a newly created tree node
+   not in use in any existing structure.  The tree node isn't folded,
+   beside EXPR is of constant class.  */
+
+tree
+convert_to_integer_nofold (tree type, tree expr)
+{
+  return convert_to_integer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
+/* Convert EXPR to the complex type TYPE in the usual ways.  If FOLD_P is
+   true, try to fold the expression.  */
+
+static tree
+convert_to_complex_1 (tree type, tree expr, bool fold_p)
 {
+  location_t loc = EXPR_LOCATION (expr);
   tree subtype = TREE_TYPE (type);
 
   switch (TREE_CODE (TREE_TYPE (expr)))
@@ -914,43 +1021,63 @@ convert_to_complex (tree type, tree expr)
 	  return expr;
 	else if (TREE_CODE (expr) == COMPOUND_EXPR)
 	  {
-	    tree t = convert_to_complex (type, TREE_OPERAND (expr, 1));
+	    tree t = convert_to_complex_1 (type, TREE_OPERAND (expr, 1),
+					   fold_p);
 	    if (t == TREE_OPERAND (expr, 1))
 	      return expr;
 	    return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR,
 			       TREE_TYPE (t), TREE_OPERAND (expr, 0), t);
-	  }    
+	  }
 	else if (TREE_CODE (expr) == COMPLEX_EXPR)
-	  return fold_build2 (COMPLEX_EXPR, type,
-			      convert (subtype, TREE_OPERAND (expr, 0)),
-			      convert (subtype, TREE_OPERAND (expr, 1)));
+	  return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+					convert (subtype,
+						 TREE_OPERAND (expr, 0)),
+					convert (subtype,
+						 TREE_OPERAND (expr, 1)));
 	else
 	  {
 	    expr = save_expr (expr);
-	    return
-	      fold_build2 (COMPLEX_EXPR, type,
-			   convert (subtype,
-				    fold_build1 (REALPART_EXPR,
-						 TREE_TYPE (TREE_TYPE (expr)),
-						 expr)),
-			   convert (subtype,
-				    fold_build1 (IMAGPART_EXPR,
-						 TREE_TYPE (TREE_TYPE (expr)),
-						 expr)));
+	    tree realp = maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+						TREE_TYPE (TREE_TYPE (expr)),
+						expr);
+	    tree imagp = maybe_fold_build1_loc (fold_p, loc, IMAGPART_EXPR,
+						TREE_TYPE (TREE_TYPE (expr)),
+						expr);
+	    return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+					  convert (subtype, realp),
+					  convert (subtype, imagp));
 	  }
       }
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       error ("pointer value used where a complex was expected");
-      return convert_to_complex (type, integer_zero_node);
+      return convert_to_complex_1 (type, integer_zero_node, fold_p);
 
     default:
       error ("aggregate value used where a complex was expected");
-      return convert_to_complex (type, integer_zero_node);
+      return convert_to_complex_1 (type, integer_zero_node, fold_p);
     }
 }
 
+/* A wrapper around convert_to_complex_1 that always folds the
+   expression.  */
+
+tree
+convert_to_complex (tree type, tree expr)
+{
+  return convert_to_complex_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_complex_1 that only folds the
+   expression if it is CONSTANT_CLASS_P.  */
+
+tree
+convert_to_complex_nofold (tree type, tree expr)
+{
+  return convert_to_complex_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
 /* Convert EXPR to the vector type TYPE in the usual ways.  */
 
 tree
diff --git a/gcc/convert.h b/gcc/convert.h
index f2e4a65..7cc3168 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -21,10 +21,14 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_CONVERT_H
 
 extern tree convert_to_integer (tree, tree);
+extern tree convert_to_integer_nofold (tree, tree);
 extern tree convert_to_pointer (tree, tree);
+extern tree convert_to_pointer_nofold (tree, tree);
 extern tree convert_to_real (tree, tree);
+extern tree convert_to_real_nofold (tree, tree);
 extern tree convert_to_fixed (tree, tree);
 extern tree convert_to_complex (tree, tree);
+extern tree convert_to_complex_nofold (tree, tree);
 extern tree convert_to_vector (tree, tree);
 
 #endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0b7d143..536989b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4747,7 +4747,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 	  tree cmp_type = build_same_sized_truth_vector_type (arg1_type);
 	  arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type));
 	}
-      return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
+      return build3_loc (loc, VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
     }
 
   /* [expr.cond]
@@ -5151,9 +5151,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 
  valid_operands:
   result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
-  if (!cp_unevaluated_operand)
-    /* Avoid folding within decltype (c++/42013) and noexcept.  */
-    result = fold_if_not_in_template (result);
 
   /* We can't use result_type below, as fold might have returned a
      throw_expr.  */
@@ -5689,8 +5686,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 		 decaying an enumerator to its value.  */
 	      if (complain & tf_warning)
 		warn_logical_operator (loc, code, boolean_type_node,
-				       code_orig_arg1, arg1,
-				       code_orig_arg2, arg2);
+				       code_orig_arg1, fold (arg1),
+				       code_orig_arg2, fold (arg2));
 
 	      arg2 = convert_like (conv, arg2, complain);
 	    }
@@ -5728,7 +5725,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     case TRUTH_OR_EXPR:
       if (complain & tf_warning)
 	warn_logical_operator (loc, code, boolean_type_node,
-			       code_orig_arg1, arg1, code_orig_arg2, arg2);
+			       code_orig_arg1, fold (arg1), code_orig_arg2, fold (arg2));
       /* Fall through.  */
     case GT_EXPR:
     case LT_EXPR:
@@ -5739,9 +5736,10 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
       if ((complain & tf_warning)
 	  && ((code_orig_arg1 == BOOLEAN_TYPE)
 	      ^ (code_orig_arg2 == BOOLEAN_TYPE)))
-	maybe_warn_bool_compare (loc, code, arg1, arg2);
+	maybe_warn_bool_compare (loc, code, fold (arg1),
+				 fold (arg2));
       if (complain & tf_warning && warn_tautological_compare)
-	warn_tautological_cmp (loc, code, arg1, arg2);
+	warn_tautological_cmp (loc, code, fold (arg1), fold (arg2));
       /* Fall through.  */
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -6495,7 +6493,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	  imag = perform_implicit_conversion (TREE_TYPE (totype),
 					      imag, complain);
 	  expr = build2 (COMPLEX_EXPR, totype, real, imag);
-	  return fold_if_not_in_template (expr);
+	  return expr;
 	}
       expr = reshape_init (totype, expr, complain);
       expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
@@ -6736,7 +6734,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
 		    "implicit conversion from %qT to %qT when passing "
 		    "argument to function",
 		    arg_type, double_type_node);
-      arg = convert_to_real (double_type_node, arg);
+      arg = convert_to_real_nofold (double_type_node, arg);
     }
   else if (NULLPTR_TYPE_P (arg_type))
     arg = null_pointer_node;
@@ -6981,7 +6979,7 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
   bitfield_type = is_bitfield_expr_with_lowered_type (val);
   if (bitfield_type 
       && TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
-    val = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), val);
+    val = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), val);
 
   if (val == error_mark_node)
     ;
@@ -7501,7 +7499,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   gcc_assert (j <= nargs);
   nargs = j;
 
-  check_function_arguments (TREE_TYPE (fn), nargs, argarray);
+  /* Avoid to do argument-transformation, if warnings for format, and for
+     nonnull are disabled.  Just in case that at least one of them is active
+     the check_function_arguments function might warn about something.  */
+
+  if (warn_nonnull || warn_format || warn_suggest_attribute_format)
+    {
+      tree *fargs = (!nargs ? argarray
+			    : (tree *) alloca (nargs * sizeof (tree)));
+      for (j = 0; j < nargs; j++)
+	fargs[j] = maybe_constant_value (argarray[j]);
+
+      check_function_arguments (TREE_TYPE (fn), nargs, fargs);
+    }
 
   /* Avoid actually calling copy constructors and copy assignment operators,
      if possible.  */
@@ -7692,7 +7702,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
 		tsubst_flags_t complain)
 {
   tree fndecl;
-  int optimize_sav;
 
   /* Remember roughly where this call is.  */
   location_t loc = EXPR_LOC_OR_LOC (fn, input_location);
@@ -7704,9 +7713,18 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
   /* Check that arguments to builtin functions match the expectations.  */
   if (fndecl
       && DECL_BUILT_IN (fndecl)
-      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-      && !check_builtin_function_arguments (fndecl, nargs, argarray))
-    return error_mark_node;
+      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      int i;
+
+      /* We need to take care that values to BUILT_IN_NORMAL
+         are reduced.  */
+      for (i = 0; i < nargs; i++)
+	argarray[i] = maybe_constant_value (argarray[i]);
+
+      if (!check_builtin_function_arguments (fndecl, nargs, argarray))
+	return error_mark_node;
+    }
 
     /* If it is a built-in array notation function, then the return type of
      the function is the element type of the array passed in as array 
@@ -7740,17 +7758,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
 	}
     }
 
-  /* Some built-in function calls will be evaluated at compile-time in
-     fold ().  Set optimize to 1 when folding __builtin_constant_p inside
-     a constexpr function so that fold_builtin_1 doesn't fold it to 0.  */
-  optimize_sav = optimize;
-  if (!optimize && fndecl && DECL_IS_BUILTIN_CONSTANT_P (fndecl)
-      && current_function_decl
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
-    optimize = 1;
-  fn = fold_if_not_in_template (fn);
-  optimize = optimize_sav;
-
   if (VOID_TYPE_P (TREE_TYPE (fn)))
     return fn;
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b123932..b5cf996 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -423,7 +423,7 @@ build_base_path (enum tree_code code,
 
 	  t = TREE_TYPE (TYPE_VFIELD (current_class_type));
 	  t = build_pointer_type (t);
-	  v_offset = convert (t, current_vtt_parm);
+	  v_offset = fold_convert (t, current_vtt_parm);
 	  v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
 	}
       else
@@ -556,8 +556,6 @@ build_simple_base_path (tree expr, tree binfo)
 	expr = build3 (COMPONENT_REF,
 		       cp_build_qualified_type (type, type_quals),
 		       expr, field, NULL_TREE);
-	expr = fold_if_not_in_template (expr);
-
 	/* Mark the expression const or volatile, as appropriate.
 	   Even though we've dealt with the type above, we still have
 	   to mark the expression itself.  */
@@ -1849,9 +1847,9 @@ determine_primary_bases (tree t)
 		 another hierarchy. As we're about to use it as a
 		 primary base, make sure the offsets match.  */
 	      delta = size_diffop_loc (input_location,
-				   convert (ssizetype,
+				   fold_convert (ssizetype,
 					    BINFO_OFFSET (base_binfo)),
-				   convert (ssizetype,
+				   fold_convert (ssizetype,
 					    BINFO_OFFSET (this_primary)));
 
 	      propagate_binfo_offsets (this_primary, delta);
@@ -1913,7 +1911,7 @@ determine_primary_bases (tree t)
 	     another hierarchy. As we're about to use it as a primary
 	     base, make sure the offsets match.  */
 	  delta = size_diffop_loc (input_location, ssize_int (0),
-			       convert (ssizetype, BINFO_OFFSET (primary)));
+			       fold_convert (ssizetype, BINFO_OFFSET (primary)));
 
 	  propagate_binfo_offsets (primary, delta);
 	}
@@ -2637,7 +2635,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
 	  if (virtual_offset
 	      || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
 	    {
-	      tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
+	      tree offset = fold_convert (ssizetype, BINFO_OFFSET (thunk_binfo));
 
 	      if (virtual_offset)
 		{
@@ -2645,7 +2643,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
 		     offset to be from there.  */
 		  offset = 
 		    size_diffop (offset,
-				 convert (ssizetype,
+				 fold_convert (ssizetype,
 					  BINFO_OFFSET (virtual_offset)));
 		}
 	      if (fixed_offset)
@@ -2734,8 +2732,8 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
     /* The `this' pointer needs to be adjusted from the declaration to
        the nearest virtual base.  */
     delta = size_diffop_loc (input_location,
-			 convert (ssizetype, BINFO_OFFSET (virtual_base)),
-			 convert (ssizetype, BINFO_OFFSET (first_defn)));
+			 fold_convert (ssizetype, BINFO_OFFSET (virtual_base)),
+			 fold_convert (ssizetype, BINFO_OFFSET (first_defn)));
   else if (lost)
     /* If the nearest definition is in a lost primary, we don't need an
        entry in our vtable.  Except possibly in a constructor vtable,
@@ -2747,9 +2745,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
        BINFO to pointing at the base where the final overrider
        appears.  */
     delta = size_diffop_loc (input_location,
-			 convert (ssizetype,
+			 fold_convert (ssizetype,
 				  BINFO_OFFSET (TREE_VALUE (overrider))),
-			 convert (ssizetype, BINFO_OFFSET (binfo)));
+			 fold_convert (ssizetype, BINFO_OFFSET (binfo)));
 
   modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
 
@@ -3471,7 +3469,7 @@ check_bitfield_decl (tree field)
 
   if (w != error_mark_node)
     {
-      DECL_SIZE (field) = convert (bitsizetype, w);
+      DECL_SIZE (field) = fold_convert (bitsizetype, w);
       DECL_BIT_FIELD (field) = 1;
       return true;
     }
@@ -4316,8 +4314,8 @@ layout_nonempty_base_or_field (record_layout_info rli,
        OFFSET.  */
     propagate_binfo_offsets (binfo,
 			     size_diffop_loc (input_location,
-					  convert (ssizetype, offset),
-					  convert (ssizetype,
+					  fold_convert (ssizetype, offset),
+					  fold_convert (ssizetype,
 						   BINFO_OFFSET (binfo))));
 }
 
@@ -4364,7 +4362,7 @@ layout_empty_base (record_layout_info rli, tree binfo,
       /* That didn't work.  Now, we move forward from the next
 	 available spot in the class.  */
       atend = true;
-      propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
+      propagate_binfo_offsets (binfo, fold_convert (ssizetype, eoc));
       while (1)
 	{
 	  if (!layout_conflict_p (binfo,
@@ -5978,9 +5976,9 @@ propagate_binfo_offsets (tree binfo, tree offset)
 
   /* Update BINFO's offset.  */
   BINFO_OFFSET (binfo)
-    = convert (sizetype,
+    = fold_convert (sizetype,
 	       size_binop (PLUS_EXPR,
-			   convert (ssizetype, BINFO_OFFSET (binfo)),
+			   fold_convert (ssizetype, BINFO_OFFSET (binfo)),
 			   offset));
 
   /* Find the primary base class.  */
@@ -6185,7 +6183,7 @@ include_empty_classes (record_layout_info rli)
 	= size_binop (PLUS_EXPR,
 		      rli->bitpos,
 		      size_binop (MULT_EXPR,
-				  convert (bitsizetype,
+				  fold_convert (bitsizetype,
 					   size_binop (MINUS_EXPR,
 						       eoc, rli_size)),
 				  bitsize_int (BITS_PER_UNIT)));
@@ -6459,7 +6457,7 @@ layout_class_type (tree t, tree *virtuals_p)
       eoc = end_of_class (t, /*include_virtuals_p=*/0);
       TYPE_SIZE_UNIT (base_t)
 	= size_binop (MAX_EXPR,
-		      convert (sizetype,
+		      fold_convert (sizetype,
 			       size_binop (CEIL_DIV_EXPR,
 					   rli_size_so_far (rli),
 					   bitsize_int (BITS_PER_UNIT))),
@@ -6468,7 +6466,7 @@ layout_class_type (tree t, tree *virtuals_p)
 	= size_binop (MAX_EXPR,
 		      rli_size_so_far (rli),
 		      size_binop (MULT_EXPR,
-				  convert (bitsizetype, eoc),
+				  fold_convert (bitsizetype, eoc),
 				  bitsize_int (BITS_PER_UNIT)));
       TYPE_ALIGN (base_t) = rli->record_align;
       TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
@@ -9304,7 +9302,7 @@ build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
       /* Figure out where we can find this vbase offset.  */
       delta = size_binop (MULT_EXPR,
 			  vid->index,
-			  convert (ssizetype,
+			  fold_convert (ssizetype,
 				   TYPE_SIZE_UNIT (vtable_entry_type)));
       if (vid->primary_vtbl_p)
 	BINFO_VPTR_FIELD (b) = delta;
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 51fae5a..eefe322 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1037,6 +1037,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
   force_folding_builtin_constant_p = true;
   new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
 					CALL_EXPR_FN (t), nargs, args);
+  /* Fold away the NOP_EXPR from fold_builtin_n.  */
+  new_call = fold (new_call);
   force_folding_builtin_constant_p = save_ffbcp;
   VERIFY_CONSTANT (new_call);
   return new_call;
@@ -1277,6 +1279,15 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       ctx->values->put (new_ctx.object, ctor);
       ctx = &new_ctx;
     }
+  else if (DECL_BY_REFERENCE (DECL_RESULT (fun))
+	   && TREE_CODE (t) != AGGR_INIT_EXPR)
+    {
+      /* convert_to_void stripped our AGGR_INIT_EXPR, in which case we don't
+	 care about a constant value.  */
+      gcc_assert (ctx->quiet && !ctx->object);
+      *non_constant_p = true;
+      return t;
+    }
 
   bool non_constant_args = false;
   cxx_bind_parameters_in_call (ctx, t, &new_call,
@@ -2542,6 +2553,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   tree orig_op0 = TREE_OPERAND (t, 0);
   bool empty_base = false;
 
+  /* We can handle a MEM_REF like an INDIRECT_REF, if MEM_REF's second
+     operand is an integer-zero.  Otherwise reject the MEM_REF for now.  */
+
+  if (TREE_CODE (t) == MEM_REF
+      && (!TREE_OPERAND (t, 1) || !integer_zerop (TREE_OPERAND (t, 1))))
+    {
+      gcc_assert (ctx->quiet);
+      *non_constant_p = true;
+      return t;
+    }
+
   /* First try to simplify it directly.  */
   tree r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), orig_op0,
 				  &empty_base);
@@ -3075,6 +3097,8 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
   if (TREE_CODE (op00) != ADDR_EXPR)
     return NULL_TREE;
 
+  op01 = cxx_eval_constant_expression (ctx, op01, lval,
+				       non_constant_p, overflow_p);
   op00 = TREE_OPERAND (op00, 0);
 
   /* &A[i] p+ j => &A[i + j] */
@@ -3112,6 +3136,26 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
   return NULL_TREE;
 }
 
+/* Reduce a SIZEOF_EXPR to its value.  */
+
+tree
+fold_sizeof_expr (tree t)
+{
+  tree r;
+  if (SIZEOF_EXPR_TYPE_P (t))
+    r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+				    SIZEOF_EXPR, false);
+  else if (TYPE_P (TREE_OPERAND (t, 0)))
+    r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+				    false);
+  else
+    r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR,
+				    false);
+  if (r == error_mark_node)
+    r = size_one_node;
+  return r;
+}
+
 /* Attempt to reduce the expression T to a constant value.
    On failure, issue diagnostic and return error_mark_node.  */
 /* FIXME unify with c_fully_fold */
@@ -3335,6 +3379,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       /* 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.  */
+    case MEM_REF:
     case INDIRECT_REF:
       r = cxx_eval_indirect_ref (ctx, t, lval,
 				 non_constant_p, overflow_p);
@@ -3372,17 +3417,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case SIZEOF_EXPR:
-      if (SIZEOF_EXPR_TYPE_P (t))
-	r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
-					SIZEOF_EXPR, false);
-      else if (TYPE_P (TREE_OPERAND (t, 0)))
-	r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR,
-					false);
-      else
-	r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR,
-					false);
-      if (r == error_mark_node)
-	r = size_one_node;
+      r = fold_sizeof_expr (t);
       VERIFY_CONSTANT (r);
       break;
 
@@ -3540,8 +3575,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
     case NOP_EXPR:
+    case UNARY_PLUS_EXPR:
       {
+	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
+
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						lval,
 						non_constant_p, overflow_p);
@@ -3561,11 +3599,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	    *non_constant_p = true;
 	    return t;
 	  }
-	if (op == oldop)
+	if (op == oldop && tcode != UNARY_PLUS_EXPR)
 	  /* We didn't fold at the top so we could check for ptr-int
 	     conversion.  */
 	  return fold (t);
-	r = fold_build1 (TREE_CODE (t), type, op);
+	if (tcode == UNARY_PLUS_EXPR)
+	  r = fold_convert (TREE_TYPE (t), op);
+	else
+	  r = fold_build1 (tcode, type, op);
 	/* Conversion of an out-of-range value has implementation-defined
 	   behavior; the language considers it different from arithmetic
 	   overflow, which is undefined.  */
@@ -3833,12 +3874,86 @@ cxx_constant_value (tree t, tree decl)
   return cxx_eval_outermost_constant_expr (t, false, true, decl);
 }
 
+/* Helper routine for fold_simple function.  Either return simplified
+   expression T, otherwise NULL_TREE.
+   In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
+   even if we are within template-declaration.  So be careful on call, as in
+   such case types can be undefined.  */
+
+static tree
+fold_simple_1 (tree t)
+{
+  tree op1;
+  enum tree_code code = TREE_CODE (t);
+
+  switch (code)
+    {
+    case INTEGER_CST:
+    case REAL_CST:
+    case VECTOR_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+      return t;
+
+    case SIZEOF_EXPR:
+      return fold_sizeof_expr (t);
+
+    case ABS_EXPR:
+    case CONJ_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case NOP_EXPR:
+    case VIEW_CONVERT_EXPR:
+    case CONVERT_EXPR:
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
+
+      op1 = TREE_OPERAND (t, 0);
+
+      t = const_unop (code, TREE_TYPE (t), op1);
+      if (!t)
+	return NULL_TREE;
+
+      if (CONVERT_EXPR_CODE_P (code)
+	  && TREE_OVERFLOW_P (t) && !TREE_OVERFLOW_P (op1))
+	TREE_OVERFLOW (t) = false;
+      return t;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* If T is a simple constant expression, returns its simplified value.
+   Otherwise returns T.  In contrast to maybe_constant_value do we
+   simplify only few operations on constant-expressions, and we don't
+   try to simplify constexpressions.  */
+
+tree
+fold_simple (tree t)
+{
+  tree r = NULL_TREE;
+  if (processing_template_decl)
+    return t;
+
+  r = fold_simple_1 (t);
+  if (!r)
+    r = t;
+
+  return r;
+}
+
 /* If T is a constant expression, returns its reduced value.
    Otherwise, if T does not have TREE_CONSTANT set, returns T.
    Otherwise, returns a version of T without TREE_CONSTANT.  */
 
-tree
-maybe_constant_value (tree t, tree decl)
+static tree
+maybe_constant_value_1 (tree t, tree decl)
 {
   tree r;
 
@@ -3864,6 +3979,56 @@ maybe_constant_value (tree t, tree decl)
   return r;
 }
 
+/* If T is a constant expression, returns its reduced value.
+   Otherwise, if T does not have TREE_CONSTANT set, returns T.
+   Otherwise, returns a version of T without TREE_CONSTANT.  */
+
+tree
+maybe_constant_value (tree t, tree decl)
+{
+  tree ret;
+  hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+  hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+  /* If current scope has a hash_map, but it was for different CFUN,
+     then destroy hash_map to avoid issues with ggc_collect.  */
+  if ((cv || ctx) && scope_chain->act_cfun != cfun)
+    {
+      if (ctx)
+	delete ctx;
+      if (cv)
+	delete cv;
+      ctx = NULL;
+      scope_chain->act_cfun = NULL;
+      scope_chain->fold_map = NULL;
+      scope_chain->cv_map = NULL;
+    }
+  if (cv && scope_chain && cfun)
+    {
+      cv = scope_chain->cv_map = new hash_map <tree, tree>;
+      scope_chain->act_cfun = cfun;
+    }
+
+  if (cv)
+    {
+      tree *slot = cv->get (t);
+      if (slot && *slot)
+	return *slot;
+    }
+
+  ret = maybe_constant_value_1 (t, decl);
+
+  if (cv)
+    {
+      /* We don't need to cache RET, as it is a
+	 constant-value if it differs.  */
+      tree *slot = &cv->get_or_insert (t);
+      *slot = ret;
+    }
+
+  return ret;
+}
+
 /* Like maybe_constant_value but first fully instantiate the argument.
 
    Note: this is equivalent to instantiate_non_dependent_expr_sfinae
@@ -3929,6 +4094,8 @@ fold_non_dependent_expr (tree t)
 tree
 maybe_constant_init (tree t, tree decl)
 {
+  if (!t)
+    return t;
   if (TREE_CODE (t) == EXPR_STMT)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CONVERT_EXPR
@@ -4039,6 +4206,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       /* We can see a FIELD_DECL in a pointer-to-member expression.  */
     case FIELD_DECL:
     case PARM_DECL:
+    case RESULT_DECL:
     case USING_DECL:
     case USING_STMT:
     case PLACEHOLDER_EXPR:
@@ -4627,6 +4795,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       /* We can see these in statement-expressions.  */
       return true;
 
+    case EMPTY_CLASS_EXPR:
+      return false;
+
     default:
       if (objc_is_property_ref (t))
 	return false;
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 9fd348c..e967c72 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -1382,7 +1382,12 @@ build_array_notation_ref (location_t loc, tree array, tree start, tree length,
     
   if (!stride) 
     stride = build_one_cst (ptrdiff_type_node);
-  
+
+  stride = maybe_constant_value (stride);
+  length = maybe_constant_value (length);
+  if (start)
+    start = maybe_constant_value (start);
+
   /* When dealing with templates, triplet type-checking will be done in pt.c 
      after type substitution.  */
   if (processing_template_decl 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e4b50e5..88baa40 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -41,7 +41,9 @@ along with GCC; see the file COPYING3.  If not see
 /* Forward declarations.  */
 
 static tree cp_genericize_r (tree *, int *, void *);
+static tree cp_fold_r (tree *, int *, void *);
 static void cp_genericize_tree (tree*);
+static tree cp_fold (tree, hash_map<tree, tree> *);
 
 /* Local declarations.  */
 
@@ -181,13 +183,13 @@ genericize_eh_spec_block (tree *stmt_p)
 /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
 
 static void
-genericize_if_stmt (tree *stmt_p)
+genericize_if_stmt (tree *stmt_p, hash_map<tree, tree> *fold_hash)
 {
   tree stmt, cond, then_, else_;
   location_t locus = EXPR_LOCATION (*stmt_p);
 
   stmt = *stmt_p;
-  cond = IF_COND (stmt);
+  cond = cp_fold (IF_COND (stmt), fold_hash);
   then_ = THEN_CLAUSE (stmt);
   else_ = ELSE_CLAUSE (stmt);
 
@@ -916,9 +918,76 @@ struct cp_genericize_data
   vec<tree> bind_expr_stack;
   struct cp_genericize_omp_taskreg *omp_ctx;
   tree try_block;
+  hash_map<tree, tree> *fold_hash;
   bool no_sanitize_p;
 };
 
+/* Perform any pre-gimplification folding of C++ front end trees to
+   GENERIC.
+   Note:  The folding of none-omp cases is something to move into
+     the middle-end.  As for now we have most foldings only on GENERIC
+     in fold-const, we need to perform this before transformation to
+     GIMPLE-form.  */
+
+static tree
+cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+  tree stmt;
+  struct cp_genericize_data *wtd = (struct cp_genericize_data *) data;
+  enum tree_code code;
+
+  *stmt_p = stmt = cp_fold (*stmt_p, wtd->fold_hash);
+
+  code = TREE_CODE (stmt);
+  if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
+      || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
+    {
+      tree x;
+      int i, n;
+
+      cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
+      cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
+      cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL);
+      x = OMP_FOR_COND (stmt);
+      if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison)
+	{
+	  cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL);
+	  cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL);
+	} 
+      else if (x && TREE_CODE (x) == TREE_VEC)
+	{
+	  n = TREE_VEC_LENGTH (x);
+	  for (i = 0; i < n; i++)
+	    {
+	      tree o = TREE_VEC_ELT (x, i);
+	      if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison)
+		cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+	    }
+	}
+      x = OMP_FOR_INCR (stmt);
+      if (x && TREE_CODE (x) == TREE_VEC)
+	{
+	  n = TREE_VEC_LENGTH (x);
+	  for (i = 0; i < n; i++)
+	    {
+	      tree o = TREE_VEC_ELT (x, i);
+	      if (o && TREE_CODE (o) == MODIFY_EXPR)
+		o = TREE_OPERAND (o, 1);
+	      if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR
+			|| TREE_CODE (o) == POINTER_PLUS_EXPR))
+		{
+		  cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL);
+		  cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+		}
+	    }
+	}
+      cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL);
+      *walk_subtrees = 0;
+    }
+
+  return NULL;
+}
+
 /* Perform any pre-gimplification lowering of C++ front end trees to
    GENERIC.  */
 
@@ -978,7 +1047,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       if (__builtin_expect (wtd->omp_ctx != NULL, 0)
 	  && omp_var_to_track (TREE_OPERAND (stmt, 0)))
 	omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0));
-      *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
+      *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
       *walk_subtrees = 0;
     }
   else if (TREE_CODE (stmt) == RETURN_EXPR
@@ -1058,7 +1127,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 
   else if (TREE_CODE (stmt) == IF_STMT)
     {
-      genericize_if_stmt (stmt_p);
+      genericize_if_stmt (stmt_p, wtd->fold_hash);
       /* *stmt_p has changed, tail recurse to handle it again.  */
       return cp_genericize_r (stmt_p, walk_subtrees, data);
     }
@@ -1307,6 +1376,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 					      SIZEOF_EXPR, false);
       if (*stmt_p == error_mark_node)
 	*stmt_p = size_one_node;
+      *stmt_p = cp_fold (*stmt_p,  wtd->fold_hash);
       return NULL;
     }
   else if ((flag_sanitize
@@ -1349,12 +1419,15 @@ cp_genericize_tree (tree* t_p)
 {
   struct cp_genericize_data wtd;
 
+  wtd.fold_hash = new hash_map<tree, tree>;
   wtd.p_set = new hash_set<tree>;
   wtd.bind_expr_stack.create (0);
   wtd.omp_ctx = NULL;
   wtd.try_block = NULL_TREE;
   wtd.no_sanitize_p = false;
   cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
+  cp_walk_tree (t_p, cp_fold_r, &wtd, NULL);
+  delete wtd.fold_hash;
   delete wtd.p_set;
   wtd.bind_expr_stack.release ();
   if (flag_sanitize & SANITIZE_VPTR)
@@ -1782,3 +1855,472 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 	 && DECL_LANG_SPECIFIC (decl)
 	 && DECL_OMP_PRIVATIZED_MEMBER (decl);
 }
+
+/* Callback for walk_tree, looking for LABEL_EXPR.  Return *TP if it is
+   a LABEL_EXPR; otherwise return NULL_TREE.  Do not check the subtrees
+   of GOTO_EXPR.  */
+
+static tree
+contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case LABEL_EXPR:
+      return *tp;
+
+    case GOTO_EXPR:
+      *walk_subtrees = 0;
+
+      /* ... fall through ...  */
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Return whether the sub-tree ST contains a label which is accessible from
+   outside the sub-tree.  */
+
+static bool
+contains_label_p (tree st)
+{
+  return
+   walk_tree_without_duplicates (&st, contains_label_1 , NULL) != NULL_TREE;
+}
+
+/* Perform folding on expression X.  */
+
+tree
+cp_fully_fold (tree x)
+{
+  hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+  hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+  /* If current scope has a hash_map, but it was for different CFUN,
+     then destroy hash_map to avoid issues with ggc_collect.  */
+  if ((cv || ctx) && scope_chain->act_cfun != cfun)
+    {
+      if (ctx)
+	delete ctx;
+      if (cv)
+	delete cv;
+      ctx = NULL;
+      scope_chain->act_cfun = NULL;
+      scope_chain->fold_map = NULL;
+      scope_chain->cv_map = NULL;
+    }
+
+  /* If there is no hash_map, but there is a scope, and a set CFUN,
+     then create the hash_map for scope.  */
+  if (!ctx && scope_chain && cfun)
+    {
+      ctx = scope_chain->fold_map = new hash_map <tree, tree>;
+      scope_chain->act_cfun = cfun;
+    }
+  /* Otherwise if there is no hash_map, use for folding temporary
+     hash_map.  */
+  else if (!ctx)
+    {
+      hash_map<tree, tree> fold_hash;
+      return cp_fold (x, &fold_hash);
+    }
+
+  return cp_fold (x, ctx);
+}
+
+/*  This function tries to fold given expression X in GENERIC-form.
+    For performance-reason, and for avoiding endless-recursion the
+    function uses given tree-hash FOLD_HASH.
+    If FOLD_HASH is 0, or we are processing within template-declaration,
+    or X is no valid expression, or has no valid type, we don't fold at all.
+    For performance-reason we don't hash on expressions representing a
+    declaration, or being of constant-class.
+    Function returns X, or its folded variant.  */
+
+static tree
+cp_fold (tree x, hash_map<tree, tree> *fold_hash)
+{
+  tree *slot, op0, op1, op2, op3;
+  tree org_x = x, r = NULL_TREE;
+  enum tree_code code;
+  location_t loc;
+
+  if (!x || x == error_mark_node)
+    return x;
+
+  if (!fold_hash
+      || processing_template_decl
+      || (EXPR_P (x) && !TREE_TYPE (x)))
+    return x;
+
+  /* Don't even try to hash on DECLs or constants.  */
+  if (DECL_P (x) || CONSTANT_CLASS_P (x))
+    return x;
+
+  slot = fold_hash->get (x);
+  if (slot && *slot)
+    return *slot;
+
+  code = TREE_CODE (x);
+  switch (code)
+    {
+    case SIZEOF_EXPR:
+      x = fold_sizeof_expr (x);
+      break;
+
+    case VIEW_CONVERT_EXPR:
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+
+      if (VOID_TYPE_P (TREE_TYPE (x)))
+	return x;
+
+      if (!TREE_OPERAND (x, 0)
+	  || TREE_CODE (TREE_OPERAND (x, 0)) == NON_LVALUE_EXPR)
+	return x;
+
+      loc = EXPR_LOCATION (x);
+      op0 = TREE_OPERAND (x, 0);
+
+      if (TREE_CODE (x) == NOP_EXPR
+	  && TREE_OVERFLOW_P (op0)
+	  && TREE_TYPE (x) == TREE_TYPE (op0))
+	return x;
+
+      op0 = cp_fold (op0, fold_hash);
+
+      if (op0 != TREE_OPERAND (x, 0))
+        x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+      x = fold (x);
+
+      /* Conversion of an out-of-range value has implementation-defined
+	 behavior; the language considers it different from arithmetic
+	 overflow, which is undefined.  */
+      if (TREE_CODE (op0) == INTEGER_CST
+	  && TREE_OVERFLOW_P (x) && !TREE_OVERFLOW_P (op0))
+	TREE_OVERFLOW (x) = false;
+      
+      break;
+
+    case ALIGNOF_EXPR:
+    case SAVE_EXPR:
+    case ADDR_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case UNARY_PLUS_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case INDIRECT_REF:
+    /* case NON_LVALUE_EXPR: */
+    case RETURN_EXPR:
+    case EXPR_STMT:
+    case STMT_EXPR:
+    case GOTO_EXPR:
+    case EXIT_EXPR:
+    case LOOP_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (op0 != TREE_OPERAND (x, 0))
+        x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+      x = fold (x);
+
+      gcc_assert (TREE_CODE (x) != COND_EXPR
+		  || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))));
+      break;
+
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case INIT_EXPR:
+
+	loc = EXPR_LOCATION (x);
+	op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+	op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+
+	if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1)
+	  x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+	break;
+
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case COMPOUND_EXPR:
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR: case LE_EXPR:
+    case GT_EXPR: case GE_EXPR:
+    case EQ_EXPR: case NE_EXPR:
+    case UNORDERED_EXPR: case ORDERED_EXPR:
+    case UNLT_EXPR: case UNLE_EXPR:
+    case UNGT_EXPR: case UNGE_EXPR:
+    case UNEQ_EXPR: case LTGT_EXPR:
+    case RANGE_EXPR: case COMPLEX_EXPR:
+    case MODIFY_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      if ((code == COMPOUND_EXPR || code == MODIFY_EXPR)
+	  && ((op1 && TREE_SIDE_EFFECTS (op1))
+	       || (op0 && TREE_SIDE_EFFECTS (op0))))
+	break;
+      if (TREE_CODE (x) == COMPOUND_EXPR && !op0)
+	op0 = build_empty_stmt (loc);
+
+      if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
+	x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+      x = fold (x);
+
+      if (TREE_CODE (x) == COMPOUND_EXPR && TREE_OPERAND (x, 0) == NULL_TREE
+	  && TREE_OPERAND (x, 1))
+	return TREE_OPERAND (x, 1);
+      break;
+
+    case VEC_COND_EXPR:
+    case COND_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (TREE_SIDE_EFFECTS (op0))
+	break;
+
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+      if (TREE_CODE (op0) == INTEGER_CST)
+	{
+	  tree un;
+
+	  if (integer_zerop (op0))
+	    {
+	      un = op1;
+	      r = op2;
+	    }
+	  else
+	    {
+	      un = op2;
+	      r = op1;
+	    }
+
+          if ((!TREE_SIDE_EFFECTS (un) || !contains_label_p (un))
+              && (! VOID_TYPE_P (TREE_TYPE (r)) || VOID_TYPE_P (x)))
+            {
+	      if (CAN_HAVE_LOCATION_P (r)
+		  && EXPR_LOCATION (r) != loc
+		  && !(TREE_CODE (r) == SAVE_EXPR
+		       || TREE_CODE (r) == TARGET_EXPR
+		       || TREE_CODE (r) == BIND_EXPR))
+	        {
+		  r = copy_node (r);
+		  SET_EXPR_LOCATION (r, loc);
+	        }
+	      x = r;
+	    }
+
+	  break;
+	}
+
+      if (VOID_TYPE_P (TREE_TYPE (x)))
+	break;
+
+      x = build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+
+      if (code != COND_EXPR)
+	x = fold (x);
+
+      break;
+
+    case CALL_EXPR:
+      {
+	int i, m, sv = optimize, nw = sv, changed = 0;
+	tree callee = get_callee_fndecl (x);
+
+	if (callee && DECL_BUILT_IN (callee) && !optimize
+	    && DECL_IS_BUILTIN_CONSTANT_P (callee)
+	    && current_function_decl
+	    && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	  nw = 1;
+	optimize = nw;
+	r = fold (x);
+	optimize = sv;
+
+	if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = cp_fold (r, fold_hash);
+	    break;
+	  }
+
+	x = copy_node (x);
+
+	m = call_expr_nargs (x);
+	for (i = 0; i < m; i++)
+	  {
+	    r = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
+	    if (r != CALL_EXPR_ARG (x, i))
+	      changed = 1;
+	    CALL_EXPR_ARG (x, i) = r;
+	  }
+
+	optimize = nw;
+	r = fold (x);
+	optimize = sv;
+
+	if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = cp_fold (r, fold_hash);
+	    break;
+	  }
+
+	optimize = nw;
+
+	/* Invoke maybe_constant_value for functions being declared
+	   constexpr, and are no AGGR_INIT_EXPRs ...
+	   TODO:
+	   Due issues in maybe_constant_value for CALL_EXPR with
+	   arguments passed by reference, it is disabled.  */
+	if (callee && DECL_DECLARED_CONSTEXPR_P (callee))
+          r = maybe_constant_value (x);
+	optimize = sv;
+
+        if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = r;
+	    break;
+	  }
+
+	if (!changed)
+	  x = org_x;
+	break;
+      }
+
+    case BIND_EXPR:
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+      if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1 || TREE_OPERAND (x, 2) != op2)
+	{
+	  x = copy_node (x);
+	  TREE_OPERAND (x, 0) = op0;
+	  TREE_OPERAND (x, 1) = op1;
+	  TREE_OPERAND (x, 2) = op2;
+	}
+      break;
+
+    case CONSTRUCTOR:
+      {
+	unsigned i;
+	constructor_elt *p;
+	vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x);
+	FOR_EACH_VEC_SAFE_ELT (elts, i, p)
+	  p->value = cp_fold (p->value, fold_hash);
+	break;
+      }
+    case TREE_VEC:
+      {
+	bool changed = false;
+	vec<tree, va_gc> *vec = make_tree_vector ();
+	int i, n = TREE_VEC_LENGTH (x);
+	vec_safe_reserve (vec, n);
+
+	for (i = 0; i < n; i++)
+	  {
+	    tree op = cp_fold (TREE_VEC_ELT (x, i), fold_hash);
+	    vec->quick_push (op);
+	    if (op != TREE_VEC_ELT (x, i))
+	      changed = true;
+	  }
+
+	if (changed)
+	  {
+	    r = copy_node (x);
+	    for (i = 0; i < n; i++)
+	      TREE_VEC_ELT (r, i) = (*vec)[i];
+	    x = r;
+	  }
+
+	release_tree_vector (vec);
+      }
+
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+      op3 = cp_fold (TREE_OPERAND (x, 3), fold_hash);
+
+      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);
+
+      x = fold (x);
+      break;
+
+    case DECL_EXPR:
+
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (op0 == TREE_OPERAND (x, 0))
+	break;
+
+      x = copy_node (x);
+      TREE_OPERAND (x, 0) = op0;
+      break;
+
+    default:
+      return org_x;
+    }
+
+  slot = &fold_hash->get_or_insert (org_x);
+  *slot = x;
+
+  /* Prevent that we try to fold an already folded result again.  */
+  if (x != org_x)
+    {
+      slot = &fold_hash->get_or_insert (x);
+      *slot = x;
+    }
+
+  return x;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 828f268..cc4148e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1239,6 +1239,11 @@ struct GTY(()) saved_scope {
 
   hash_map<tree, tree> *GTY((skip)) x_local_specializations;
 
+  hash_map<tree, tree> *GTY((skip)) fold_map;
+  hash_map<tree, tree> *GTY((skip)) cv_map;
+
+  struct function *GTY((skip)) act_cfun;
+
   struct saved_scope *prev;
 };
 
@@ -6474,7 +6479,6 @@ extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
 	walk_tree_1 (tp, func, data, pset, cp_walk_subtrees)
 #define cp_walk_tree_without_duplicates(tp,func,data) \
 	walk_tree_without_duplicates_1 (tp, func, data, cp_walk_subtrees)
-extern tree fold_if_not_in_template		(tree);
 extern tree rvalue				(tree);
 extern tree convert_bitfield_to_declared_type   (tree);
 extern tree cp_save_expr			(tree);
@@ -6705,6 +6709,7 @@ extern tree cxx_omp_clause_dtor			(tree, tree);
 extern void cxx_omp_finish_clause		(tree, gimple_seq *);
 extern bool cxx_omp_privatize_by_reference	(const_tree);
 extern bool cxx_omp_disregard_value_expr	(tree, bool);
+extern tree cp_fully_fold			(tree);
 
 /* in name-lookup.c */
 extern void suggest_alternatives_for            (location_t, tree);
@@ -6796,12 +6801,14 @@ extern tree cxx_constant_value			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE);
 extern tree fold_non_dependent_expr		(tree);
+extern tree fold_simple				(tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
 extern bool is_instantiation_of_constexpr       (tree);
 extern bool var_in_constexpr_fn                 (tree);
 extern void explain_invalid_constexpr_fn        (tree);
 extern vec<tree> cx_error_context               (void);
+extern tree fold_sizeof_expr			(tree);
 
 /* In c-family/cilk.c */
 extern bool cilk_valid_spawn                    (tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index e764ee1..51b992c 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -53,7 +53,7 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
 
    Here is a list of all the functions that assume that widening and
    narrowing is always done with a NOP_EXPR:
-     In convert.c, convert_to_integer.
+     In convert.c, convert_to_integer[_nofold].
      In c-typeck.c, build_binary_op_nodefault (boolean ops),
 	and c_common_truthvalue_conversion.
      In expr.c: expand_expr, for operands of a MULT_EXPR.
@@ -240,7 +240,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
       gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
 		  == GET_MODE_SIZE (TYPE_MODE (type)));
 
-      return convert_to_pointer (type, expr);
+      return convert_to_pointer_nofold (type, expr);
     }
 
   if (type_unknown_p (expr))
@@ -608,6 +608,7 @@ cp_fold_convert (tree type, tree expr)
       conv = fold_convert (type, expr);
       conv = ignore_overflows (conv, expr);
     }
+
   return conv;
 }
 
@@ -633,7 +634,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
 
   if (TREE_TYPE (expr) == type)
     return expr;
-  
+  if (expr == error_mark_node)
+    return expr;
   result = cp_convert (type, expr, complain);
 
   if ((complain & tf_warning)
@@ -641,13 +643,14 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
     {
       tree folded = maybe_constant_value (expr);
       tree stripped = folded;
-      tree folded_result
+      tree folded_result;
+      folded_result
 	= folded != expr ? cp_convert (type, folded, complain) : result;
-
-      /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
-	 NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
+      folded_result = cp_fully_fold (folded_result);
+      /* The maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW
+	 in a NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
       STRIP_NOPS (stripped);
-
+      folded = cp_fully_fold (folded);
       if (!TREE_OVERFLOW_P (stripped)
 	  && folded_result != error_mark_node)
 	warnings_for_convert_and_check (input_location, type, folded,
@@ -706,9 +709,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       /* For complex data types, we need to perform componentwise
 	 conversion.  */
       else if (TREE_CODE (type) == COMPLEX_TYPE)
-	return fold_if_not_in_template (convert_to_complex (type, e));
+	return convert_to_complex_nofold (type, e);
       else if (VECTOR_TYPE_P (type))
-	return fold_if_not_in_template (convert_to_vector (type, e));
+	return convert_to_vector (type, e);
       else if (TREE_CODE (e) == TARGET_EXPR)
 	{
 	  /* Don't build a NOP_EXPR of class type.  Instead, change the
@@ -721,7 +724,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 	  /* We shouldn't be treating objects of ADDRESSABLE type as
 	     rvalues.  */
 	  gcc_assert (!TREE_ADDRESSABLE (type));
-	  return fold_if_not_in_template (build_nop (type, e));
+	  return build_nop (type, e);
 	}
     }
 
@@ -799,7 +802,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 	  return cp_truthvalue_conversion (e);
 	}
 
-      converted = fold_if_not_in_template (convert_to_integer (type, e));
+      converted = convert_to_integer_nofold (type, e);
 
       /* Ignore any integer overflow caused by the conversion.  */
       return ignore_overflows (converted, e);
@@ -811,7 +814,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       return nullptr_node;
     }
   if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
-    return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
+    return cp_convert_to_pointer (type, e, complain);
   if (code == VECTOR_TYPE)
     {
       tree in_vtype = TREE_TYPE (e);
@@ -826,7 +829,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 		      in_vtype, type);
 	  return error_mark_node;
 	}
-      return fold_if_not_in_template (convert_to_vector (type, e));
+      return convert_to_vector (type, e);
     }
   if (code == REAL_TYPE || code == COMPLEX_TYPE)
     {
@@ -842,9 +845,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 		      TREE_TYPE (e));
 	}
       if (code == REAL_TYPE)
-	return fold_if_not_in_template (convert_to_real (type, e));
+	return convert_to_real_nofold (type, e);
       else if (code == COMPLEX_TYPE)
-	return fold_if_not_in_template (convert_to_complex (type, e));
+	return convert_to_complex_nofold (type, e);
     }
 
   /* New C++ semantics:  since assignment is now based on
@@ -1457,7 +1460,7 @@ convert (tree type, tree expr)
   intype = TREE_TYPE (expr);
 
   if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
-    return fold_if_not_in_template (build_nop (type, expr));
+    return build_nop (type, expr);
 
   return ocp_convert (type, expr, CONV_OLD_CONVERT,
 		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
@@ -1475,13 +1478,11 @@ convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
   enum tree_code code = TREE_CODE (type);
 
   if (code == REFERENCE_TYPE)
-    return (fold_if_not_in_template
-	    (convert_to_reference (type, e, CONV_C_CAST, 0,
-				   NULL_TREE, complain)));
+    return convert_to_reference (type, e, CONV_C_CAST, 0,
+				 NULL_TREE, complain);
 
   if (code == POINTER_TYPE)
-    return fold_if_not_in_template (convert_to_pointer_force (type, e,
-							      complain));
+    return convert_to_pointer_force (type, e, complain);
 
   /* From typeck.c convert_for_assignment */
   if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bd3f2bc..484f4f2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8580,35 +8580,6 @@ stabilize_vla_size (tree size)
   cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset);
 }
 
-/* Helper function for compute_array_index_type.  Look for SIZEOF_EXPR
-   not inside of SAVE_EXPR and fold them.  */
-
-static tree
-fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
-{
-  tree expr = *expr_p;
-  if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
-    *walk_subtrees = 0;
-  else if (TREE_CODE (expr) == SIZEOF_EXPR)
-    {
-      *(bool *)data = true;
-      if (SIZEOF_EXPR_TYPE_P (expr))
-	expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
-					   SIZEOF_EXPR, false);
-      else if (TYPE_P (TREE_OPERAND (expr, 0)))
-	expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
-					   false);
-      else
-        expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
-					   false);
-      if (expr == error_mark_node)
-        expr = size_one_node;
-      *expr_p = expr;
-      *walk_subtrees = 0;
-    }
-  return NULL;
-}
-
 /* Given the SIZE (i.e., number of elements) in an array, compute an
    appropriate index type for the array.  If non-NULL, NAME is the
    name of the thing being declared.  */
@@ -8699,7 +8670,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       SET_TYPE_STRUCTURAL_EQUALITY (itype);
       return itype;
     }
-  
+
+  if (TREE_CODE (size) != INTEGER_CST)
+    {
+      tree folded = cp_fully_fold (size);
+      if (TREE_CODE (folded) == INTEGER_CST)
+	pedwarn (location_of (size), OPT_Wpedantic,
+		 "size of array is not an integral constant-expression");
+      /* Use the folded result for VLAs, too; it will have resolved
+	 SIZEOF_EXPR.  */
+      size = folded;
+    }
+
   /* Normally, the array-bound will be a constant.  */
   if (TREE_CODE (size) == INTEGER_CST)
     {
@@ -8786,7 +8768,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 				  cp_convert (ssizetype, integer_one_node,
 					      complain),
 				  complain);
-      itype = fold (itype);
+      itype = maybe_constant_value (itype);
       processing_template_decl = saved_processing_template_decl;
 
       if (!TREE_CONSTANT (itype))
@@ -8794,18 +8776,6 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 	  /* A variable sized array.  */
 	  itype = variable_size (itype);
 
-	  if (TREE_CODE (itype) != SAVE_EXPR)
-	    {
-	      /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
-		 they might survive till gimplification.  */
-	      tree newitype = itype;
-	      bool found = false;
-	      cp_walk_tree_without_duplicates (&newitype,
-					       fold_sizeof_expr_r, &found);
-	      if (found)
-		itype = variable_size (fold (newitype));
-	    }
-
 	  stabilize_vla_size (itype);
 
 	  if (flag_sanitize & SANITIZE_VLA
@@ -13515,7 +13485,7 @@ incremented enumerator value is too large for %<long%>");
 		   "type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype));
 
           /* Convert the value to the appropriate type.  */
-          value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
+          value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
         }
     }
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a2d31a3..89859e9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3116,7 +3116,7 @@ get_guard_cond (tree guard, bool thread_safe)
     {
       guard_value = integer_one_node;
       if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
-	guard_value = convert (TREE_TYPE (guard), guard_value);
+	guard_value = fold_convert (TREE_TYPE (guard), guard_value);
       guard = cp_build_binary_op (input_location,
 				  BIT_AND_EXPR, guard, guard_value,
 				  tf_warning_or_error);
@@ -3124,7 +3124,7 @@ get_guard_cond (tree guard, bool thread_safe)
 
   guard_value = integer_zero_node;
   if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
-    guard_value = convert (TREE_TYPE (guard), guard_value);
+    guard_value = fold_convert (TREE_TYPE (guard), guard_value);
   return cp_build_binary_op (input_location,
 			     EQ_EXPR, guard, guard_value,
 			     tf_warning_or_error);
@@ -3142,7 +3142,7 @@ set_guard (tree guard)
   guard = get_guard_bits (guard);
   guard_init = integer_one_node;
   if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
-    guard_init = convert (TREE_TYPE (guard), guard_init);
+    guard_init = fold_convert (TREE_TYPE (guard), guard_init);
   return cp_build_modify_expr (guard, NOP_EXPR, guard_init, 
 			       tf_warning_or_error);
 }
@@ -4573,6 +4573,19 @@ c_parse_final_cleanups (void)
       /* If there are templates that we've put off instantiating, do
 	 them now.  */
       instantiate_pending_templates (retries);
+      /* Clear fold_map and/or cv_map of current scope, if present.  */
+      if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree,tree> *fm = scope_chain->fold_map;
+	  hash_map<tree,tree> *cv = scope_chain->cv_map;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	}
       ggc_collect ();
 
       /* Write out virtual tables as required.  Note that writing out
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b45281f..fd9ae0d 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -178,9 +178,9 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
        initialized are initialized to zero.  */
     ;
   else if (TYPE_PTR_OR_PTRMEM_P (type))
-    init = convert (type, nullptr_node);
+    init = fold (convert (type, nullptr_node));
   else if (SCALAR_TYPE_P (type))
-    init = convert (type, integer_zero_node);
+    init = fold (convert (type, integer_zero_node));
   else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type)))
     {
       tree field;
@@ -794,7 +794,6 @@ perform_member_init (tree member, tree init)
 	   in that case.  */
 	init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
 						tf_warning_or_error);
-
       if (init)
 	finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
 						tf_warning_or_error));
@@ -2712,7 +2711,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
       }
       max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
 
-      size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+      size = size_binop (MULT_EXPR, size, fold_convert (sizetype, nelts));
       outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
 				       outer_nelts,
 				       max_outer_nelts_tree);
@@ -2872,7 +2871,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 	{
 	  placement_expr = get_target_expr (placement_first);
 	  CALL_EXPR_ARG (alloc_call, 1)
-	    = convert (TREE_TYPE (placement), placement_expr);
+	    = fold_convert (TREE_TYPE (placement), placement_expr);
 	}
 
       if (!member_new_p
@@ -3464,7 +3463,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   /* The below is short by the cookie size.  */
   virtual_size = size_binop (MULT_EXPR, size_exp,
-			     convert (sizetype, maxindex));
+			     fold_convert (sizetype, maxindex));
 
   tbase = create_temporary_var (ptype);
   tbase_init
@@ -3507,7 +3506,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
       /* The below is short by the cookie size.  */
       virtual_size = size_binop (MULT_EXPR, size_exp,
-				 convert (sizetype, maxindex));
+				 fold_convert (sizetype, maxindex));
 
       if (! TYPE_VEC_NEW_USES_COOKIE (type))
 	/* no header */
@@ -3553,8 +3552,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
 		      fold_build2_loc (input_location,
 				   NE_EXPR, boolean_type_node, base,
-				   convert (TREE_TYPE (base),
-					    nullptr_node)),
+				   fold_convert (TREE_TYPE (base),
+						 nullptr_node)),
 		      body, integer_zero_node);
   body = build1 (NOP_EXPR, void_type_node, body);
 
@@ -3676,6 +3675,7 @@ build_vec_init (tree base, tree maxindex, tree init,
   if (maxindex == NULL_TREE || maxindex == error_mark_node)
     return error_mark_node;
 
+  maxindex = maybe_constant_value (maxindex);
   if (explicit_value_init_p)
     gcc_assert (!init);
 
@@ -3717,6 +3717,8 @@ build_vec_init (tree base, tree maxindex, tree init,
     }
 
   maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
+  maxindex = fold_simple (maxindex);
+
   if (TREE_CODE (atype) == ARRAY_TYPE)
     {
       ptype = build_pointer_type (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 8744fff..61a352a 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -6182,6 +6182,19 @@ push_to_top_level (void)
   s->unevaluated_operand = cp_unevaluated_operand;
   s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
   s->x_stmt_tree.stmts_are_full_exprs_p = true;
+  if (current_function_decl
+      && scope_chain && scope_chain->function_decl == current_function_decl
+      && cfun && scope_chain->act_cfun == cfun)
+    {
+      s->fold_map = scope_chain->fold_map;
+      s->cv_map = scope_chain->cv_map;
+    }
+  else
+    {
+      s->fold_map = NULL;
+      s->cv_map = NULL;
+    }
+  s->act_cfun = cfun;
 
   scope_chain = s;
   current_function_decl = NULL_TREE;
@@ -6199,7 +6212,10 @@ pop_from_top_level_1 (void)
 {
   struct saved_scope *s = scope_chain;
   cxx_saved_binding *saved;
+  hash_map<tree, tree> *fm = s->fold_map;
+  hash_map<tree, tree> *cv = s->cv_map;
   size_t i;
+  bool same_fold_map = false;
 
   /* Clear out class-level bindings cache.  */
   if (previous_class_level)
@@ -6221,9 +6237,32 @@ pop_from_top_level_1 (void)
      state.  */
   if (s->need_pop_function_context)
     pop_function_context ();
+
+  /* If 'current_function_decl' isn't NULL and is equal to prior pushed,
+     we are within a nested function.
+     If additionally saved 'cfun' is identical to current, we can use
+     the same 'fold_map'.  */
+     
+  if (current_function_decl && s->function_decl == current_function_decl
+      && scope_chain && s->fold_map == scope_chain->fold_map
+      && scope_chain->act_cfun && scope_chain->act_cfun == cfun)
+    same_fold_map = true;
+
   current_function_decl = s->function_decl;
   cp_unevaluated_operand = s->unevaluated_operand;
   c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
+
+  /* If we have a new 'fold_map', and it isn't equal, or outside of
+     scope_chain, then invalidate it.  */
+  if (fm && (!same_fold_map || !scope_chain))
+    delete fm;
+  if (cv && (!same_fold_map || !scope_chain))
+    delete cv;
+
+  /* Invalidate explicit.  */
+  s->fold_map = NULL;
+  s->cv_map = NULL;
+  s->act_cfun = NULL;
 }
 
 /* Wrapper for pop_from_top_level_1.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d1f4970..24a77f8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6769,7 +6769,7 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
 	 2. ARRAY [ EXP : EXP ]
 	 3. ARRAY [ EXP : EXP : EXP ]  */
 
-      *init_index = cp_parser_expression (parser);	
+      *init_index = cp_parser_expression (parser);
       if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
 	{  
 	  /* This indicates that we have a normal array expression.  */
@@ -8513,9 +8513,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
       /* For "false && x" or "true || x", x will never be executed;
 	 disable warnings while evaluating it.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings +=
+	  cp_fully_fold (current.lhs) == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings +=
+	  cp_fully_fold (current.lhs) == truthvalue_true_node;
 
       /* Extract another operand.  It may be the RHS of this expression
 	 or the LHS of a new, higher priority expression.  */
@@ -8562,9 +8564,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 
       /* Undo the disabling of warnings done above.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings -=
+	  cp_fully_fold (current.lhs) == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings -=
+	  cp_fully_fold (current.lhs) == truthvalue_true_node;
 
       if (warn_logical_not_paren
 	  && TREE_CODE_CLASS (current.tree_type) == tcc_comparison
@@ -8650,7 +8654,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 static tree
 cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
 {
-  tree expr;
+  tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr);
   tree assignment_expr;
   struct cp_token *token;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -8665,7 +8669,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
                "ISO C++ does not allow ?: with omitted middle operand");
       /* Implicit true clause.  */
       expr = NULL_TREE;
-      c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node;
+      c_inhibit_evaluation_warnings +=
+	folded_logical_or_expr == truthvalue_true_node;
       warn_for_omitted_condop (token->location, logical_or_expr);
     }
   else
@@ -8673,11 +8678,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
       bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
       parser->colon_corrects_to_scope_p = false;
       /* Parse the expression.  */
-      c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
+      c_inhibit_evaluation_warnings +=
+	folded_logical_or_expr == truthvalue_false_node;
       expr = cp_parser_expression (parser);
       c_inhibit_evaluation_warnings +=
-	((logical_or_expr == truthvalue_true_node)
-	 - (logical_or_expr == truthvalue_false_node));
+	((folded_logical_or_expr == truthvalue_true_node)
+	 - (folded_logical_or_expr == truthvalue_false_node));
       parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
     }
 
@@ -8685,7 +8691,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
   cp_parser_require (parser, CPP_COLON, RT_COLON);
   /* Parse the assignment-expression.  */
   assignment_expr = cp_parser_assignment_expression (parser);
-  c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node;
+  c_inhibit_evaluation_warnings -=
+    folded_logical_or_expr == truthvalue_true_node;
 
   /* Build the conditional-expression.  */
   return build_x_conditional_expr (loc, logical_or_expr,
@@ -20330,8 +20337,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
     {
       initializer
 	= cp_parser_constant_expression (parser,
-					/*allow_non_constant_p=*/true,
-					non_constant_p);
+					 /*allow_non_constant_p=*/true,
+					 non_constant_p);
     }
   else
     initializer = cp_parser_braced_list (parser, non_constant_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfea8e2..fb9cdf8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6217,7 +6217,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   /* 14.3.2/5: The null pointer{,-to-member} conversion is applied
      to a non-type argument of "nullptr".  */
   if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
-    expr = convert (type, expr);
+    expr = fold_simple (convert (type, expr));
 
   /* In C++11, integral or enumeration non-type template arguments can be
      arbitrary constant expressions.  Pointer and pointer to
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7702a41..73f05f0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2569,9 +2569,26 @@ finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
 		      tsubst_flags_t complain)
 {
   tree result = build_x_unary_op (loc, code, expr, complain);
-  if ((complain & tf_warning)
-      && TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr))
-    overflow_warning (input_location, result);
+  tree result_ovl, expr_ovl;
+
+  if (!(complain & tf_warning))
+    return result;
+
+  result_ovl = result;
+  expr_ovl = expr;
+
+  if (!processing_template_decl)
+    expr_ovl = cp_fully_fold (expr_ovl);
+
+  if (!CONSTANT_CLASS_P (expr_ovl)
+      || TREE_OVERFLOW_P (expr_ovl))
+    return result;
+
+  if (!processing_template_decl)
+    result_ovl = cp_fully_fold (result_ovl);
+
+  if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
+    overflow_warning (input_location, result_ovl);
 
   return result;
 }
@@ -3895,6 +3912,7 @@ finish_offsetof (tree expr, location_t loc)
 	      TREE_OPERAND (expr, 2));
       return error_mark_node;
     }
+
   if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
       || TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE
       || TREE_TYPE (expr) == unknown_type_node)
@@ -4049,6 +4067,22 @@ emit_associated_thunks (tree fn)
 bool
 expand_or_defer_fn_1 (tree fn)
 {
+  if (!function_depth)
+    {
+      if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree, tree> *fm = scope_chain->fold_map;
+	  hash_map<tree, tree> *cv = scope_chain->cv_map;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	}
+    }
+
   /* When the parser calls us after finishing the body of a template
      function, we don't really want to expand the body.  */
   if (processing_template_decl)
@@ -4129,6 +4163,19 @@ expand_or_defer_fn (tree fn)
       emit_associated_thunks (fn);
 
       function_depth--;
+      if (function_depth == 0
+	  && scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree, tree> *fm = scope_chain->fold_map;
+	  hash_map<tree, tree> *cv = scope_chain->cv_map;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	}
     }
 }
 
@@ -4483,6 +4530,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
     low_bound = mark_rvalue_use (low_bound);
   if (length)
     length = mark_rvalue_use (length);
+  /* We need to reduce to real constant-values for checks below.  */
+  if (length)
+    length = fold_simple (length);
+  if (low_bound)
+    low_bound = fold_simple (low_bound);
   if (low_bound
       && TREE_CODE (low_bound) == INTEGER_CST
       && TYPE_PRECISION (TREE_TYPE (low_bound))
@@ -6178,7 +6230,8 @@ finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd)
 		  if (OMP_CLAUSE_SCHEDULE_KIND (c)
 		      == OMP_CLAUSE_SCHEDULE_CILKFOR)
 		    {
-		      t = convert_to_integer (long_integer_type_node, t);
+		      t = convert_to_integer_nofold (long_integer_type_node,
+						     t);
 		      if (t == error_mark_node)
 			{
 			  remove = true;
@@ -7447,6 +7500,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
   if (init && EXPR_HAS_LOCATION (init))
     elocus = EXPR_LOCATION (init);
 
+  cond = cp_fully_fold (cond);
   switch (TREE_CODE (cond))
     {
     case GT_EXPR:
@@ -7482,6 +7536,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
   diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1),
 			    ERROR_MARK, iter, ERROR_MARK, NULL,
 			    tf_warning_or_error);
+  diff = cp_fully_fold (diff);
   if (error_operand_p (diff))
     return true;
   if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE)
@@ -7543,8 +7598,9 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
 		  if (TREE_CODE (rhs) == MINUS_EXPR)
 		    {
 		      incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
-		      incr = fold_if_not_in_template (incr);
+		      incr = fold_simple (incr);
 		    }
+
 		  if (TREE_CODE (incr) != INTEGER_CST
 		      && (TREE_CODE (incr) != NOP_EXPR
 			  || (TREE_CODE (TREE_OPERAND (incr, 0))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4311212..dd4daed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -308,9 +308,19 @@ xvalue_p (const_tree ref)
 bool
 builtin_valid_in_constant_expr_p (const_tree decl)
 {
-  /* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing
-     in constant-expressions.  We may want to add other builtins later. */
-  return DECL_IS_BUILTIN_CONSTANT_P (decl);
+  if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)))
+    /* Not a built-in.  */
+    return false;
+  switch (DECL_FUNCTION_CODE (decl))
+    {
+    case BUILT_IN_CONSTANT_P:
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      /* These have constant results even if their operands are
+	 non-constant.  */
+      return true;
+    default:
+      return false;
+    }
 }
 
 /* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
@@ -686,8 +696,8 @@ convert_bitfield_to_declared_type (tree expr)
 
   bitfield_type = is_bitfield_expr_with_lowered_type (expr);
   if (bitfield_type)
-    expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type),
-			       expr);
+    expr = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type),
+				      expr);
   return expr;
 }
 
@@ -3484,10 +3494,13 @@ handle_init_priority_attribute (tree* node,
 
   STRIP_NOPS (initp_expr);
   initp_expr = default_conversion (initp_expr);
+  if (initp_expr)
+    initp_expr = maybe_constant_value (initp_expr);
 
   if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
     {
       error ("requested init_priority is not an integer constant");
+      cxx_constant_value (initp_expr);
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -4262,26 +4275,6 @@ stabilize_init (tree init, tree *initp)
   return !TREE_SIDE_EFFECTS (init);
 }
 
-/* Like "fold", but should be used whenever we might be processing the
-   body of a template.  */
-
-tree
-fold_if_not_in_template (tree expr)
-{
-  /* In the body of a template, there is never any need to call
-     "fold".  We will call fold later when actually instantiating the
-     template.  Integral constant expressions in templates will be
-     evaluated via instantiate_non_dependent_expr, as necessary.  */
-  if (processing_template_decl)
-    return expr;
-
-  /* Fold C++ front-end specific tree codes.  */
-  if (TREE_CODE (expr) == UNARY_PLUS_EXPR)
-    return fold_convert (TREE_TYPE (expr), TREE_OPERAND (expr, 0));
-
-  return fold (expr);
-}
-
 /* Returns true if a cast to TYPE may appear in an integral constant
    expression.  */
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0501e4d..4e7ef58 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1948,8 +1948,6 @@ decay_conversion (tree exp,
 
   code = TREE_CODE (type);
 
-  /* FIXME remove for delayed folding.  */
-  exp = scalar_constant_value (exp);
   if (error_operand_p (exp))
     return error_mark_node;
 
@@ -2442,7 +2440,6 @@ build_class_member_access_expr (tree object, tree member,
 
       result = build3_loc (input_location, COMPONENT_REF, member_type,
 			   object, member, NULL_TREE);
-      result = fold_if_not_in_template (result);
 
       /* Mark the expression const or volatile, as appropriate.  Even
 	 though we've dealt with the type above, we still have to mark the
@@ -2855,9 +2852,9 @@ build_simple_component_ref (tree object, tree member)
 {
   tree type = cp_build_qualified_type (TREE_TYPE (member),
 				       cp_type_quals (TREE_TYPE (object)));
-  return fold_build3_loc (input_location,
-			  COMPONENT_REF, type,
-			  object, member, NULL_TREE);
+  return build3_loc (input_location,
+		     COMPONENT_REF, type,
+		     object, member, NULL_TREE);
 }
 
 /* Return an expression for the MEMBER_NAME field in the internal
@@ -3176,8 +3173,7 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
       TREE_THIS_VOLATILE (rval)
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
-      ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
-					  complain);
+      ret = require_complete_type_sfinae (rval, complain);
       protected_set_expr_location (ret, loc);
       if (non_lvalue)
 	ret = non_lvalue_loc (loc, ret);
@@ -3924,7 +3920,6 @@ build_vec_cmp (tree_code code, tree type,
   tree minus_one_vec = build_minus_one_cst (type);
   tree cmp_type = build_same_sized_truth_vector_type(type);
   tree cmp = build2 (code, cmp_type, arg0, arg1);
-  cmp = fold_if_not_in_template (cmp);
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
@@ -3979,7 +3974,7 @@ cp_build_binary_op (location_t location,
      convert it to this type.  */
   tree final_type = 0;
 
-  tree result;
+  tree result, result_ovl;
   tree orig_type = NULL;
 
   /* Nonzero if this is an operation like MIN or MAX which can
@@ -4602,7 +4597,7 @@ cp_build_binary_op (location_t location,
 	      op0 = cp_build_binary_op (location,
 					TRUTH_ANDIF_EXPR, e1, e2,
 					complain);
-	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain); 
+	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
 	    }
      	  else 
 	    {
@@ -4643,10 +4638,12 @@ cp_build_binary_op (location_t location,
 	    op1 = save_expr (op1);
 
 	  pfn0 = pfn_from_ptrmemfunc (op0);
+	  pfn0 = cp_fully_fold (pfn0);
 	  /* Avoid -Waddress warnings (c++/64877).  */
 	  if (TREE_CODE (pfn0) == ADDR_EXPR)
 	    TREE_NO_WARNING (pfn0) = 1;
 	  pfn1 = pfn_from_ptrmemfunc (op1);
+	  pfn1 = cp_fully_fold (pfn1);
 	  delta0 = delta_from_ptrmemfunc (op0);
 	  delta1 = delta_from_ptrmemfunc (op1);
 	  if (TARGET_PTRMEMFUNC_VBIT_LOCATION
@@ -5000,10 +4997,7 @@ cp_build_binary_op (location_t location,
 		  gcc_unreachable();
 		}
 	    }
-	  real = fold_if_not_in_template (real);
-	  imag = fold_if_not_in_template (imag);
 	  result = build2 (COMPLEX_EXPR, result_type, real, imag);
-	  result = fold_if_not_in_template (result);
 	  return result;
 	}
 
@@ -5031,20 +5025,12 @@ cp_build_binary_op (location_t location,
 
       if (short_compare)
 	{
-	  /* Don't write &op0, etc., because that would prevent op0
-	     from being kept in a register.
-	     Instead, make copies of the our local variables and
-	     pass the copies by reference, then copy them back afterward.  */
-	  tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+	  /* We call shorten_compare only for diagnostic-reason.  */
+	  tree xop0 = fold_simple (op0), xop1 = fold_simple (op1),
+	       xresult_type = result_type;
 	  enum tree_code xresultcode = resultcode;
-	  tree val
-	    = shorten_compare (location, &xop0, &xop1, &xresult_type,
+	  shorten_compare (location, &xop0, &xop1, &xresult_type,
 			       &xresultcode);
-	  if (val != 0)
-	    return cp_convert (boolean_type_node, val, complain);
-	  op0 = xop0, op1 = xop1;
-	  converted = 1;
-	  resultcode = xresultcode;
 	}
 
       if ((short_compare || code == MIN_EXPR || code == MAX_EXPR)
@@ -5063,9 +5049,9 @@ cp_build_binary_op (location_t location,
 	  tree oop1 = maybe_constant_value (orig_op1);
 
 	  if (TREE_CODE (oop0) != INTEGER_CST)
-	    oop0 = orig_op0;
+	    oop0 = cp_fully_fold (orig_op0);
 	  if (TREE_CODE (oop1) != INTEGER_CST)
-	    oop1 = orig_op1;
+	    oop1 = cp_fully_fold (orig_op1);
 	  warn_for_sign_compare (location, oop0, oop1, op0, op1, 
 				 result_type, resultcode);
 	}
@@ -5120,18 +5106,30 @@ cp_build_binary_op (location_t location,
     }
 
   result = build2 (resultcode, build_type, op0, op1);
-  result = fold_if_not_in_template (result);
   if (final_type != 0)
     result = cp_convert (final_type, result, complain);
 
-  if (TREE_OVERFLOW_P (result) 
-      && !TREE_OVERFLOW_P (op0) 
-      && !TREE_OVERFLOW_P (op1))
-    overflow_warning (location, result);
-
   if (instrument_expr != NULL)
-    result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
-			  instrument_expr, result);
+    result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+		     instrument_expr, result);
+
+  if (!processing_template_decl)
+    {
+      op0 = cp_fully_fold (op0);
+      /* Only consider the second argument if the first isn't overflowed.  */
+      if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
+	return result;
+      op1 = cp_fully_fold (op1);
+      if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+	return result;
+    }
+  else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
+	   || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
+    return result;
+
+  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
+  if (TREE_OVERFLOW_P (result_ovl))
+    overflow_warning (location, result_ovl);
 
   return result;
 }
@@ -5181,8 +5179,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
   complete_type (TREE_TYPE (res_type));
 
   return pointer_int_sum (input_location, resultcode, ptrop,
-			  fold_if_not_in_template (intop),
-			  complain & tf_warning_or_error);
+			  intop, complain & tf_warning_or_error);
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
@@ -5258,7 +5255,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
 
   result = build2 (EXACT_DIV_EXPR, restype, op0,
 		   cp_convert (restype, op1, complain));
-  return fold_if_not_in_template (result);
+  return result;
 }
 \f
 /* Construct and perhaps optimize a tree representation
@@ -5774,6 +5771,10 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
 	    /* Make sure the result is not an lvalue: a unary plus or minus
 	       expression is always a rvalue.  */
 	    arg = rvalue (arg);
+
+	    if (code == NEGATE_EXPR && CONSTANT_CLASS_P (arg))
+	      /* Immediately fold negation of a constant.  */
+	      return fold_build1 (code, TREE_TYPE (arg), arg);
 	  }
       }
       break;
@@ -5838,10 +5839,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     case REALPART_EXPR:
     case IMAGPART_EXPR:
       arg = build_real_imag_expr (input_location, code, arg);
-      if (arg == error_mark_node)
-	return arg;
-      else
-	return fold_if_not_in_template (arg);
+      return arg;
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -6008,7 +6006,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     {
       if (argtype == 0)
 	argtype = TREE_TYPE (arg);
-      return fold_if_not_in_template (build1 (code, argtype, arg));
+      return build1 (code, argtype, arg);
     }
 
   if (complain & tf_error)
@@ -7002,7 +7000,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     return rvalue (expr);
   else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
 	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
-    return fold_if_not_in_template (build_nop (type, expr));
+    return build_nop (type, expr);
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
 	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
     {
@@ -7030,7 +7028,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
       if (warn_strict_aliasing <= 2)
 	strict_aliasing_warning (intype, type, sexpr);
 
-      return fold_if_not_in_template (build_nop (type, expr));
+      return build_nop (type, expr);
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
 	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7041,13 +7039,13 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
 	warning (OPT_Wconditionally_supported,
 		 "casting between pointer-to-function and pointer-to-object "
 		 "is conditionally-supported");
-      return fold_if_not_in_template (build_nop (type, expr));
+      return build_nop (type, expr);
     }
   else if (VECTOR_TYPE_P (type))
-    return fold_if_not_in_template (convert_to_vector (type, expr));
+    return convert_to_vector (type, expr);
   else if (VECTOR_TYPE_P (intype)
 	   && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
-    return fold_if_not_in_template (convert_to_integer (type, expr));
+    return convert_to_integer_nofold (type, expr);
   else
     {
       if (valid_p)
@@ -7899,8 +7897,7 @@ get_delta_difference (tree from, tree to,
       }
   }
 
-  return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
-						      result));
+  return convert_to_integer (ptrdiff_type_node, result);
 }
 
 /* Return a constructor for the pointer-to-member-function TYPE using
@@ -8081,41 +8078,35 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
 	 fn; the call will do the opposite adjustment.  */
       tree orig_class = DECL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
-      *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
-		       *delta, BINFO_OFFSET (binfo));
-      *delta = fold_if_not_in_template (*delta);
+      *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+			    *delta, BINFO_OFFSET (binfo));
 
       /* We set PFN to the vtable offset at which the function can be
 	 found, plus one (unless ptrmemfunc_vbit_in_delta, in which
 	 case delta is shifted left, and then incremented).  */
       *pfn = DECL_VINDEX (fn);
-      *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
-		     TYPE_SIZE_UNIT (vtable_entry_type));
-      *pfn = fold_if_not_in_template (*pfn);
+      *pfn = fold_build2 (MULT_EXPR, integer_type_node, *pfn,
+			  TYPE_SIZE_UNIT (vtable_entry_type));
 
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
 	{
 	case ptrmemfunc_vbit_in_pfn:
-	  *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
-			 integer_one_node);
-	  *pfn = fold_if_not_in_template (*pfn);
+	  *pfn = fold_build2 (PLUS_EXPR, integer_type_node, *pfn,
+			      integer_one_node);
 	  break;
 
 	case ptrmemfunc_vbit_in_delta:
-	  *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
-			   *delta, integer_one_node);
-	  *delta = fold_if_not_in_template (*delta);
-	  *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
-			   *delta, integer_one_node);
-	  *delta = fold_if_not_in_template (*delta);
+	  *delta = fold_build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node);
+	  *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
-      *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
-      *pfn = fold_if_not_in_template (*pfn);
+      *pfn = fold_convert (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
     }
 }
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e73ea13..7544333 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -742,6 +742,7 @@ split_nonconstant_init (tree dest, tree init)
     init = TARGET_EXPR_INITIAL (init);
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
+      init = cp_fully_fold (init);
       code = push_stmt_list ();
       if (split_nonconstant_init_1 (dest, init))
 	init = NULL_TREE;
@@ -832,6 +833,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
       TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
     }
+  value = cp_fully_fold (value);
 
   if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
     /* Handle aggregate NSDMI in non-constant initializers, too.  */
@@ -930,19 +932,35 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	}
     }
 
+  bool almost_ok = ok;
+  if (!ok && !CONSTANT_CLASS_P (init) && (complain & tf_warning_or_error))
+    {
+      tree folded = cp_fully_fold (init);
+      if (TREE_CONSTANT (folded) && check_narrowing (type, folded, tf_none))
+	almost_ok = true;
+    }
+
   if (!ok)
     {
+      location_t loc = EXPR_LOC_OR_LOC (init, input_location);
       if (cxx_dialect == cxx98)
-	warning_at (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
-		    "narrowing conversion of %qE from %qT to %qT inside { } "
-		    "is ill-formed in C++11", init, ftype, type);
-      else if (!TREE_CONSTANT (init))
+	{
+	  if (complain & tf_warning)
+	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+			"from %qT to %qT inside { } is ill-formed in C++11",
+			init, ftype, type);
+	  ok = true;
+	}
+      else if (!CONSTANT_CLASS_P (init))
 	{
 	  if (complain & tf_warning_or_error)
 	    {
-	      pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
-		       "narrowing conversion of %qE from %qT to %qT inside { }",
-		       init, ftype, type);
+	      if (!almost_ok || pedantic)
+		pedwarn (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+			 "from %qT to %qT inside { }", init, ftype, type);
+	      if (pedantic && almost_ok)
+		inform (loc, " the expression has a constant value but is not "
+			"a C++ constant-expression");
 	      ok = true;
 	    }
 	}
@@ -950,7 +968,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
-	  pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
+	  pedwarn (loc, OPT_Wnarrowing,
 		   "narrowing conversion of %qE from %qT to %qT "
 		   "inside { }", init, ftype, type);
 	  if (errorcount == savederrorcount)
@@ -959,7 +977,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	}
     }
 
-  return cxx_dialect == cxx98 || ok; 
+  return ok;
 }
 
 /* Process the initializer INIT for a variable of type TYPE, emitting
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5e32901..d754a90 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
       else if (TREE_CODE (arg1) == REAL_CST)
 	return fold_convert_const_fixed_from_real (type, arg1);
     }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      if (TREE_CODE (arg1) == VECTOR_CST
+	  && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
+	  && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
+	{
+	  tree r = copy_node (arg1);
+	  TREE_TYPE (arg1) = type;
+	  return r;
+	}
+    }
   return NULL_TREE;
 }
 
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
index 5d803ad..8f14034 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
@@ -47,3 +47,5 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
index fc89af1..55523a5 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
index bf9b1a0..1295b72 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
index 85fbd0e..3088220 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/fold-bitand-4.c b/gcc/testsuite/c-c++-common/fold-bitand-4.c
index 1b9c388..a658ff1 100644
--- a/gcc/testsuite/c-c++-common/fold-bitand-4.c
+++ b/gcc/testsuite/c-c++-common/fold-bitand-4.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c } } } */
 /* { dg-options "-fdump-tree-original" } */
 /* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
index 26c9293..a5e3c1f1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
@@ -18,7 +18,7 @@ public:
   {
     /* I am surprised this is considered a constexpr */
     return *((Inner *)4);
-  } // { dg-error "reinterpret_cast" "" { xfail *-*-* } }
+  } // { dg-error "reinterpret_cast" "" }
 };
 
 B B::instance;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53792.C b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
new file mode 100644
index 0000000..deb5c1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
@@ -0,0 +1,29 @@
+// PR c++/53792
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-final { scan-tree-dump "return 0" "optimized" } }
+
+struct entry {
+  char const* label;
+  int         value;
+};
+
+constexpr bool same(char const *x, char const *y) {
+  return !*x && !*y ? true
+    : /* default */    (*x == *y && same(x+1, y+1));
+}
+
+constexpr int keyToValue(char const *label, entry const *entries) {
+  return !entries->label ? entries->value
+       : same(entries->label, label) ? entries->value
+       : /*default*/                   keyToValue(label, entries+1);
+}
+
+constexpr entry foo[] = {{"Foo", 0}, {"Bar", 1}, {"FooBar", 2}, {0, -1}};
+
+int
+bar()
+{
+  int result = keyToValue("Foo", foo);
+  return result;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
new file mode 100644
index 0000000..afa7edb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+constexpr int f(void *) { return 0; }
+constexpr int f(...) { return 1; }
+constexpr int g1() { return f(0); }
+constexpr int g2(int n) { return f(n); }
+constexpr int g3(int n) { return f(n*0); }
+
+int main()
+{
+    static_assert(g1() == 0, "g1 failed");
+    static_assert(g2(0) == 1, "g2 failed");
+    static_assert(g3(0) == 1, "g3 failed");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
new file mode 100644
index 0000000..e340de4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MIN; }
+
+int main()
+{
+  return -f(); // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
new file mode 100644
index 0000000..6b5dff8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MAX; }
+
+int main()
+{
+  return f() + 2; // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
new file mode 100644
index 0000000..39b3557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" }  */
+
+extern int fl;
+
+#define MAK (fl < 0 ? 1 : (fl ? -1 : 0))
+
+int foo (int sz)
+{
+  if (MAK) return 1;
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
new file mode 100644
index 0000000..fa91a4f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" }  */
+
+extern int fl;
+extern int arr[];
+
+#define MAK (fl < 0 ? 1 : (fl ? 2 : 0))
+
+int foo (int sz)
+{
+  unsigned i;
+  int r = 0;
+  for (i = 0; i < MAK; i++)
+    r += arr[i];
+  return r;
+}
+
diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
index c8ec07d..0c5df6d 100644
--- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C
+++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
@@ -5,8 +5,8 @@
 
 template<typename T>
 void type_alignment(const T&) {
-  struct { char c; T t; } s;
-  SA((char*)&s.t - (char*)&s.c == 1);
+  struct S { char c; T t; } s;
+  SA(__builtin_offsetof (S,t) - __builtin_offsetof (S,c) == 1);
 }
 
 template <class T> struct A { char c; T t; };
@@ -17,7 +17,8 @@ int main() {
 
   A<aligned> a;			// { dg-warning "ignoring attributes" }
 
-  SA((char*)&a.t - (char*)&a.c == 1);
+  SA(  __builtin_offsetof (__typeof(a),t)
+     - __builtin_offsetof (__typeof(a),c) == 1);
 
   aligned z;
   type_alignment(z);		// { dg-warning "ignoring attributes" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/ext/offsetof1.C b/gcc/testsuite/g++.dg/ext/offsetof1.C
index 1468c0a..23f3537 100644
--- a/gcc/testsuite/g++.dg/ext/offsetof1.C
+++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
@@ -1,6 +1,7 @@
 // PR c++/27601
 // Origin: Patrik Hägglund  <patrik.hagglund@bredband.net>
 // { dg-do compile }
+// { dg-options "-Wno-pointer-arith" }
 
 struct bar {
   static int foo;
@@ -10,7 +11,7 @@ struct bar {
 int a = __builtin_offsetof(bar, foo);  // { dg-error "static data member" }
 int av = __builtin_offsetof(volatile bar, foo);  // { dg-error "static data member" }
 int b = __builtin_offsetof(bar, baz);  // { dg-error "member function" }
-int b0 = __builtin_offsetof(bar, baz[0]);  // { dg-error "function" }
+int b0 = __builtin_offsetof(bar, baz[0]);  // { dg-error "single identifier nor|member function" }
 int bv0 = __builtin_offsetof(volatile bar, baz[0]);  // { dg-error "function" }
 int c = __builtin_offsetof(bar, ~bar);  // { dg-error "member function" }
 
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
index dbc60b3..e1f31bc 100644
--- a/gcc/testsuite/g++.dg/init/const7.C
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -1,9 +1,9 @@
 // { dg-do compile }
-// { dg-options "-fdump-tree-gimple" }
+// { dg-options "-fdump-tree-gimple -pedantic" }
 
 struct s { int x, y; };
 short offsets[1] = {
-  ((char*) &(((struct s*)16)->y) - (char *)16),
+  ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } }
 };
 
 // This ensures that we get a dump whether or not the bug is present.
diff --git a/gcc/testsuite/g++.dg/init/self1.C b/gcc/testsuite/g++.dg/init/self1.C
index dd37c8e..7620833 100644
--- a/gcc/testsuite/g++.dg/init/self1.C
+++ b/gcc/testsuite/g++.dg/init/self1.C
@@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) {
 
 int main()
 {
-  int* const savepos = sizeof(*savepos) ? 0 : 0;
+  int* const savepos = sizeof(*savepos) ? 0 : 0;  /* { dg-error "invalid conversion" "convert" { target c++11 }  } */
 
   f (sizeof (*savepos));
 
diff --git a/gcc/testsuite/g++.dg/other/error22.C b/gcc/testsuite/g++.dg/other/error22.C
index 225dcae..eba0746 100644
--- a/gcc/testsuite/g++.dg/other/error22.C
+++ b/gcc/testsuite/g++.dg/other/error22.C
@@ -5,5 +5,5 @@ extern "C" double fabs (double);
 
 void foo (double x)
 {
-  fabs (x) ();	// { dg-error "__builtin_abs" }
+  fabs (x) ();	// { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/other/error24.C b/gcc/testsuite/g++.dg/other/error24.C
index 54343c5..e5e6a4f 100644
--- a/gcc/testsuite/g++.dg/other/error24.C
+++ b/gcc/testsuite/g++.dg/other/error24.C
@@ -8,6 +8,6 @@ void
 bar (int i, int j, double k)
 {
   foo (i && j) ();	// { dg-error "\\(\\(?i != 0\\)? \\&\\& \\(?j != 0\\)?\\)" }
-  foo (!i || !j) ();	// { dg-error "\\(\\(?i == 0\\)? \\|\\| \\(?j == 0\\)?\\)" }
-  foo (!i == !j) ();	// { dg-error "\\(\\(?i != 0\\)? \\^ \\(?j == 0\\)?\\)" }
+  foo (!i || !j) ();	// { dg-error "function" }
+  foo (!i == !j) ();	// { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/other/error26.C b/gcc/testsuite/g++.dg/other/error26.C
index fb2c8b7..ffe2728 100644
--- a/gcc/testsuite/g++.dg/other/error26.C
+++ b/gcc/testsuite/g++.dg/other/error26.C
@@ -2,5 +2,5 @@
 
 void foo(__complex__ double x)
 {
-  __builtin_conj(x)(); // { dg-error "~x" }
+  __builtin_conj(x)(); // { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/parse/array-size2.C b/gcc/testsuite/g++.dg/parse/array-size2.C
index 355ed61..3c83347 100644
--- a/gcc/testsuite/g++.dg/parse/array-size2.C
+++ b/gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0];
-  char h[(__SIZE_TYPE__) &((struct S *) 8)->b];
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" "" { xfail *-*-* } }
   bar (g, h);
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
index 946f2e6..8014705 100644
--- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -1,14 +1,10 @@
 /* { dg-do compile } */
 /* { dg-options "-fsanitize=integer-divide-by-zero" } */
 
-/* TODO: We expect an error on the invalid case here, because that
-   must be a constant-expression.  This will be fixed when we have
-   proper delayed folding.  */
-
 void
 foo (int i)
 {
   switch (i)
   case 0 * (1 / 0): /* { dg-warning "division by zero" } */
-    ;  /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */
+    ;  /* { dg-error "is not a constant.expression" "" { target *-*-* } 8 } */
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/shift-1.C b/gcc/testsuite/g++.dg/ubsan/shift-1.C
index 05e049e..493a55c 100644
--- a/gcc/testsuite/g++.dg/ubsan/shift-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/shift-1.C
@@ -8,10 +8,10 @@ foo (int x)
   /* None of the following should pass.  */
   switch (x)
     {
-    case 1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case -1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case 1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case -1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+    case 1 >> -1: /* { dg-error "operand of shift" "" } */
+    case -1 >> -1: /* { dg-error "operand of shift" "" } */
+    case 1 << -1: /* { dg-error "operand of shift" "" } */
+    case -1 << -1: /* { dg-error "operand of shift" "" } */
       return 1;
     }
   return 0;
@@ -23,8 +23,8 @@ bar (int x)
   /* None of the following should pass.  */
   switch (x)
     {
-    case -1 >> 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case 1 << 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+    case -1 >> 200: /* { dg-error "operand of shift" "" } */
+    case 1 << 200: /* { dg-error "operand of shift" "" } */
       return 1;
     }
   return 0;
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
index 7cd76e7..a10e15b 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -126,3 +126,11 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target *-*-* } 56 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 58 } */
+/* { dg-error "is not a constant expression" "const" { target *-*-* } 65 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 65 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
index 73c0e00..c73a28c 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
 /* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
+/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
@@ -65,7 +65,7 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
-      ;
+      ;  /* { dg-error "is not a constant expression" "const" { target *-*-* } 67 }  */
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
       /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 69 } */
       ;
@@ -128,3 +128,9 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 60 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 67 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
index 24b3959..23a2585 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
@@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
 /* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 61 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
@@ -68,7 +68,7 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
-      ;
+      ;  /* { dg-error "is not a constant expression" "const" { target *-*-* } 70 } */
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
       /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
       ;
@@ -131,3 +131,9 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "invalid conversion from" "convert" { target c++11 } 63 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 34 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 70 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 34 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 34 } */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C
index ff1d0669..96691d3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/null3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C
@@ -3,5 +3,5 @@
 void x()
 {
  int* p = 1==0;	// { dg-warning "converting 'false' to pointer" "" { target { ! c++11 } } }
-// { dg-error "cannot convert" "" { target c++11 } 5 } 
+// { dg-error "cannot convert" "" { target { c++11 } } 5 }
 }
diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c
index 11d5999..0204cfe 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -432,8 +432,8 @@ create_one_component_var (tree type, tree orig, const char *prefix,
   if (DECL_NAME (orig) && !DECL_IGNORED_P (orig))
     {
       const char *name = IDENTIFIER_POINTER (DECL_NAME (orig));
-
-      DECL_NAME (r) = get_identifier (ACONCAT ((name, suffix, NULL)));
+      name = ACONCAT ((name, suffix, NULL));
+      DECL_NAME (r) = get_identifier (name);
 
       SET_DECL_DEBUG_EXPR (r, build1 (code, type, orig));
       DECL_HAS_DEBUG_EXPR_P (r) = 1;

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: df-front.patch --]
[-- Type: text/x-patch; name="df-front.patch", Size: 106849 bytes --]

commit 2689ad9313b746c46a952bdec5f214ec737bc12e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Nov 9 01:14:35 2015 -0500

    Merge c++-delayed-folding branch.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0b7d143..536989b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4747,7 +4747,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 	  tree cmp_type = build_same_sized_truth_vector_type (arg1_type);
 	  arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type));
 	}
-      return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
+      return build3_loc (loc, VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
     }
 
   /* [expr.cond]
@@ -5151,9 +5151,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
 
  valid_operands:
   result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
-  if (!cp_unevaluated_operand)
-    /* Avoid folding within decltype (c++/42013) and noexcept.  */
-    result = fold_if_not_in_template (result);
 
   /* We can't use result_type below, as fold might have returned a
      throw_expr.  */
@@ -5689,8 +5686,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 		 decaying an enumerator to its value.  */
 	      if (complain & tf_warning)
 		warn_logical_operator (loc, code, boolean_type_node,
-				       code_orig_arg1, arg1,
-				       code_orig_arg2, arg2);
+				       code_orig_arg1, fold (arg1),
+				       code_orig_arg2, fold (arg2));
 
 	      arg2 = convert_like (conv, arg2, complain);
 	    }
@@ -5728,7 +5725,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     case TRUTH_OR_EXPR:
       if (complain & tf_warning)
 	warn_logical_operator (loc, code, boolean_type_node,
-			       code_orig_arg1, arg1, code_orig_arg2, arg2);
+			       code_orig_arg1, fold (arg1), code_orig_arg2, fold (arg2));
       /* Fall through.  */
     case GT_EXPR:
     case LT_EXPR:
@@ -5739,9 +5736,10 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
       if ((complain & tf_warning)
 	  && ((code_orig_arg1 == BOOLEAN_TYPE)
 	      ^ (code_orig_arg2 == BOOLEAN_TYPE)))
-	maybe_warn_bool_compare (loc, code, arg1, arg2);
+	maybe_warn_bool_compare (loc, code, fold (arg1),
+				 fold (arg2));
       if (complain & tf_warning && warn_tautological_compare)
-	warn_tautological_cmp (loc, code, arg1, arg2);
+	warn_tautological_cmp (loc, code, fold (arg1), fold (arg2));
       /* Fall through.  */
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -6495,7 +6493,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	  imag = perform_implicit_conversion (TREE_TYPE (totype),
 					      imag, complain);
 	  expr = build2 (COMPLEX_EXPR, totype, real, imag);
-	  return fold_if_not_in_template (expr);
+	  return expr;
 	}
       expr = reshape_init (totype, expr, complain);
       expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
@@ -6736,7 +6734,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
 		    "implicit conversion from %qT to %qT when passing "
 		    "argument to function",
 		    arg_type, double_type_node);
-      arg = convert_to_real (double_type_node, arg);
+      arg = convert_to_real_nofold (double_type_node, arg);
     }
   else if (NULLPTR_TYPE_P (arg_type))
     arg = null_pointer_node;
@@ -6981,7 +6979,7 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
   bitfield_type = is_bitfield_expr_with_lowered_type (val);
   if (bitfield_type 
       && TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
-    val = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), val);
+    val = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), val);
 
   if (val == error_mark_node)
     ;
@@ -7501,7 +7499,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   gcc_assert (j <= nargs);
   nargs = j;
 
-  check_function_arguments (TREE_TYPE (fn), nargs, argarray);
+  /* Avoid to do argument-transformation, if warnings for format, and for
+     nonnull are disabled.  Just in case that at least one of them is active
+     the check_function_arguments function might warn about something.  */
+
+  if (warn_nonnull || warn_format || warn_suggest_attribute_format)
+    {
+      tree *fargs = (!nargs ? argarray
+			    : (tree *) alloca (nargs * sizeof (tree)));
+      for (j = 0; j < nargs; j++)
+	fargs[j] = maybe_constant_value (argarray[j]);
+
+      check_function_arguments (TREE_TYPE (fn), nargs, fargs);
+    }
 
   /* Avoid actually calling copy constructors and copy assignment operators,
      if possible.  */
@@ -7692,7 +7702,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
 		tsubst_flags_t complain)
 {
   tree fndecl;
-  int optimize_sav;
 
   /* Remember roughly where this call is.  */
   location_t loc = EXPR_LOC_OR_LOC (fn, input_location);
@@ -7704,9 +7713,18 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
   /* Check that arguments to builtin functions match the expectations.  */
   if (fndecl
       && DECL_BUILT_IN (fndecl)
-      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-      && !check_builtin_function_arguments (fndecl, nargs, argarray))
-    return error_mark_node;
+      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+    {
+      int i;
+
+      /* We need to take care that values to BUILT_IN_NORMAL
+         are reduced.  */
+      for (i = 0; i < nargs; i++)
+	argarray[i] = maybe_constant_value (argarray[i]);
+
+      if (!check_builtin_function_arguments (fndecl, nargs, argarray))
+	return error_mark_node;
+    }
 
     /* If it is a built-in array notation function, then the return type of
      the function is the element type of the array passed in as array 
@@ -7740,17 +7758,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
 	}
     }
 
-  /* Some built-in function calls will be evaluated at compile-time in
-     fold ().  Set optimize to 1 when folding __builtin_constant_p inside
-     a constexpr function so that fold_builtin_1 doesn't fold it to 0.  */
-  optimize_sav = optimize;
-  if (!optimize && fndecl && DECL_IS_BUILTIN_CONSTANT_P (fndecl)
-      && current_function_decl
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
-    optimize = 1;
-  fn = fold_if_not_in_template (fn);
-  optimize = optimize_sav;
-
   if (VOID_TYPE_P (TREE_TYPE (fn)))
     return fn;
 
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b123932..b5cf996 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -423,7 +423,7 @@ build_base_path (enum tree_code code,
 
 	  t = TREE_TYPE (TYPE_VFIELD (current_class_type));
 	  t = build_pointer_type (t);
-	  v_offset = convert (t, current_vtt_parm);
+	  v_offset = fold_convert (t, current_vtt_parm);
 	  v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
 	}
       else
@@ -556,8 +556,6 @@ build_simple_base_path (tree expr, tree binfo)
 	expr = build3 (COMPONENT_REF,
 		       cp_build_qualified_type (type, type_quals),
 		       expr, field, NULL_TREE);
-	expr = fold_if_not_in_template (expr);
-
 	/* Mark the expression const or volatile, as appropriate.
 	   Even though we've dealt with the type above, we still have
 	   to mark the expression itself.  */
@@ -1849,9 +1847,9 @@ determine_primary_bases (tree t)
 		 another hierarchy. As we're about to use it as a
 		 primary base, make sure the offsets match.  */
 	      delta = size_diffop_loc (input_location,
-				   convert (ssizetype,
+				   fold_convert (ssizetype,
 					    BINFO_OFFSET (base_binfo)),
-				   convert (ssizetype,
+				   fold_convert (ssizetype,
 					    BINFO_OFFSET (this_primary)));
 
 	      propagate_binfo_offsets (this_primary, delta);
@@ -1913,7 +1911,7 @@ determine_primary_bases (tree t)
 	     another hierarchy. As we're about to use it as a primary
 	     base, make sure the offsets match.  */
 	  delta = size_diffop_loc (input_location, ssize_int (0),
-			       convert (ssizetype, BINFO_OFFSET (primary)));
+			       fold_convert (ssizetype, BINFO_OFFSET (primary)));
 
 	  propagate_binfo_offsets (primary, delta);
 	}
@@ -2637,7 +2635,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
 	  if (virtual_offset
 	      || (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
 	    {
-	      tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
+	      tree offset = fold_convert (ssizetype, BINFO_OFFSET (thunk_binfo));
 
 	      if (virtual_offset)
 		{
@@ -2645,7 +2643,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
 		     offset to be from there.  */
 		  offset = 
 		    size_diffop (offset,
-				 convert (ssizetype,
+				 fold_convert (ssizetype,
 					  BINFO_OFFSET (virtual_offset)));
 		}
 	      if (fixed_offset)
@@ -2734,8 +2732,8 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
     /* The `this' pointer needs to be adjusted from the declaration to
        the nearest virtual base.  */
     delta = size_diffop_loc (input_location,
-			 convert (ssizetype, BINFO_OFFSET (virtual_base)),
-			 convert (ssizetype, BINFO_OFFSET (first_defn)));
+			 fold_convert (ssizetype, BINFO_OFFSET (virtual_base)),
+			 fold_convert (ssizetype, BINFO_OFFSET (first_defn)));
   else if (lost)
     /* If the nearest definition is in a lost primary, we don't need an
        entry in our vtable.  Except possibly in a constructor vtable,
@@ -2747,9 +2745,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
        BINFO to pointing at the base where the final overrider
        appears.  */
     delta = size_diffop_loc (input_location,
-			 convert (ssizetype,
+			 fold_convert (ssizetype,
 				  BINFO_OFFSET (TREE_VALUE (overrider))),
-			 convert (ssizetype, BINFO_OFFSET (binfo)));
+			 fold_convert (ssizetype, BINFO_OFFSET (binfo)));
 
   modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
 
@@ -3471,7 +3469,7 @@ check_bitfield_decl (tree field)
 
   if (w != error_mark_node)
     {
-      DECL_SIZE (field) = convert (bitsizetype, w);
+      DECL_SIZE (field) = fold_convert (bitsizetype, w);
       DECL_BIT_FIELD (field) = 1;
       return true;
     }
@@ -4316,8 +4314,8 @@ layout_nonempty_base_or_field (record_layout_info rli,
        OFFSET.  */
     propagate_binfo_offsets (binfo,
 			     size_diffop_loc (input_location,
-					  convert (ssizetype, offset),
-					  convert (ssizetype,
+					  fold_convert (ssizetype, offset),
+					  fold_convert (ssizetype,
 						   BINFO_OFFSET (binfo))));
 }
 
@@ -4364,7 +4362,7 @@ layout_empty_base (record_layout_info rli, tree binfo,
       /* That didn't work.  Now, we move forward from the next
 	 available spot in the class.  */
       atend = true;
-      propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
+      propagate_binfo_offsets (binfo, fold_convert (ssizetype, eoc));
       while (1)
 	{
 	  if (!layout_conflict_p (binfo,
@@ -5978,9 +5976,9 @@ propagate_binfo_offsets (tree binfo, tree offset)
 
   /* Update BINFO's offset.  */
   BINFO_OFFSET (binfo)
-    = convert (sizetype,
+    = fold_convert (sizetype,
 	       size_binop (PLUS_EXPR,
-			   convert (ssizetype, BINFO_OFFSET (binfo)),
+			   fold_convert (ssizetype, BINFO_OFFSET (binfo)),
 			   offset));
 
   /* Find the primary base class.  */
@@ -6185,7 +6183,7 @@ include_empty_classes (record_layout_info rli)
 	= size_binop (PLUS_EXPR,
 		      rli->bitpos,
 		      size_binop (MULT_EXPR,
-				  convert (bitsizetype,
+				  fold_convert (bitsizetype,
 					   size_binop (MINUS_EXPR,
 						       eoc, rli_size)),
 				  bitsize_int (BITS_PER_UNIT)));
@@ -6459,7 +6457,7 @@ layout_class_type (tree t, tree *virtuals_p)
       eoc = end_of_class (t, /*include_virtuals_p=*/0);
       TYPE_SIZE_UNIT (base_t)
 	= size_binop (MAX_EXPR,
-		      convert (sizetype,
+		      fold_convert (sizetype,
 			       size_binop (CEIL_DIV_EXPR,
 					   rli_size_so_far (rli),
 					   bitsize_int (BITS_PER_UNIT))),
@@ -6468,7 +6466,7 @@ layout_class_type (tree t, tree *virtuals_p)
 	= size_binop (MAX_EXPR,
 		      rli_size_so_far (rli),
 		      size_binop (MULT_EXPR,
-				  convert (bitsizetype, eoc),
+				  fold_convert (bitsizetype, eoc),
 				  bitsize_int (BITS_PER_UNIT)));
       TYPE_ALIGN (base_t) = rli->record_align;
       TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
@@ -9304,7 +9302,7 @@ build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
       /* Figure out where we can find this vbase offset.  */
       delta = size_binop (MULT_EXPR,
 			  vid->index,
-			  convert (ssizetype,
+			  fold_convert (ssizetype,
 				   TYPE_SIZE_UNIT (vtable_entry_type)));
       if (vid->primary_vtbl_p)
 	BINFO_VPTR_FIELD (b) = delta;
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 51fae5a..5bda494 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1037,6 +1037,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
   force_folding_builtin_constant_p = true;
   new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
 					CALL_EXPR_FN (t), nargs, args);
+  /* Fold away the NOP_EXPR from fold_builtin_n.  */
+  new_call = fold (new_call);
   force_folding_builtin_constant_p = save_ffbcp;
   VERIFY_CONSTANT (new_call);
   return new_call;
@@ -1277,6 +1279,15 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
       ctx->values->put (new_ctx.object, ctor);
       ctx = &new_ctx;
     }
+  else if (DECL_BY_REFERENCE (DECL_RESULT (fun))
+	   && TREE_CODE (t) != AGGR_INIT_EXPR)
+    {
+      /* convert_to_void stripped our AGGR_INIT_EXPR, in which case we don't
+	 care about a constant value.  */
+      gcc_assert (ctx->quiet && !ctx->object);
+      *non_constant_p = true;
+      return t;
+    }
 
   bool non_constant_args = false;
   cxx_bind_parameters_in_call (ctx, t, &new_call,
@@ -2542,6 +2553,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   tree orig_op0 = TREE_OPERAND (t, 0);
   bool empty_base = false;
 
+  /* We can handle a MEM_REF like an INDIRECT_REF, if MEM_REF's second
+     operand is an integer-zero.  Otherwise reject the MEM_REF for now.  */
+
+  if (TREE_CODE (t) == MEM_REF
+      && (!TREE_OPERAND (t, 1) || !integer_zerop (TREE_OPERAND (t, 1))))
+    {
+      gcc_assert (ctx->quiet);
+      *non_constant_p = true;
+      return t;
+    }
+
   /* First try to simplify it directly.  */
   tree r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), orig_op0,
 				  &empty_base);
@@ -3075,6 +3097,8 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
   if (TREE_CODE (op00) != ADDR_EXPR)
     return NULL_TREE;
 
+  op01 = cxx_eval_constant_expression (ctx, op01, lval,
+				       non_constant_p, overflow_p);
   op00 = TREE_OPERAND (op00, 0);
 
   /* &A[i] p+ j => &A[i + j] */
@@ -3335,6 +3359,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       /* 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.  */
+    case MEM_REF:
     case INDIRECT_REF:
       r = cxx_eval_indirect_ref (ctx, t, lval,
 				 non_constant_p, overflow_p);
@@ -3540,8 +3565,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
     case NOP_EXPR:
+    case UNARY_PLUS_EXPR:
       {
+	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
+
 	tree op = cxx_eval_constant_expression (ctx, oldop,
 						lval,
 						non_constant_p, overflow_p);
@@ -3561,11 +3589,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	    *non_constant_p = true;
 	    return t;
 	  }
-	if (op == oldop)
+	if (op == oldop && tcode != UNARY_PLUS_EXPR)
 	  /* We didn't fold at the top so we could check for ptr-int
 	     conversion.  */
 	  return fold (t);
-	r = fold_build1 (TREE_CODE (t), type, op);
+	if (tcode == UNARY_PLUS_EXPR)
+	  r = fold_convert (TREE_TYPE (t), op);
+	else
+	  r = fold_build1 (tcode, type, op);
 	/* Conversion of an out-of-range value has implementation-defined
 	   behavior; the language considers it different from arithmetic
 	   overflow, which is undefined.  */
@@ -3833,12 +3864,187 @@ cxx_constant_value (tree t, tree decl)
   return cxx_eval_outermost_constant_expr (t, false, true, decl);
 }
 
+/* Helper routine for fold_simple function.  Either return simplified
+   expression T, otherwise NULL_TREE.
+   In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
+   even if we are within template-declaration.  So be careful on call, as in
+   such case types can be undefined.  */
+
+static tree
+fold_simple_1 (tree t)
+{
+  tree op1, op2, op3;
+  enum tree_code code = TREE_CODE (t);
+
+  if (code == VAR_DECL)
+    return NULL_TREE;
+
+  switch (code)
+    {
+    case INTEGER_CST:
+    case REAL_CST:
+    case VECTOR_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+      return t;
+
+    case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (t))
+        t = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+                                        SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (t, 0)))
+        t = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0),
+                                        SIZEOF_EXPR, false);
+      else
+        t = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0),
+                                        SIZEOF_EXPR, false);
+      if (t == error_mark_node)
+        t = size_one_node;
+      break;
+
+    case ABS_EXPR:
+    case CONJ_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case NOP_EXPR:
+    case VIEW_CONVERT_EXPR:
+    case CONVERT_EXPR:
+    case FLOAT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
+
+      op1 = fold_simple_1 (TREE_OPERAND (t, 0));
+      if (!op1 || (code == NOP_EXPR && TREE_OVERFLOW (op1)))
+	return NULL_TREE;
+
+      t = const_unop (code, TREE_TYPE (t), op1);
+      if (!t)
+	return NULL_TREE;
+
+      if (CONVERT_EXPR_CODE_P (code)
+	  && TREE_OVERFLOW_P (t) && !TREE_OVERFLOW_P (op1))
+	TREE_OVERFLOW (t) = false;
+      break;
+
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR: case LE_EXPR:
+    case GT_EXPR: case GE_EXPR:
+    case EQ_EXPR: case NE_EXPR:
+    case UNORDERED_EXPR: case ORDERED_EXPR:
+    case UNLT_EXPR: case UNLE_EXPR:
+    case UNGT_EXPR: case UNGE_EXPR:
+    case UNEQ_EXPR: case LTGT_EXPR:
+
+      op1 = fold_simple_1 (TREE_OPERAND (t, 0));
+      op2 = fold_simple_1 (TREE_OPERAND (t, 1));
+
+      if (!op1 && !op2)
+	return NULL_TREE;
+      if (!op1)
+	op1 = TREE_OPERAND (t, 0);
+      if (!op2)
+	op2 = TREE_OPERAND (t, 1);
+
+      t = fold_build2_loc (EXPR_LOCATION (t), code, TREE_TYPE (t),
+			   op1, op2);
+      break;
+
+    case VEC_COND_EXPR:
+    case COND_EXPR:
+
+      if (VOID_TYPE_P (TREE_TYPE (t)))
+	return NULL_TREE;
+
+      op1 = TREE_OPERAND (t, 0);
+      op1 = fold_simple_1 (op1);
+      op2 = TREE_OPERAND (t, 1);
+      op3 = TREE_OPERAND (t, 2);
+      if (!op1)
+	return NULL_TREE;
+      op1 = fold (build3 (code, TREE_TYPE (t), op1, op2, op3));
+
+      /* We need to recurse into result, if CODE isn't
+         a COND-expression.  */
+      if (TREE_CODE (op1) != code)
+	return fold_simple_1 (op1);
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+
+  /* Just return folded expression if we got as result
+     a CST-expression.  */
+  switch (TREE_CODE (t))
+    {
+    case STRING_CST:
+    case INTEGER_CST:
+    case REAL_CST:
+    case VECTOR_CST:
+    case FIXED_CST:
+    case COMPLEX_CST:
+      break;
+    default:
+      return NULL_TREE;
+    }
+
+  return t;
+}
+
+/* If T is a simple constant expression, returns its simplified value.
+   Otherwise returns T.  In contrast to maybe_constant_value do we
+   simplify only few operations on constant-expressions, and we don't
+   try to simplify constexpressions.  */
+
+tree
+fold_simple (tree t)
+{
+  tree r = NULL_TREE;
+  if (processing_template_decl)
+    return t;
+
+  r = fold_simple_1 (t);
+  if (!r)
+    r = t;
+
+  return r;
+}
+
 /* If T is a constant expression, returns its reduced value.
    Otherwise, if T does not have TREE_CONSTANT set, returns T.
    Otherwise, returns a version of T without TREE_CONSTANT.  */
 
-tree
-maybe_constant_value (tree t, tree decl)
+static tree
+maybe_constant_value_1 (tree t, tree decl)
 {
   tree r;
 
@@ -3864,6 +4070,56 @@ maybe_constant_value (tree t, tree decl)
   return r;
 }
 
+/* If T is a constant expression, returns its reduced value.
+   Otherwise, if T does not have TREE_CONSTANT set, returns T.
+   Otherwise, returns a version of T without TREE_CONSTANT.  */
+
+tree
+maybe_constant_value (tree t, tree decl)
+{
+  tree ret;
+  hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+  hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+  /* If current scope has a hash_map, but it was for different CFUN,
+     then destroy hash_map to avoid issues with ggc_collect.  */
+  if ((cv || ctx) && scope_chain->act_cfun != cfun)
+    {
+      if (ctx)
+	delete ctx;
+      if (cv)
+	delete cv;
+      ctx = NULL;
+      scope_chain->act_cfun = NULL;
+      scope_chain->fold_map = NULL;
+      scope_chain->cv_map = NULL;
+    }
+  if (cv && scope_chain && cfun)
+    {
+      cv = scope_chain->cv_map = new hash_map <tree, tree>;
+      scope_chain->act_cfun = cfun;
+    }
+
+  if (cv)
+    {
+      tree *slot = cv->get (t);
+      if (slot && *slot)
+	return *slot;
+    }
+
+  ret = maybe_constant_value_1 (t, decl);
+
+  if (cv)
+    {
+      /* We don't need to cache RET, as it is a
+	 constant-value if it differs.  */
+      tree *slot = &cv->get_or_insert (t);
+      *slot = ret;
+    }
+
+  return ret;
+}
+
 /* Like maybe_constant_value but first fully instantiate the argument.
 
    Note: this is equivalent to instantiate_non_dependent_expr_sfinae
@@ -3929,6 +4185,8 @@ fold_non_dependent_expr (tree t)
 tree
 maybe_constant_init (tree t, tree decl)
 {
+  if (!t)
+    return t;
   if (TREE_CODE (t) == EXPR_STMT)
     t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CONVERT_EXPR
@@ -4039,6 +4297,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       /* We can see a FIELD_DECL in a pointer-to-member expression.  */
     case FIELD_DECL:
     case PARM_DECL:
+    case RESULT_DECL:
     case USING_DECL:
     case USING_STMT:
     case PLACEHOLDER_EXPR:
@@ -4627,6 +4886,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       /* We can see these in statement-expressions.  */
       return true;
 
+    case EMPTY_CLASS_EXPR:
+      return false;
+
     default:
       if (objc_is_property_ref (t))
 	return false;
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 9fd348c..e967c72 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -1382,7 +1382,12 @@ build_array_notation_ref (location_t loc, tree array, tree start, tree length,
     
   if (!stride) 
     stride = build_one_cst (ptrdiff_type_node);
-  
+
+  stride = maybe_constant_value (stride);
+  length = maybe_constant_value (length);
+  if (start)
+    start = maybe_constant_value (start);
+
   /* When dealing with templates, triplet type-checking will be done in pt.c 
      after type substitution.  */
   if (processing_template_decl 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e4b50e5..c14ddce 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -41,7 +41,9 @@ along with GCC; see the file COPYING3.  If not see
 /* Forward declarations.  */
 
 static tree cp_genericize_r (tree *, int *, void *);
+static tree cp_fold_r (tree *, int *, void *);
 static void cp_genericize_tree (tree*);
+static tree cp_fold (tree, hash_map<tree, tree> *);
 
 /* Local declarations.  */
 
@@ -181,13 +183,13 @@ genericize_eh_spec_block (tree *stmt_p)
 /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
 
 static void
-genericize_if_stmt (tree *stmt_p)
+genericize_if_stmt (tree *stmt_p, hash_map<tree, tree> *fold_hash)
 {
   tree stmt, cond, then_, else_;
   location_t locus = EXPR_LOCATION (*stmt_p);
 
   stmt = *stmt_p;
-  cond = IF_COND (stmt);
+  cond = cp_fold (IF_COND (stmt), fold_hash);
   then_ = THEN_CLAUSE (stmt);
   else_ = ELSE_CLAUSE (stmt);
 
@@ -916,9 +918,76 @@ struct cp_genericize_data
   vec<tree> bind_expr_stack;
   struct cp_genericize_omp_taskreg *omp_ctx;
   tree try_block;
+  hash_map<tree, tree> *fold_hash;
   bool no_sanitize_p;
 };
 
+/* Perform any pre-gimplification folding of C++ front end trees to
+   GENERIC.
+   Note:  The folding of none-omp cases is something to move into
+     the middle-end.  As for now we have most foldings only on GENERIC
+     in fold-const, we need to perform this before transformation to
+     GIMPLE-form.  */
+
+static tree
+cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+  tree stmt;
+  struct cp_genericize_data *wtd = (struct cp_genericize_data *) data;
+  enum tree_code code;
+
+  *stmt_p = stmt = cp_fold (*stmt_p, wtd->fold_hash);
+
+  code = TREE_CODE (stmt);
+  if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
+      || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
+    {
+      tree x;
+      int i, n;
+
+      cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
+      cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
+      cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL);
+      x = OMP_FOR_COND (stmt);
+      if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison)
+	{
+	  cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL);
+	  cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL);
+	} 
+      else if (x && TREE_CODE (x) == TREE_VEC)
+	{
+	  n = TREE_VEC_LENGTH (x);
+	  for (i = 0; i < n; i++)
+	    {
+	      tree o = TREE_VEC_ELT (x, i);
+	      if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison)
+		cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+	    }
+	}
+      x = OMP_FOR_INCR (stmt);
+      if (x && TREE_CODE (x) == TREE_VEC)
+	{
+	  n = TREE_VEC_LENGTH (x);
+	  for (i = 0; i < n; i++)
+	    {
+	      tree o = TREE_VEC_ELT (x, i);
+	      if (o && TREE_CODE (o) == MODIFY_EXPR)
+		o = TREE_OPERAND (o, 1);
+	      if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR
+			|| TREE_CODE (o) == POINTER_PLUS_EXPR))
+		{
+		  cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL);
+		  cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+		}
+	    }
+	}
+      cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL);
+      *walk_subtrees = 0;
+    }
+
+  return NULL;
+}
+
 /* Perform any pre-gimplification lowering of C++ front end trees to
    GENERIC.  */
 
@@ -978,7 +1047,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
       if (__builtin_expect (wtd->omp_ctx != NULL, 0)
 	  && omp_var_to_track (TREE_OPERAND (stmt, 0)))
 	omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0));
-      *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
+      *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
       *walk_subtrees = 0;
     }
   else if (TREE_CODE (stmt) == RETURN_EXPR
@@ -1058,7 +1127,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 
   else if (TREE_CODE (stmt) == IF_STMT)
     {
-      genericize_if_stmt (stmt_p);
+      genericize_if_stmt (stmt_p, wtd->fold_hash);
       /* *stmt_p has changed, tail recurse to handle it again.  */
       return cp_genericize_r (stmt_p, walk_subtrees, data);
     }
@@ -1307,6 +1376,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 					      SIZEOF_EXPR, false);
       if (*stmt_p == error_mark_node)
 	*stmt_p = size_one_node;
+      *stmt_p = cp_fold (*stmt_p,  wtd->fold_hash);
       return NULL;
     }
   else if ((flag_sanitize
@@ -1349,12 +1419,15 @@ cp_genericize_tree (tree* t_p)
 {
   struct cp_genericize_data wtd;
 
+  wtd.fold_hash = new hash_map<tree, tree>;
   wtd.p_set = new hash_set<tree>;
   wtd.bind_expr_stack.create (0);
   wtd.omp_ctx = NULL;
   wtd.try_block = NULL_TREE;
   wtd.no_sanitize_p = false;
   cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
+  cp_walk_tree (t_p, cp_fold_r, &wtd, NULL);
+  delete wtd.fold_hash;
   delete wtd.p_set;
   wtd.bind_expr_stack.release ();
   if (flag_sanitize & SANITIZE_VPTR)
@@ -1782,3 +1855,483 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 	 && DECL_LANG_SPECIFIC (decl)
 	 && DECL_OMP_PRIVATIZED_MEMBER (decl);
 }
+
+/* Callback for walk_tree, looking for LABEL_EXPR.  Return *TP if it is
+   a LABEL_EXPR; otherwise return NULL_TREE.  Do not check the subtrees
+   of GOTO_EXPR.  */
+
+static tree
+contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case LABEL_EXPR:
+      return *tp;
+
+    case GOTO_EXPR:
+      *walk_subtrees = 0;
+
+      /* ... fall through ...  */
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Return whether the sub-tree ST contains a label which is accessible from
+   outside the sub-tree.  */
+
+static bool
+contains_label_p (tree st)
+{
+  return
+   walk_tree_without_duplicates (&st, contains_label_1 , NULL) != NULL_TREE;
+}
+
+/* Perform folding on expression X.  */
+
+tree
+cp_fully_fold (tree x)
+{
+  hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+  hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+  /* If current scope has a hash_map, but it was for different CFUN,
+     then destroy hash_map to avoid issues with ggc_collect.  */
+  if ((cv || ctx) && scope_chain->act_cfun != cfun)
+    {
+      if (ctx)
+	delete ctx;
+      if (cv)
+	delete cv;
+      ctx = NULL;
+      scope_chain->act_cfun = NULL;
+      scope_chain->fold_map = NULL;
+      scope_chain->cv_map = NULL;
+    }
+
+  /* If there is no hash_map, but there is a scope, and a set CFUN,
+     then create the hash_map for scope.  */
+  if (!ctx && scope_chain && cfun)
+    {
+      ctx = scope_chain->fold_map = new hash_map <tree, tree>;
+      scope_chain->act_cfun = cfun;
+    }
+  /* Otherwise if there is no hash_map, use for folding temporary
+     hash_map.  */
+  else if (!ctx)
+    {
+      hash_map<tree, tree> fold_hash;
+      return cp_fold (x, &fold_hash);
+    }
+
+  return cp_fold (x, ctx);
+}
+
+/*  This function tries to fold given expression X in GENERIC-form.
+    For performance-reason, and for avoiding endless-recursion the
+    function uses given tree-hash FOLD_HASH.
+    If FOLD_HASH is 0, or we are processing within template-declaration,
+    or X is no valid expression, or has no valid type, we don't fold at all.
+    For performance-reason we don't hash on expressions representing a
+    declaration, or being of constant-class.
+    Function returns X, or its folded variant.  */
+
+static tree
+cp_fold (tree x, hash_map<tree, tree> *fold_hash)
+{
+  tree *slot, op0, op1, op2, op3;
+  tree org_x = x, r = NULL_TREE;
+  enum tree_code code;
+  location_t loc;
+
+  if (!x || x == error_mark_node)
+    return x;
+
+  if (!fold_hash
+      || processing_template_decl
+      || (EXPR_P (x) && !TREE_TYPE (x)))
+    return x;
+
+  /* Don't even try to hash on DECLs or constants.  */
+  if (DECL_P (x) || CONSTANT_CLASS_P (x))
+    return x;
+
+  slot = fold_hash->get (x);
+  if (slot && *slot)
+    return *slot;
+
+  code = TREE_CODE (x);
+  switch (code)
+    {
+    case SIZEOF_EXPR:
+      if (SIZEOF_EXPR_TYPE_P (x))
+	  r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (x, 0)),
+					  SIZEOF_EXPR, false);
+      else if (TYPE_P (TREE_OPERAND (x, 0)))
+	r = cxx_sizeof_or_alignof_type (TREE_OPERAND (x, 0),
+					SIZEOF_EXPR, false);
+      else
+	r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (x, 0),
+					SIZEOF_EXPR, false);
+      if (r == error_mark_node)
+	r = size_one_node;
+      x = r;
+      break;
+
+    case VIEW_CONVERT_EXPR:
+    case CONVERT_EXPR:
+    case NOP_EXPR:
+
+      if (VOID_TYPE_P (TREE_TYPE (x)))
+	return x;
+
+      if (!TREE_OPERAND (x, 0)
+	  || TREE_CODE (TREE_OPERAND (x, 0)) == NON_LVALUE_EXPR)
+	return x;
+
+      loc = EXPR_LOCATION (x);
+      op0 = TREE_OPERAND (x, 0);
+
+      if (TREE_CODE (x) == NOP_EXPR
+	  && TREE_OVERFLOW_P (op0)
+	  && TREE_TYPE (x) == TREE_TYPE (op0))
+	return x;
+
+      op0 = cp_fold (op0, fold_hash);
+
+      if (op0 != TREE_OPERAND (x, 0))
+        x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+      x = fold (x);
+
+      /* Conversion of an out-of-range value has implementation-defined
+	 behavior; the language considers it different from arithmetic
+	 overflow, which is undefined.  */
+      if (TREE_CODE (op0) == INTEGER_CST
+	  && TREE_OVERFLOW_P (x) && !TREE_OVERFLOW_P (op0))
+	TREE_OVERFLOW (x) = false;
+      
+      break;
+
+    case ALIGNOF_EXPR:
+    case SAVE_EXPR:
+    case ADDR_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case CONJ_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case UNARY_PLUS_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case INDIRECT_REF:
+    /* case NON_LVALUE_EXPR: */
+    case RETURN_EXPR:
+    case EXPR_STMT:
+    case STMT_EXPR:
+    case GOTO_EXPR:
+    case EXIT_EXPR:
+    case LOOP_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (op0 != TREE_OPERAND (x, 0))
+        x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+      x = fold (x);
+
+      gcc_assert (TREE_CODE (x) != COND_EXPR
+		  || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))));
+      break;
+
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case INIT_EXPR:
+
+	loc = EXPR_LOCATION (x);
+	op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+	op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+
+	if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1)
+	  x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+	break;
+
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case COMPOUND_EXPR:
+    case POINTER_PLUS_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case CEIL_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_XOR_EXPR:
+    case LT_EXPR: case LE_EXPR:
+    case GT_EXPR: case GE_EXPR:
+    case EQ_EXPR: case NE_EXPR:
+    case UNORDERED_EXPR: case ORDERED_EXPR:
+    case UNLT_EXPR: case UNLE_EXPR:
+    case UNGT_EXPR: case UNGE_EXPR:
+    case UNEQ_EXPR: case LTGT_EXPR:
+    case RANGE_EXPR: case COMPLEX_EXPR:
+    case MODIFY_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      if ((code == COMPOUND_EXPR || code == MODIFY_EXPR)
+	  && ((op1 && TREE_SIDE_EFFECTS (op1))
+	       || (op0 && TREE_SIDE_EFFECTS (op0))))
+	break;
+      if (TREE_CODE (x) == COMPOUND_EXPR && !op0)
+	op0 = build_empty_stmt (loc);
+
+      if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
+	x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+      x = fold (x);
+
+      if (TREE_CODE (x) == COMPOUND_EXPR && TREE_OPERAND (x, 0) == NULL_TREE
+	  && TREE_OPERAND (x, 1))
+	return TREE_OPERAND (x, 1);
+      break;
+
+    case VEC_COND_EXPR:
+    case COND_EXPR:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (TREE_SIDE_EFFECTS (op0))
+	break;
+
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+      if (TREE_CODE (op0) == INTEGER_CST)
+	{
+	  tree un;
+
+	  if (integer_zerop (op0))
+	    {
+	      un = op1;
+	      r = op2;
+	    }
+	  else
+	    {
+	      un = op2;
+	      r = op1;
+	    }
+
+          if ((!TREE_SIDE_EFFECTS (un) || !contains_label_p (un))
+              && (! VOID_TYPE_P (TREE_TYPE (r)) || VOID_TYPE_P (x)))
+            {
+	      if (CAN_HAVE_LOCATION_P (r)
+		  && EXPR_LOCATION (r) != loc
+		  && !(TREE_CODE (r) == SAVE_EXPR
+		       || TREE_CODE (r) == TARGET_EXPR
+		       || TREE_CODE (r) == BIND_EXPR))
+	        {
+		  r = copy_node (r);
+		  SET_EXPR_LOCATION (r, loc);
+	        }
+	      x = r;
+	    }
+
+	  break;
+	}
+
+      if (VOID_TYPE_P (TREE_TYPE (x)))
+	break;
+
+      x = build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+
+      if (code != COND_EXPR)
+	x = fold (x);
+
+      break;
+
+    case CALL_EXPR:
+      {
+	int i, m, sv = optimize, nw = sv, changed = 0;
+	tree callee = get_callee_fndecl (x);
+
+	if (callee && DECL_BUILT_IN (callee) && !optimize
+	    && DECL_IS_BUILTIN_CONSTANT_P (callee)
+	    && current_function_decl
+	    && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+	  nw = 1;
+	optimize = nw;
+	r = fold (x);
+	optimize = sv;
+
+	if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = cp_fold (r, fold_hash);
+	    break;
+	  }
+
+	x = copy_node (x);
+
+	m = call_expr_nargs (x);
+	for (i = 0; i < m; i++)
+	  {
+	    r = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
+	    if (r != CALL_EXPR_ARG (x, i))
+	      changed = 1;
+	    CALL_EXPR_ARG (x, i) = r;
+	  }
+
+	optimize = nw;
+	r = fold (x);
+	optimize = sv;
+
+	if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = cp_fold (r, fold_hash);
+	    break;
+	  }
+
+	optimize = nw;
+
+	/* Invoke maybe_constant_value for functions being declared
+	   constexpr, and are no AGGR_INIT_EXPRs ...
+	   TODO:
+	   Due issues in maybe_constant_value for CALL_EXPR with
+	   arguments passed by reference, it is disabled.  */
+	if (callee && DECL_DECLARED_CONSTEXPR_P (callee))
+          r = maybe_constant_value (x);
+	optimize = sv;
+
+        if (TREE_CODE (r) != CALL_EXPR)
+	  {
+	    x = r;
+	    break;
+	  }
+
+	if (!changed)
+	  x = org_x;
+	break;
+      }
+
+    case BIND_EXPR:
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+      if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1 || TREE_OPERAND (x, 2) != op2)
+	{
+	  x = copy_node (x);
+	  TREE_OPERAND (x, 0) = op0;
+	  TREE_OPERAND (x, 1) = op1;
+	  TREE_OPERAND (x, 2) = op2;
+	}
+      break;
+
+    case CONSTRUCTOR:
+      {
+	unsigned i;
+	constructor_elt *p;
+	vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x);
+	FOR_EACH_VEC_SAFE_ELT (elts, i, p)
+	  p->value = cp_fold (p->value, fold_hash);
+	break;
+      }
+    case TREE_VEC:
+      {
+	bool changed = false;
+	vec<tree, va_gc> *vec = make_tree_vector ();
+	int i, n = TREE_VEC_LENGTH (x);
+	vec_safe_reserve (vec, n);
+
+	for (i = 0; i < n; i++)
+	  {
+	    tree op = cp_fold (TREE_VEC_ELT (x, i), fold_hash);
+	    vec->quick_push (op);
+	    if (op != TREE_VEC_ELT (x, i))
+	      changed = true;
+	  }
+
+	if (changed)
+	  {
+	    r = copy_node (x);
+	    for (i = 0; i < n; i++)
+	      TREE_VEC_ELT (r, i) = (*vec)[i];
+	    x = r;
+	  }
+
+	release_tree_vector (vec);
+      }
+
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+
+      loc = EXPR_LOCATION (x);
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+      op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+      op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+      op3 = cp_fold (TREE_OPERAND (x, 3), fold_hash);
+
+      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);
+
+      x = fold (x);
+      break;
+
+    case DECL_EXPR:
+
+      op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+      if (op0 == TREE_OPERAND (x, 0))
+	break;
+
+      x = copy_node (x);
+      TREE_OPERAND (x, 0) = op0;
+      break;
+
+    default:
+      return org_x;
+    }
+
+  slot = &fold_hash->get_or_insert (org_x);
+  *slot = x;
+
+  /* Prevent that we try to fold an already folded result again.  */
+  if (x != org_x)
+    {
+      slot = &fold_hash->get_or_insert (x);
+      *slot = x;
+    }
+
+  return x;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 828f268..5fc017a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1239,6 +1239,11 @@ struct GTY(()) saved_scope {
 
   hash_map<tree, tree> *GTY((skip)) x_local_specializations;
 
+  hash_map<tree, tree> *GTY((skip)) fold_map;
+  hash_map<tree, tree> *GTY((skip)) cv_map;
+
+  struct function *GTY((skip)) act_cfun;
+
   struct saved_scope *prev;
 };
 
@@ -6474,7 +6479,6 @@ extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
 	walk_tree_1 (tp, func, data, pset, cp_walk_subtrees)
 #define cp_walk_tree_without_duplicates(tp,func,data) \
 	walk_tree_without_duplicates_1 (tp, func, data, cp_walk_subtrees)
-extern tree fold_if_not_in_template		(tree);
 extern tree rvalue				(tree);
 extern tree convert_bitfield_to_declared_type   (tree);
 extern tree cp_save_expr			(tree);
@@ -6705,6 +6709,7 @@ extern tree cxx_omp_clause_dtor			(tree, tree);
 extern void cxx_omp_finish_clause		(tree, gimple_seq *);
 extern bool cxx_omp_privatize_by_reference	(const_tree);
 extern bool cxx_omp_disregard_value_expr	(tree, bool);
+extern tree cp_fully_fold			(tree);
 
 /* in name-lookup.c */
 extern void suggest_alternatives_for            (location_t, tree);
@@ -6796,6 +6801,7 @@ extern tree cxx_constant_value			(tree, tree = NULL_TREE);
 extern tree maybe_constant_value		(tree, tree = NULL_TREE);
 extern tree maybe_constant_init			(tree, tree = NULL_TREE);
 extern tree fold_non_dependent_expr		(tree);
+extern tree fold_simple				(tree);
 extern bool is_sub_constant_expr                (tree);
 extern bool reduced_constant_expression_p       (tree);
 extern bool is_instantiation_of_constexpr       (tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index e764ee1..51b992c 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -53,7 +53,7 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
 
    Here is a list of all the functions that assume that widening and
    narrowing is always done with a NOP_EXPR:
-     In convert.c, convert_to_integer.
+     In convert.c, convert_to_integer[_nofold].
      In c-typeck.c, build_binary_op_nodefault (boolean ops),
 	and c_common_truthvalue_conversion.
      In expr.c: expand_expr, for operands of a MULT_EXPR.
@@ -240,7 +240,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
       gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
 		  == GET_MODE_SIZE (TYPE_MODE (type)));
 
-      return convert_to_pointer (type, expr);
+      return convert_to_pointer_nofold (type, expr);
     }
 
   if (type_unknown_p (expr))
@@ -608,6 +608,7 @@ cp_fold_convert (tree type, tree expr)
       conv = fold_convert (type, expr);
       conv = ignore_overflows (conv, expr);
     }
+
   return conv;
 }
 
@@ -633,7 +634,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
 
   if (TREE_TYPE (expr) == type)
     return expr;
-  
+  if (expr == error_mark_node)
+    return expr;
   result = cp_convert (type, expr, complain);
 
   if ((complain & tf_warning)
@@ -641,13 +643,14 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
     {
       tree folded = maybe_constant_value (expr);
       tree stripped = folded;
-      tree folded_result
+      tree folded_result;
+      folded_result
 	= folded != expr ? cp_convert (type, folded, complain) : result;
-
-      /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
-	 NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
+      folded_result = cp_fully_fold (folded_result);
+      /* The maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW
+	 in a NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
       STRIP_NOPS (stripped);
-
+      folded = cp_fully_fold (folded);
       if (!TREE_OVERFLOW_P (stripped)
 	  && folded_result != error_mark_node)
 	warnings_for_convert_and_check (input_location, type, folded,
@@ -706,9 +709,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       /* For complex data types, we need to perform componentwise
 	 conversion.  */
       else if (TREE_CODE (type) == COMPLEX_TYPE)
-	return fold_if_not_in_template (convert_to_complex (type, e));
+	return convert_to_complex_nofold (type, e);
       else if (VECTOR_TYPE_P (type))
-	return fold_if_not_in_template (convert_to_vector (type, e));
+	return convert_to_vector (type, e);
       else if (TREE_CODE (e) == TARGET_EXPR)
 	{
 	  /* Don't build a NOP_EXPR of class type.  Instead, change the
@@ -721,7 +724,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 	  /* We shouldn't be treating objects of ADDRESSABLE type as
 	     rvalues.  */
 	  gcc_assert (!TREE_ADDRESSABLE (type));
-	  return fold_if_not_in_template (build_nop (type, e));
+	  return build_nop (type, e);
 	}
     }
 
@@ -799,7 +802,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 	  return cp_truthvalue_conversion (e);
 	}
 
-      converted = fold_if_not_in_template (convert_to_integer (type, e));
+      converted = convert_to_integer_nofold (type, e);
 
       /* Ignore any integer overflow caused by the conversion.  */
       return ignore_overflows (converted, e);
@@ -811,7 +814,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       return nullptr_node;
     }
   if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
-    return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
+    return cp_convert_to_pointer (type, e, complain);
   if (code == VECTOR_TYPE)
     {
       tree in_vtype = TREE_TYPE (e);
@@ -826,7 +829,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 		      in_vtype, type);
 	  return error_mark_node;
 	}
-      return fold_if_not_in_template (convert_to_vector (type, e));
+      return convert_to_vector (type, e);
     }
   if (code == REAL_TYPE || code == COMPLEX_TYPE)
     {
@@ -842,9 +845,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 		      TREE_TYPE (e));
 	}
       if (code == REAL_TYPE)
-	return fold_if_not_in_template (convert_to_real (type, e));
+	return convert_to_real_nofold (type, e);
       else if (code == COMPLEX_TYPE)
-	return fold_if_not_in_template (convert_to_complex (type, e));
+	return convert_to_complex_nofold (type, e);
     }
 
   /* New C++ semantics:  since assignment is now based on
@@ -1457,7 +1460,7 @@ convert (tree type, tree expr)
   intype = TREE_TYPE (expr);
 
   if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
-    return fold_if_not_in_template (build_nop (type, expr));
+    return build_nop (type, expr);
 
   return ocp_convert (type, expr, CONV_OLD_CONVERT,
 		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
@@ -1475,13 +1478,11 @@ convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
   enum tree_code code = TREE_CODE (type);
 
   if (code == REFERENCE_TYPE)
-    return (fold_if_not_in_template
-	    (convert_to_reference (type, e, CONV_C_CAST, 0,
-				   NULL_TREE, complain)));
+    return convert_to_reference (type, e, CONV_C_CAST, 0,
+				 NULL_TREE, complain);
 
   if (code == POINTER_TYPE)
-    return fold_if_not_in_template (convert_to_pointer_force (type, e,
-							      complain));
+    return convert_to_pointer_force (type, e, complain);
 
   /* From typeck.c convert_for_assignment */
   if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bd3f2bc..484f4f2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8580,35 +8580,6 @@ stabilize_vla_size (tree size)
   cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset);
 }
 
-/* Helper function for compute_array_index_type.  Look for SIZEOF_EXPR
-   not inside of SAVE_EXPR and fold them.  */
-
-static tree
-fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
-{
-  tree expr = *expr_p;
-  if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
-    *walk_subtrees = 0;
-  else if (TREE_CODE (expr) == SIZEOF_EXPR)
-    {
-      *(bool *)data = true;
-      if (SIZEOF_EXPR_TYPE_P (expr))
-	expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
-					   SIZEOF_EXPR, false);
-      else if (TYPE_P (TREE_OPERAND (expr, 0)))
-	expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
-					   false);
-      else
-        expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
-					   false);
-      if (expr == error_mark_node)
-        expr = size_one_node;
-      *expr_p = expr;
-      *walk_subtrees = 0;
-    }
-  return NULL;
-}
-
 /* Given the SIZE (i.e., number of elements) in an array, compute an
    appropriate index type for the array.  If non-NULL, NAME is the
    name of the thing being declared.  */
@@ -8699,7 +8670,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       SET_TYPE_STRUCTURAL_EQUALITY (itype);
       return itype;
     }
-  
+
+  if (TREE_CODE (size) != INTEGER_CST)
+    {
+      tree folded = cp_fully_fold (size);
+      if (TREE_CODE (folded) == INTEGER_CST)
+	pedwarn (location_of (size), OPT_Wpedantic,
+		 "size of array is not an integral constant-expression");
+      /* Use the folded result for VLAs, too; it will have resolved
+	 SIZEOF_EXPR.  */
+      size = folded;
+    }
+
   /* Normally, the array-bound will be a constant.  */
   if (TREE_CODE (size) == INTEGER_CST)
     {
@@ -8786,7 +8768,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 				  cp_convert (ssizetype, integer_one_node,
 					      complain),
 				  complain);
-      itype = fold (itype);
+      itype = maybe_constant_value (itype);
       processing_template_decl = saved_processing_template_decl;
 
       if (!TREE_CONSTANT (itype))
@@ -8794,18 +8776,6 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
 	  /* A variable sized array.  */
 	  itype = variable_size (itype);
 
-	  if (TREE_CODE (itype) != SAVE_EXPR)
-	    {
-	      /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
-		 they might survive till gimplification.  */
-	      tree newitype = itype;
-	      bool found = false;
-	      cp_walk_tree_without_duplicates (&newitype,
-					       fold_sizeof_expr_r, &found);
-	      if (found)
-		itype = variable_size (fold (newitype));
-	    }
-
 	  stabilize_vla_size (itype);
 
 	  if (flag_sanitize & SANITIZE_VLA
@@ -13515,7 +13485,7 @@ incremented enumerator value is too large for %<long%>");
 		   "type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype));
 
           /* Convert the value to the appropriate type.  */
-          value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
+          value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
         }
     }
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a2d31a3..89859e9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3116,7 +3116,7 @@ get_guard_cond (tree guard, bool thread_safe)
     {
       guard_value = integer_one_node;
       if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
-	guard_value = convert (TREE_TYPE (guard), guard_value);
+	guard_value = fold_convert (TREE_TYPE (guard), guard_value);
       guard = cp_build_binary_op (input_location,
 				  BIT_AND_EXPR, guard, guard_value,
 				  tf_warning_or_error);
@@ -3124,7 +3124,7 @@ get_guard_cond (tree guard, bool thread_safe)
 
   guard_value = integer_zero_node;
   if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
-    guard_value = convert (TREE_TYPE (guard), guard_value);
+    guard_value = fold_convert (TREE_TYPE (guard), guard_value);
   return cp_build_binary_op (input_location,
 			     EQ_EXPR, guard, guard_value,
 			     tf_warning_or_error);
@@ -3142,7 +3142,7 @@ set_guard (tree guard)
   guard = get_guard_bits (guard);
   guard_init = integer_one_node;
   if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
-    guard_init = convert (TREE_TYPE (guard), guard_init);
+    guard_init = fold_convert (TREE_TYPE (guard), guard_init);
   return cp_build_modify_expr (guard, NOP_EXPR, guard_init, 
 			       tf_warning_or_error);
 }
@@ -4573,6 +4573,19 @@ c_parse_final_cleanups (void)
       /* If there are templates that we've put off instantiating, do
 	 them now.  */
       instantiate_pending_templates (retries);
+      /* Clear fold_map and/or cv_map of current scope, if present.  */
+      if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree,tree> *fm = scope_chain->fold_map;
+	  hash_map<tree,tree> *cv = scope_chain->cv_map;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	}
       ggc_collect ();
 
       /* Write out virtual tables as required.  Note that writing out
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b45281f..fd9ae0d 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -178,9 +178,9 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
        initialized are initialized to zero.  */
     ;
   else if (TYPE_PTR_OR_PTRMEM_P (type))
-    init = convert (type, nullptr_node);
+    init = fold (convert (type, nullptr_node));
   else if (SCALAR_TYPE_P (type))
-    init = convert (type, integer_zero_node);
+    init = fold (convert (type, integer_zero_node));
   else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type)))
     {
       tree field;
@@ -794,7 +794,6 @@ perform_member_init (tree member, tree init)
 	   in that case.  */
 	init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
 						tf_warning_or_error);
-
       if (init)
 	finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
 						tf_warning_or_error));
@@ -2712,7 +2711,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
       }
       max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
 
-      size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+      size = size_binop (MULT_EXPR, size, fold_convert (sizetype, nelts));
       outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
 				       outer_nelts,
 				       max_outer_nelts_tree);
@@ -2872,7 +2871,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 	{
 	  placement_expr = get_target_expr (placement_first);
 	  CALL_EXPR_ARG (alloc_call, 1)
-	    = convert (TREE_TYPE (placement), placement_expr);
+	    = fold_convert (TREE_TYPE (placement), placement_expr);
 	}
 
       if (!member_new_p
@@ -3464,7 +3463,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   /* The below is short by the cookie size.  */
   virtual_size = size_binop (MULT_EXPR, size_exp,
-			     convert (sizetype, maxindex));
+			     fold_convert (sizetype, maxindex));
 
   tbase = create_temporary_var (ptype);
   tbase_init
@@ -3507,7 +3506,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
       /* The below is short by the cookie size.  */
       virtual_size = size_binop (MULT_EXPR, size_exp,
-				 convert (sizetype, maxindex));
+				 fold_convert (sizetype, maxindex));
 
       if (! TYPE_VEC_NEW_USES_COOKIE (type))
 	/* no header */
@@ -3553,8 +3552,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
 		      fold_build2_loc (input_location,
 				   NE_EXPR, boolean_type_node, base,
-				   convert (TREE_TYPE (base),
-					    nullptr_node)),
+				   fold_convert (TREE_TYPE (base),
+						 nullptr_node)),
 		      body, integer_zero_node);
   body = build1 (NOP_EXPR, void_type_node, body);
 
@@ -3676,6 +3675,7 @@ build_vec_init (tree base, tree maxindex, tree init,
   if (maxindex == NULL_TREE || maxindex == error_mark_node)
     return error_mark_node;
 
+  maxindex = maybe_constant_value (maxindex);
   if (explicit_value_init_p)
     gcc_assert (!init);
 
@@ -3717,6 +3717,8 @@ build_vec_init (tree base, tree maxindex, tree init,
     }
 
   maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
+  maxindex = fold_simple (maxindex);
+
   if (TREE_CODE (atype) == ARRAY_TYPE)
     {
       ptype = build_pointer_type (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 8744fff..61a352a 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -6182,6 +6182,19 @@ push_to_top_level (void)
   s->unevaluated_operand = cp_unevaluated_operand;
   s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
   s->x_stmt_tree.stmts_are_full_exprs_p = true;
+  if (current_function_decl
+      && scope_chain && scope_chain->function_decl == current_function_decl
+      && cfun && scope_chain->act_cfun == cfun)
+    {
+      s->fold_map = scope_chain->fold_map;
+      s->cv_map = scope_chain->cv_map;
+    }
+  else
+    {
+      s->fold_map = NULL;
+      s->cv_map = NULL;
+    }
+  s->act_cfun = cfun;
 
   scope_chain = s;
   current_function_decl = NULL_TREE;
@@ -6199,7 +6212,10 @@ pop_from_top_level_1 (void)
 {
   struct saved_scope *s = scope_chain;
   cxx_saved_binding *saved;
+  hash_map<tree, tree> *fm = s->fold_map;
+  hash_map<tree, tree> *cv = s->cv_map;
   size_t i;
+  bool same_fold_map = false;
 
   /* Clear out class-level bindings cache.  */
   if (previous_class_level)
@@ -6221,9 +6237,32 @@ pop_from_top_level_1 (void)
      state.  */
   if (s->need_pop_function_context)
     pop_function_context ();
+
+  /* If 'current_function_decl' isn't NULL and is equal to prior pushed,
+     we are within a nested function.
+     If additionally saved 'cfun' is identical to current, we can use
+     the same 'fold_map'.  */
+     
+  if (current_function_decl && s->function_decl == current_function_decl
+      && scope_chain && s->fold_map == scope_chain->fold_map
+      && scope_chain->act_cfun && scope_chain->act_cfun == cfun)
+    same_fold_map = true;
+
   current_function_decl = s->function_decl;
   cp_unevaluated_operand = s->unevaluated_operand;
   c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
+
+  /* If we have a new 'fold_map', and it isn't equal, or outside of
+     scope_chain, then invalidate it.  */
+  if (fm && (!same_fold_map || !scope_chain))
+    delete fm;
+  if (cv && (!same_fold_map || !scope_chain))
+    delete cv;
+
+  /* Invalidate explicit.  */
+  s->fold_map = NULL;
+  s->cv_map = NULL;
+  s->act_cfun = NULL;
 }
 
 /* Wrapper for pop_from_top_level_1.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d1f4970..24a77f8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6769,7 +6769,7 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
 	 2. ARRAY [ EXP : EXP ]
 	 3. ARRAY [ EXP : EXP : EXP ]  */
 
-      *init_index = cp_parser_expression (parser);	
+      *init_index = cp_parser_expression (parser);
       if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
 	{  
 	  /* This indicates that we have a normal array expression.  */
@@ -8513,9 +8513,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
       /* For "false && x" or "true || x", x will never be executed;
 	 disable warnings while evaluating it.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings +=
+	  cp_fully_fold (current.lhs) == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings += current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings +=
+	  cp_fully_fold (current.lhs) == truthvalue_true_node;
 
       /* Extract another operand.  It may be the RHS of this expression
 	 or the LHS of a new, higher priority expression.  */
@@ -8562,9 +8564,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 
       /* Undo the disabling of warnings done above.  */
       if (current.tree_type == TRUTH_ANDIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_false_node;
+	c_inhibit_evaluation_warnings -=
+	  cp_fully_fold (current.lhs) == truthvalue_false_node;
       else if (current.tree_type == TRUTH_ORIF_EXPR)
-	c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
+	c_inhibit_evaluation_warnings -=
+	  cp_fully_fold (current.lhs) == truthvalue_true_node;
 
       if (warn_logical_not_paren
 	  && TREE_CODE_CLASS (current.tree_type) == tcc_comparison
@@ -8650,7 +8654,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
 static tree
 cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
 {
-  tree expr;
+  tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr);
   tree assignment_expr;
   struct cp_token *token;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -8665,7 +8669,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
                "ISO C++ does not allow ?: with omitted middle operand");
       /* Implicit true clause.  */
       expr = NULL_TREE;
-      c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node;
+      c_inhibit_evaluation_warnings +=
+	folded_logical_or_expr == truthvalue_true_node;
       warn_for_omitted_condop (token->location, logical_or_expr);
     }
   else
@@ -8673,11 +8678,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
       bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
       parser->colon_corrects_to_scope_p = false;
       /* Parse the expression.  */
-      c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
+      c_inhibit_evaluation_warnings +=
+	folded_logical_or_expr == truthvalue_false_node;
       expr = cp_parser_expression (parser);
       c_inhibit_evaluation_warnings +=
-	((logical_or_expr == truthvalue_true_node)
-	 - (logical_or_expr == truthvalue_false_node));
+	((folded_logical_or_expr == truthvalue_true_node)
+	 - (folded_logical_or_expr == truthvalue_false_node));
       parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
     }
 
@@ -8685,7 +8691,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
   cp_parser_require (parser, CPP_COLON, RT_COLON);
   /* Parse the assignment-expression.  */
   assignment_expr = cp_parser_assignment_expression (parser);
-  c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node;
+  c_inhibit_evaluation_warnings -=
+    folded_logical_or_expr == truthvalue_true_node;
 
   /* Build the conditional-expression.  */
   return build_x_conditional_expr (loc, logical_or_expr,
@@ -20330,8 +20337,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
     {
       initializer
 	= cp_parser_constant_expression (parser,
-					/*allow_non_constant_p=*/true,
-					non_constant_p);
+					 /*allow_non_constant_p=*/true,
+					 non_constant_p);
     }
   else
     initializer = cp_parser_braced_list (parser, non_constant_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfea8e2..fb9cdf8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6217,7 +6217,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   /* 14.3.2/5: The null pointer{,-to-member} conversion is applied
      to a non-type argument of "nullptr".  */
   if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
-    expr = convert (type, expr);
+    expr = fold_simple (convert (type, expr));
 
   /* In C++11, integral or enumeration non-type template arguments can be
      arbitrary constant expressions.  Pointer and pointer to
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7702a41..73f05f0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2569,9 +2569,26 @@ finish_unary_op_expr (location_t loc, enum tree_code code, tree expr,
 		      tsubst_flags_t complain)
 {
   tree result = build_x_unary_op (loc, code, expr, complain);
-  if ((complain & tf_warning)
-      && TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr))
-    overflow_warning (input_location, result);
+  tree result_ovl, expr_ovl;
+
+  if (!(complain & tf_warning))
+    return result;
+
+  result_ovl = result;
+  expr_ovl = expr;
+
+  if (!processing_template_decl)
+    expr_ovl = cp_fully_fold (expr_ovl);
+
+  if (!CONSTANT_CLASS_P (expr_ovl)
+      || TREE_OVERFLOW_P (expr_ovl))
+    return result;
+
+  if (!processing_template_decl)
+    result_ovl = cp_fully_fold (result_ovl);
+
+  if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
+    overflow_warning (input_location, result_ovl);
 
   return result;
 }
@@ -3895,6 +3912,7 @@ finish_offsetof (tree expr, location_t loc)
 	      TREE_OPERAND (expr, 2));
       return error_mark_node;
     }
+
   if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
       || TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE
       || TREE_TYPE (expr) == unknown_type_node)
@@ -4049,6 +4067,22 @@ emit_associated_thunks (tree fn)
 bool
 expand_or_defer_fn_1 (tree fn)
 {
+  if (!function_depth)
+    {
+      if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree, tree> *fm = scope_chain->fold_map;
+	  hash_map<tree, tree> *cv = scope_chain->cv_map;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	}
+    }
+
   /* When the parser calls us after finishing the body of a template
      function, we don't really want to expand the body.  */
   if (processing_template_decl)
@@ -4129,6 +4163,19 @@ expand_or_defer_fn (tree fn)
       emit_associated_thunks (fn);
 
       function_depth--;
+      if (function_depth == 0
+	  && scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+	{
+	  hash_map<tree, tree> *fm = scope_chain->fold_map;
+	  hash_map<tree, tree> *cv = scope_chain->cv_map;
+	  scope_chain->fold_map = NULL;
+	  scope_chain->cv_map = NULL;
+	  scope_chain->act_cfun = NULL;
+	  if (fm)
+	    delete fm;
+	  if (cv)
+	    delete cv;
+	}
     }
 }
 
@@ -4483,6 +4530,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
     low_bound = mark_rvalue_use (low_bound);
   if (length)
     length = mark_rvalue_use (length);
+  /* We need to reduce to real constant-values for checks below.  */
+  if (length)
+    length = fold_simple (length);
+  if (low_bound)
+    low_bound = fold_simple (low_bound);
   if (low_bound
       && TREE_CODE (low_bound) == INTEGER_CST
       && TYPE_PRECISION (TREE_TYPE (low_bound))
@@ -6178,7 +6230,8 @@ finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd)
 		  if (OMP_CLAUSE_SCHEDULE_KIND (c)
 		      == OMP_CLAUSE_SCHEDULE_CILKFOR)
 		    {
-		      t = convert_to_integer (long_integer_type_node, t);
+		      t = convert_to_integer_nofold (long_integer_type_node,
+						     t);
 		      if (t == error_mark_node)
 			{
 			  remove = true;
@@ -7447,6 +7500,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
   if (init && EXPR_HAS_LOCATION (init))
     elocus = EXPR_LOCATION (init);
 
+  cond = cp_fully_fold (cond);
   switch (TREE_CODE (cond))
     {
     case GT_EXPR:
@@ -7482,6 +7536,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
   diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1),
 			    ERROR_MARK, iter, ERROR_MARK, NULL,
 			    tf_warning_or_error);
+  diff = cp_fully_fold (diff);
   if (error_operand_p (diff))
     return true;
   if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE)
@@ -7543,8 +7598,9 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
 		  if (TREE_CODE (rhs) == MINUS_EXPR)
 		    {
 		      incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
-		      incr = fold_if_not_in_template (incr);
+		      incr = fold_simple (incr);
 		    }
+
 		  if (TREE_CODE (incr) != INTEGER_CST
 		      && (TREE_CODE (incr) != NOP_EXPR
 			  || (TREE_CODE (TREE_OPERAND (incr, 0))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4311212..dd4daed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -308,9 +308,19 @@ xvalue_p (const_tree ref)
 bool
 builtin_valid_in_constant_expr_p (const_tree decl)
 {
-  /* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing
-     in constant-expressions.  We may want to add other builtins later. */
-  return DECL_IS_BUILTIN_CONSTANT_P (decl);
+  if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)))
+    /* Not a built-in.  */
+    return false;
+  switch (DECL_FUNCTION_CODE (decl))
+    {
+    case BUILT_IN_CONSTANT_P:
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      /* These have constant results even if their operands are
+	 non-constant.  */
+      return true;
+    default:
+      return false;
+    }
 }
 
 /* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
@@ -686,8 +696,8 @@ convert_bitfield_to_declared_type (tree expr)
 
   bitfield_type = is_bitfield_expr_with_lowered_type (expr);
   if (bitfield_type)
-    expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type),
-			       expr);
+    expr = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type),
+				      expr);
   return expr;
 }
 
@@ -3484,10 +3494,13 @@ handle_init_priority_attribute (tree* node,
 
   STRIP_NOPS (initp_expr);
   initp_expr = default_conversion (initp_expr);
+  if (initp_expr)
+    initp_expr = maybe_constant_value (initp_expr);
 
   if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
     {
       error ("requested init_priority is not an integer constant");
+      cxx_constant_value (initp_expr);
       *no_add_attrs = true;
       return NULL_TREE;
     }
@@ -4262,26 +4275,6 @@ stabilize_init (tree init, tree *initp)
   return !TREE_SIDE_EFFECTS (init);
 }
 
-/* Like "fold", but should be used whenever we might be processing the
-   body of a template.  */
-
-tree
-fold_if_not_in_template (tree expr)
-{
-  /* In the body of a template, there is never any need to call
-     "fold".  We will call fold later when actually instantiating the
-     template.  Integral constant expressions in templates will be
-     evaluated via instantiate_non_dependent_expr, as necessary.  */
-  if (processing_template_decl)
-    return expr;
-
-  /* Fold C++ front-end specific tree codes.  */
-  if (TREE_CODE (expr) == UNARY_PLUS_EXPR)
-    return fold_convert (TREE_TYPE (expr), TREE_OPERAND (expr, 0));
-
-  return fold (expr);
-}
-
 /* Returns true if a cast to TYPE may appear in an integral constant
    expression.  */
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0501e4d..4e7ef58 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1948,8 +1948,6 @@ decay_conversion (tree exp,
 
   code = TREE_CODE (type);
 
-  /* FIXME remove for delayed folding.  */
-  exp = scalar_constant_value (exp);
   if (error_operand_p (exp))
     return error_mark_node;
 
@@ -2442,7 +2440,6 @@ build_class_member_access_expr (tree object, tree member,
 
       result = build3_loc (input_location, COMPONENT_REF, member_type,
 			   object, member, NULL_TREE);
-      result = fold_if_not_in_template (result);
 
       /* Mark the expression const or volatile, as appropriate.  Even
 	 though we've dealt with the type above, we still have to mark the
@@ -2855,9 +2852,9 @@ build_simple_component_ref (tree object, tree member)
 {
   tree type = cp_build_qualified_type (TREE_TYPE (member),
 				       cp_type_quals (TREE_TYPE (object)));
-  return fold_build3_loc (input_location,
-			  COMPONENT_REF, type,
-			  object, member, NULL_TREE);
+  return build3_loc (input_location,
+		     COMPONENT_REF, type,
+		     object, member, NULL_TREE);
 }
 
 /* Return an expression for the MEMBER_NAME field in the internal
@@ -3176,8 +3173,7 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
       TREE_THIS_VOLATILE (rval)
 	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
-      ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
-					  complain);
+      ret = require_complete_type_sfinae (rval, complain);
       protected_set_expr_location (ret, loc);
       if (non_lvalue)
 	ret = non_lvalue_loc (loc, ret);
@@ -3924,7 +3920,6 @@ build_vec_cmp (tree_code code, tree type,
   tree minus_one_vec = build_minus_one_cst (type);
   tree cmp_type = build_same_sized_truth_vector_type(type);
   tree cmp = build2 (code, cmp_type, arg0, arg1);
-  cmp = fold_if_not_in_template (cmp);
   return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
 }
 
@@ -3979,7 +3974,7 @@ cp_build_binary_op (location_t location,
      convert it to this type.  */
   tree final_type = 0;
 
-  tree result;
+  tree result, result_ovl;
   tree orig_type = NULL;
 
   /* Nonzero if this is an operation like MIN or MAX which can
@@ -4602,7 +4597,7 @@ cp_build_binary_op (location_t location,
 	      op0 = cp_build_binary_op (location,
 					TRUTH_ANDIF_EXPR, e1, e2,
 					complain);
-	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain); 
+	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
 	    }
      	  else 
 	    {
@@ -4643,10 +4638,12 @@ cp_build_binary_op (location_t location,
 	    op1 = save_expr (op1);
 
 	  pfn0 = pfn_from_ptrmemfunc (op0);
+	  pfn0 = cp_fully_fold (pfn0);
 	  /* Avoid -Waddress warnings (c++/64877).  */
 	  if (TREE_CODE (pfn0) == ADDR_EXPR)
 	    TREE_NO_WARNING (pfn0) = 1;
 	  pfn1 = pfn_from_ptrmemfunc (op1);
+	  pfn1 = cp_fully_fold (pfn1);
 	  delta0 = delta_from_ptrmemfunc (op0);
 	  delta1 = delta_from_ptrmemfunc (op1);
 	  if (TARGET_PTRMEMFUNC_VBIT_LOCATION
@@ -5000,10 +4997,7 @@ cp_build_binary_op (location_t location,
 		  gcc_unreachable();
 		}
 	    }
-	  real = fold_if_not_in_template (real);
-	  imag = fold_if_not_in_template (imag);
 	  result = build2 (COMPLEX_EXPR, result_type, real, imag);
-	  result = fold_if_not_in_template (result);
 	  return result;
 	}
 
@@ -5031,20 +5025,12 @@ cp_build_binary_op (location_t location,
 
       if (short_compare)
 	{
-	  /* Don't write &op0, etc., because that would prevent op0
-	     from being kept in a register.
-	     Instead, make copies of the our local variables and
-	     pass the copies by reference, then copy them back afterward.  */
-	  tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+	  /* We call shorten_compare only for diagnostic-reason.  */
+	  tree xop0 = fold_simple (op0), xop1 = fold_simple (op1),
+	       xresult_type = result_type;
 	  enum tree_code xresultcode = resultcode;
-	  tree val
-	    = shorten_compare (location, &xop0, &xop1, &xresult_type,
+	  shorten_compare (location, &xop0, &xop1, &xresult_type,
 			       &xresultcode);
-	  if (val != 0)
-	    return cp_convert (boolean_type_node, val, complain);
-	  op0 = xop0, op1 = xop1;
-	  converted = 1;
-	  resultcode = xresultcode;
 	}
 
       if ((short_compare || code == MIN_EXPR || code == MAX_EXPR)
@@ -5063,9 +5049,9 @@ cp_build_binary_op (location_t location,
 	  tree oop1 = maybe_constant_value (orig_op1);
 
 	  if (TREE_CODE (oop0) != INTEGER_CST)
-	    oop0 = orig_op0;
+	    oop0 = cp_fully_fold (orig_op0);
 	  if (TREE_CODE (oop1) != INTEGER_CST)
-	    oop1 = orig_op1;
+	    oop1 = cp_fully_fold (orig_op1);
 	  warn_for_sign_compare (location, oop0, oop1, op0, op1, 
 				 result_type, resultcode);
 	}
@@ -5120,18 +5106,30 @@ cp_build_binary_op (location_t location,
     }
 
   result = build2 (resultcode, build_type, op0, op1);
-  result = fold_if_not_in_template (result);
   if (final_type != 0)
     result = cp_convert (final_type, result, complain);
 
-  if (TREE_OVERFLOW_P (result) 
-      && !TREE_OVERFLOW_P (op0) 
-      && !TREE_OVERFLOW_P (op1))
-    overflow_warning (location, result);
-
   if (instrument_expr != NULL)
-    result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
-			  instrument_expr, result);
+    result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+		     instrument_expr, result);
+
+  if (!processing_template_decl)
+    {
+      op0 = cp_fully_fold (op0);
+      /* Only consider the second argument if the first isn't overflowed.  */
+      if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
+	return result;
+      op1 = cp_fully_fold (op1);
+      if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+	return result;
+    }
+  else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
+	   || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
+    return result;
+
+  result_ovl = fold_build2 (resultcode, build_type, op0, op1);
+  if (TREE_OVERFLOW_P (result_ovl))
+    overflow_warning (location, result_ovl);
 
   return result;
 }
@@ -5181,8 +5179,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
   complete_type (TREE_TYPE (res_type));
 
   return pointer_int_sum (input_location, resultcode, ptrop,
-			  fold_if_not_in_template (intop),
-			  complain & tf_warning_or_error);
+			  intop, complain & tf_warning_or_error);
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
@@ -5258,7 +5255,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
 
   result = build2 (EXACT_DIV_EXPR, restype, op0,
 		   cp_convert (restype, op1, complain));
-  return fold_if_not_in_template (result);
+  return result;
 }
 \f
 /* Construct and perhaps optimize a tree representation
@@ -5774,6 +5771,10 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
 	    /* Make sure the result is not an lvalue: a unary plus or minus
 	       expression is always a rvalue.  */
 	    arg = rvalue (arg);
+
+	    if (code == NEGATE_EXPR && CONSTANT_CLASS_P (arg))
+	      /* Immediately fold negation of a constant.  */
+	      return fold_build1 (code, TREE_TYPE (arg), arg);
 	  }
       }
       break;
@@ -5838,10 +5839,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     case REALPART_EXPR:
     case IMAGPART_EXPR:
       arg = build_real_imag_expr (input_location, code, arg);
-      if (arg == error_mark_node)
-	return arg;
-      else
-	return fold_if_not_in_template (arg);
+      return arg;
 
     case PREINCREMENT_EXPR:
     case POSTINCREMENT_EXPR:
@@ -6008,7 +6006,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
     {
       if (argtype == 0)
 	argtype = TREE_TYPE (arg);
-      return fold_if_not_in_template (build1 (code, argtype, arg));
+      return build1 (code, argtype, arg);
     }
 
   if (complain & tf_error)
@@ -7002,7 +7000,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
     return rvalue (expr);
   else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
 	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
-    return fold_if_not_in_template (build_nop (type, expr));
+    return build_nop (type, expr);
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
 	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
     {
@@ -7030,7 +7028,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
       if (warn_strict_aliasing <= 2)
 	strict_aliasing_warning (intype, type, sexpr);
 
-      return fold_if_not_in_template (build_nop (type, expr));
+      return build_nop (type, expr);
     }
   else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
 	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7041,13 +7039,13 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
 	warning (OPT_Wconditionally_supported,
 		 "casting between pointer-to-function and pointer-to-object "
 		 "is conditionally-supported");
-      return fold_if_not_in_template (build_nop (type, expr));
+      return build_nop (type, expr);
     }
   else if (VECTOR_TYPE_P (type))
-    return fold_if_not_in_template (convert_to_vector (type, expr));
+    return convert_to_vector (type, expr);
   else if (VECTOR_TYPE_P (intype)
 	   && INTEGRAL_OR_ENUMERATION_TYPE_P (type))
-    return fold_if_not_in_template (convert_to_integer (type, expr));
+    return convert_to_integer_nofold (type, expr);
   else
     {
       if (valid_p)
@@ -7899,8 +7897,7 @@ get_delta_difference (tree from, tree to,
       }
   }
 
-  return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
-						      result));
+  return convert_to_integer (ptrdiff_type_node, result);
 }
 
 /* Return a constructor for the pointer-to-member-function TYPE using
@@ -8081,41 +8078,35 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
 	 fn; the call will do the opposite adjustment.  */
       tree orig_class = DECL_CONTEXT (fn);
       tree binfo = binfo_or_else (orig_class, fn_class);
-      *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
-		       *delta, BINFO_OFFSET (binfo));
-      *delta = fold_if_not_in_template (*delta);
+      *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+			    *delta, BINFO_OFFSET (binfo));
 
       /* We set PFN to the vtable offset at which the function can be
 	 found, plus one (unless ptrmemfunc_vbit_in_delta, in which
 	 case delta is shifted left, and then incremented).  */
       *pfn = DECL_VINDEX (fn);
-      *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
-		     TYPE_SIZE_UNIT (vtable_entry_type));
-      *pfn = fold_if_not_in_template (*pfn);
+      *pfn = fold_build2 (MULT_EXPR, integer_type_node, *pfn,
+			  TYPE_SIZE_UNIT (vtable_entry_type));
 
       switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
 	{
 	case ptrmemfunc_vbit_in_pfn:
-	  *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
-			 integer_one_node);
-	  *pfn = fold_if_not_in_template (*pfn);
+	  *pfn = fold_build2 (PLUS_EXPR, integer_type_node, *pfn,
+			      integer_one_node);
 	  break;
 
 	case ptrmemfunc_vbit_in_delta:
-	  *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
-			   *delta, integer_one_node);
-	  *delta = fold_if_not_in_template (*delta);
-	  *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
-			   *delta, integer_one_node);
-	  *delta = fold_if_not_in_template (*delta);
+	  *delta = fold_build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node);
+	  *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+				*delta, integer_one_node);
 	  break;
 
 	default:
 	  gcc_unreachable ();
 	}
 
-      *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
-      *pfn = fold_if_not_in_template (*pfn);
+      *pfn = fold_convert (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
     }
 }
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e73ea13..7544333 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -742,6 +742,7 @@ split_nonconstant_init (tree dest, tree init)
     init = TARGET_EXPR_INITIAL (init);
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
+      init = cp_fully_fold (init);
       code = push_stmt_list ();
       if (split_nonconstant_init_1 (dest, init))
 	init = NULL_TREE;
@@ -832,6 +833,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
       TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
     }
+  value = cp_fully_fold (value);
 
   if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
     /* Handle aggregate NSDMI in non-constant initializers, too.  */
@@ -930,19 +932,35 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	}
     }
 
+  bool almost_ok = ok;
+  if (!ok && !CONSTANT_CLASS_P (init) && (complain & tf_warning_or_error))
+    {
+      tree folded = cp_fully_fold (init);
+      if (TREE_CONSTANT (folded) && check_narrowing (type, folded, tf_none))
+	almost_ok = true;
+    }
+
   if (!ok)
     {
+      location_t loc = EXPR_LOC_OR_LOC (init, input_location);
       if (cxx_dialect == cxx98)
-	warning_at (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
-		    "narrowing conversion of %qE from %qT to %qT inside { } "
-		    "is ill-formed in C++11", init, ftype, type);
-      else if (!TREE_CONSTANT (init))
+	{
+	  if (complain & tf_warning)
+	    warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+			"from %qT to %qT inside { } is ill-formed in C++11",
+			init, ftype, type);
+	  ok = true;
+	}
+      else if (!CONSTANT_CLASS_P (init))
 	{
 	  if (complain & tf_warning_or_error)
 	    {
-	      pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
-		       "narrowing conversion of %qE from %qT to %qT inside { }",
-		       init, ftype, type);
+	      if (!almost_ok || pedantic)
+		pedwarn (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+			 "from %qT to %qT inside { }", init, ftype, type);
+	      if (pedantic && almost_ok)
+		inform (loc, " the expression has a constant value but is not "
+			"a C++ constant-expression");
 	      ok = true;
 	    }
 	}
@@ -950,7 +968,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	{
 	  int savederrorcount = errorcount;
 	  global_dc->pedantic_errors = 1;
-	  pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
+	  pedwarn (loc, OPT_Wnarrowing,
 		   "narrowing conversion of %qE from %qT to %qT "
 		   "inside { }", init, ftype, type);
 	  if (errorcount == savederrorcount)
@@ -959,7 +977,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
 	}
     }
 
-  return cxx_dialect == cxx98 || ok; 
+  return ok;
 }
 
 /* Process the initializer INIT for a variable of type TYPE, emitting
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
index 5d803ad..8f14034 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
@@ -47,3 +47,5 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
index fc89af1..55523a5 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
index bf9b1a0..1295b72 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
index 85fbd0e..3088220 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
@@ -47,3 +47,6 @@ right (int x)
   r += -1U >> x;
   return r;
 }
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/fold-bitand-4.c b/gcc/testsuite/c-c++-common/fold-bitand-4.c
index 1b9c388..a658ff1 100644
--- a/gcc/testsuite/c-c++-common/fold-bitand-4.c
+++ b/gcc/testsuite/c-c++-common/fold-bitand-4.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c } } } */
 /* { dg-options "-fdump-tree-original" } */
 /* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
index 26c9293..a5e3c1f1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
@@ -18,7 +18,7 @@ public:
   {
     /* I am surprised this is considered a constexpr */
     return *((Inner *)4);
-  } // { dg-error "reinterpret_cast" "" { xfail *-*-* } }
+  } // { dg-error "reinterpret_cast" "" }
 };
 
 B B::instance;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53792.C b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
new file mode 100644
index 0000000..deb5c1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
@@ -0,0 +1,29 @@
+// PR c++/53792
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-final { scan-tree-dump "return 0" "optimized" } }
+
+struct entry {
+  char const* label;
+  int         value;
+};
+
+constexpr bool same(char const *x, char const *y) {
+  return !*x && !*y ? true
+    : /* default */    (*x == *y && same(x+1, y+1));
+}
+
+constexpr int keyToValue(char const *label, entry const *entries) {
+  return !entries->label ? entries->value
+       : same(entries->label, label) ? entries->value
+       : /*default*/                   keyToValue(label, entries+1);
+}
+
+constexpr entry foo[] = {{"Foo", 0}, {"Bar", 1}, {"FooBar", 2}, {0, -1}};
+
+int
+bar()
+{
+  int result = keyToValue("Foo", foo);
+  return result;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
new file mode 100644
index 0000000..afa7edb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+constexpr int f(void *) { return 0; }
+constexpr int f(...) { return 1; }
+constexpr int g1() { return f(0); }
+constexpr int g2(int n) { return f(n); }
+constexpr int g3(int n) { return f(n*0); }
+
+int main()
+{
+    static_assert(g1() == 0, "g1 failed");
+    static_assert(g2(0) == 1, "g2 failed");
+    static_assert(g3(0) == 1, "g3 failed");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
new file mode 100644
index 0000000..e340de4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MIN; }
+
+int main()
+{
+  return -f(); // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
new file mode 100644
index 0000000..6b5dff8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MAX; }
+
+int main()
+{
+  return f() + 2; // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
new file mode 100644
index 0000000..39b3557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" }  */
+
+extern int fl;
+
+#define MAK (fl < 0 ? 1 : (fl ? -1 : 0))
+
+int foo (int sz)
+{
+  if (MAK) return 1;
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
new file mode 100644
index 0000000..fa91a4f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" }  */
+
+extern int fl;
+extern int arr[];
+
+#define MAK (fl < 0 ? 1 : (fl ? 2 : 0))
+
+int foo (int sz)
+{
+  unsigned i;
+  int r = 0;
+  for (i = 0; i < MAK; i++)
+    r += arr[i];
+  return r;
+}
+
diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
index c8ec07d..0c5df6d 100644
--- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C
+++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
@@ -5,8 +5,8 @@
 
 template<typename T>
 void type_alignment(const T&) {
-  struct { char c; T t; } s;
-  SA((char*)&s.t - (char*)&s.c == 1);
+  struct S { char c; T t; } s;
+  SA(__builtin_offsetof (S,t) - __builtin_offsetof (S,c) == 1);
 }
 
 template <class T> struct A { char c; T t; };
@@ -17,7 +17,8 @@ int main() {
 
   A<aligned> a;			// { dg-warning "ignoring attributes" }
 
-  SA((char*)&a.t - (char*)&a.c == 1);
+  SA(  __builtin_offsetof (__typeof(a),t)
+     - __builtin_offsetof (__typeof(a),c) == 1);
 
   aligned z;
   type_alignment(z);		// { dg-warning "ignoring attributes" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/ext/offsetof1.C b/gcc/testsuite/g++.dg/ext/offsetof1.C
index 1468c0a..23f3537 100644
--- a/gcc/testsuite/g++.dg/ext/offsetof1.C
+++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
@@ -1,6 +1,7 @@
 // PR c++/27601
 // Origin: Patrik Hägglund  <patrik.hagglund@bredband.net>
 // { dg-do compile }
+// { dg-options "-Wno-pointer-arith" }
 
 struct bar {
   static int foo;
@@ -10,7 +11,7 @@ struct bar {
 int a = __builtin_offsetof(bar, foo);  // { dg-error "static data member" }
 int av = __builtin_offsetof(volatile bar, foo);  // { dg-error "static data member" }
 int b = __builtin_offsetof(bar, baz);  // { dg-error "member function" }
-int b0 = __builtin_offsetof(bar, baz[0]);  // { dg-error "function" }
+int b0 = __builtin_offsetof(bar, baz[0]);  // { dg-error "single identifier nor|member function" }
 int bv0 = __builtin_offsetof(volatile bar, baz[0]);  // { dg-error "function" }
 int c = __builtin_offsetof(bar, ~bar);  // { dg-error "member function" }
 
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
index dbc60b3..e1f31bc 100644
--- a/gcc/testsuite/g++.dg/init/const7.C
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -1,9 +1,9 @@
 // { dg-do compile }
-// { dg-options "-fdump-tree-gimple" }
+// { dg-options "-fdump-tree-gimple -pedantic" }
 
 struct s { int x, y; };
 short offsets[1] = {
-  ((char*) &(((struct s*)16)->y) - (char *)16),
+  ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } }
 };
 
 // This ensures that we get a dump whether or not the bug is present.
diff --git a/gcc/testsuite/g++.dg/init/self1.C b/gcc/testsuite/g++.dg/init/self1.C
index dd37c8e..7620833 100644
--- a/gcc/testsuite/g++.dg/init/self1.C
+++ b/gcc/testsuite/g++.dg/init/self1.C
@@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) {
 
 int main()
 {
-  int* const savepos = sizeof(*savepos) ? 0 : 0;
+  int* const savepos = sizeof(*savepos) ? 0 : 0;  /* { dg-error "invalid conversion" "convert" { target c++11 }  } */
 
   f (sizeof (*savepos));
 
diff --git a/gcc/testsuite/g++.dg/other/error22.C b/gcc/testsuite/g++.dg/other/error22.C
index 225dcae..eba0746 100644
--- a/gcc/testsuite/g++.dg/other/error22.C
+++ b/gcc/testsuite/g++.dg/other/error22.C
@@ -5,5 +5,5 @@ extern "C" double fabs (double);
 
 void foo (double x)
 {
-  fabs (x) ();	// { dg-error "__builtin_abs" }
+  fabs (x) ();	// { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/other/error24.C b/gcc/testsuite/g++.dg/other/error24.C
index 54343c5..e5e6a4f 100644
--- a/gcc/testsuite/g++.dg/other/error24.C
+++ b/gcc/testsuite/g++.dg/other/error24.C
@@ -8,6 +8,6 @@ void
 bar (int i, int j, double k)
 {
   foo (i && j) ();	// { dg-error "\\(\\(?i != 0\\)? \\&\\& \\(?j != 0\\)?\\)" }
-  foo (!i || !j) ();	// { dg-error "\\(\\(?i == 0\\)? \\|\\| \\(?j == 0\\)?\\)" }
-  foo (!i == !j) ();	// { dg-error "\\(\\(?i != 0\\)? \\^ \\(?j == 0\\)?\\)" }
+  foo (!i || !j) ();	// { dg-error "function" }
+  foo (!i == !j) ();	// { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/other/error26.C b/gcc/testsuite/g++.dg/other/error26.C
index fb2c8b7..ffe2728 100644
--- a/gcc/testsuite/g++.dg/other/error26.C
+++ b/gcc/testsuite/g++.dg/other/error26.C
@@ -2,5 +2,5 @@
 
 void foo(__complex__ double x)
 {
-  __builtin_conj(x)(); // { dg-error "~x" }
+  __builtin_conj(x)(); // { dg-error "function" }
 }
diff --git a/gcc/testsuite/g++.dg/parse/array-size2.C b/gcc/testsuite/g++.dg/parse/array-size2.C
index 355ed61..3c83347 100644
--- a/gcc/testsuite/g++.dg/parse/array-size2.C
+++ b/gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
 void
 foo (void)
 {
-  char g[(char *) &((struct S *) 0)->b - (char *) 0];
-  char h[(__SIZE_TYPE__) &((struct S *) 8)->b];
+  char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+  char h[(__SIZE_TYPE__) &((struct S *) 8)->b];	      // { dg-error "constant" "" { xfail *-*-* } }
   bar (g, h);
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
index 946f2e6..8014705 100644
--- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -1,14 +1,10 @@
 /* { dg-do compile } */
 /* { dg-options "-fsanitize=integer-divide-by-zero" } */
 
-/* TODO: We expect an error on the invalid case here, because that
-   must be a constant-expression.  This will be fixed when we have
-   proper delayed folding.  */
-
 void
 foo (int i)
 {
   switch (i)
   case 0 * (1 / 0): /* { dg-warning "division by zero" } */
-    ;  /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */
+    ;  /* { dg-error "is not a constant.expression" "" { target *-*-* } 8 } */
 }
diff --git a/gcc/testsuite/g++.dg/ubsan/shift-1.C b/gcc/testsuite/g++.dg/ubsan/shift-1.C
index 05e049e..493a55c 100644
--- a/gcc/testsuite/g++.dg/ubsan/shift-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/shift-1.C
@@ -8,10 +8,10 @@ foo (int x)
   /* None of the following should pass.  */
   switch (x)
     {
-    case 1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case -1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case 1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case -1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+    case 1 >> -1: /* { dg-error "operand of shift" "" } */
+    case -1 >> -1: /* { dg-error "operand of shift" "" } */
+    case 1 << -1: /* { dg-error "operand of shift" "" } */
+    case -1 << -1: /* { dg-error "operand of shift" "" } */
       return 1;
     }
   return 0;
@@ -23,8 +23,8 @@ bar (int x)
   /* None of the following should pass.  */
   switch (x)
     {
-    case -1 >> 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
-    case 1 << 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+    case -1 >> 200: /* { dg-error "operand of shift" "" } */
+    case 1 << 200: /* { dg-error "operand of shift" "" } */
       return 1;
     }
   return 0;
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
index 7cd76e7..a10e15b 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -126,3 +126,11 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target *-*-* } 56 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 58 } */
+/* { dg-error "is not a constant expression" "const" { target *-*-* } 65 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 65 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
index 73c0e00..c73a28c 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
 /* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
+/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
@@ -65,7 +65,7 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
-      ;
+      ;  /* { dg-error "is not a constant expression" "const" { target *-*-* } 67 }  */
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
       /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 69 } */
       ;
@@ -128,3 +128,9 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 60 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 67 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
index 24b3959..23a2585 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
   /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
@@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
 /* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 61 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
 
 void
@@ -68,7 +68,7 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
-      ;
+      ;  /* { dg-error "is not a constant expression" "const" { target *-*-* } 70 } */
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
       /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
       ;
@@ -131,3 +131,9 @@ h2i (int x)
   ui = INT_MIN;
   ui = x ? INT_MIN : 1U;
 }
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "invalid conversion from" "convert" { target c++11 } 63 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 34 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 70 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 34 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 34 } */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C
index ff1d0669..96691d3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/null3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C
@@ -3,5 +3,5 @@
 void x()
 {
  int* p = 1==0;	// { dg-warning "converting 'false' to pointer" "" { target { ! c++11 } } }
-// { dg-error "cannot convert" "" { target c++11 } 5 } 
+// { dg-error "cannot convert" "" { target { c++11 } } 5 }
 }

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
@ 2015-11-09  9:08   ` Richard Biener
  2015-11-09 19:28     ` Jason Merrill
  2015-11-09  9:24   ` Eric Botcazou
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Richard Biener @ 2015-11-09  9:08 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List, Marek Polacek

On Mon, 9 Nov 2015, Jason Merrill wrote:

> I'm planning to merge the C++ delayed folding branch this week, but I need to
> get approval of the back end changes (the first patch attached).  Most of
> these are the introduction of non-folding variants of convert_to_*, but there
> are a few others.
> 
> One question: The branch changes 'convert' to not fold its result, and it's
> not clear to me whether that's part of the expected behavior of a front end
> 'convert' function or not.

History.  convert is purely frontend (but shared, unfortunately between
all frontends).  I would expect that FEs that do not do delayed folding
expect convert to fold.

> Also, I'm a bit uncertain about merging this at the end of stage 1, since it's
> a large internal change with relatively small user impact; it just improves
> handling of constant expression corner cases.  I'm inclined to go ahead with
> it at this point, but I'm interested in contrary opinions.

I welcome this change as it should allow cleaning up the FE-middle-end
interface a bit more.  It should be possible to remove all
NON_LVALUE_EXPR adding/removal from the middle-end folders.

Looks like the backend patch included frontend parts but as far as I
skimmed it only

diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5e32901..d754a90 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree type,
tree arg1)
       else if (TREE_CODE (arg1) == REAL_CST)
        return fold_convert_const_fixed_from_real (type, arg1);
     }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      if (TREE_CODE (arg1) == VECTOR_CST
+         && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE
(arg1))
+         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
+       {
+         tree r = copy_node (arg1);
+         TREE_TYPE (arg1) = type;
+         return r;
+       }
+    }


looks suspicious.  The issue here is that the vector elements will
have the wrong type after this simple handling.

If you fix that you can as well handle all kind of element type
changes via recursing to fold_convert_const (that includes
float to int / int to float changes).  Not sure if we can even
write a testcase for such conversions with the GCC vector extensions
though.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
  2015-11-09  9:08   ` Richard Biener
@ 2015-11-09  9:24   ` Eric Botcazou
  2015-11-09 14:08     ` Jason Merrill
  2015-11-23  7:44   ` Thomas Schwinge
  2015-11-26  8:50   ` Thomas Schwinge
  3 siblings, 1 reply; 13+ messages in thread
From: Eric Botcazou @ 2015-11-09  9:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Richard Biener, Marek Polacek

> One question: The branch changes 'convert' to not fold its result, and
> it's not clear to me whether that's part of the expected behavior of a
> front end 'convert' function or not.

I don't think that you should change the behavior for front-ends that have an 
internal representation distinct from the GENERIC trees and thus do a global 
translation to GENERIC at the end; e.g. in the Ada compiler we'd rather have 
*more* folding than less during this translation.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  9:24   ` Eric Botcazou
@ 2015-11-09 14:08     ` Jason Merrill
  2015-11-09 22:07       ` Eric Botcazou
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2015-11-09 14:08 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches, Richard Biener, Marek Polacek

On 11/09/2015 04:24 AM, Eric Botcazou wrote:
>> One question: The branch changes 'convert' to not fold its result, and
>> it's not clear to me whether that's part of the expected behavior of a
>> front end 'convert' function or not.
>
> I don't think that you should change the behavior for front-ends that have an
> internal representation distinct from the GENERIC trees and thus do a global
> translation to GENERIC at the end; e.g. in the Ada compiler we'd rather have
> *more* folding than less during this translation.

Right, the change is just to the C++ front end 'convert'.

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  9:08   ` Richard Biener
@ 2015-11-09 19:28     ` Jason Merrill
  2015-11-09 20:55       ` Jason Merrill
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2015-11-09 19:28 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches List, Marek Polacek

On 11/09/2015 04:08 AM, Richard Biener wrote:
> On Mon, 9 Nov 2015, Jason Merrill wrote:
>
>> I'm planning to merge the C++ delayed folding branch this week, but I need to
>> get approval of the back end changes (the first patch attached).  Most of
>> these are the introduction of non-folding variants of convert_to_*, but there
>> are a few others.
>>
>> One question: The branch changes 'convert' to not fold its result, and it's
>> not clear to me whether that's part of the expected behavior of a front end
>> 'convert' function or not.
>
> History.  convert is purely frontend (but shared, unfortunately between
> all frontends).  I would expect that FEs that do not do delayed folding
> expect convert to fold.
>
>> Also, I'm a bit uncertain about merging this at the end of stage 1, since it's
>> a large internal change with relatively small user impact; it just improves
>> handling of constant expression corner cases.  I'm inclined to go ahead with
>> it at this point, but I'm interested in contrary opinions.
>
> I welcome this change as it should allow cleaning up the FE-middle-end
> interface a bit more.  It should be possible to remove all
> NON_LVALUE_EXPR adding/removal from the middle-end folders.
>
> Looks like the backend patch included frontend parts but as far as I
> skimmed it only
>
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 5e32901..d754a90 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree type,
> tree arg1)
>         else if (TREE_CODE (arg1) == REAL_CST)
>          return fold_convert_const_fixed_from_real (type, arg1);
>       }
> +  else if (TREE_CODE (type) == VECTOR_TYPE)
> +    {
> +      if (TREE_CODE (arg1) == VECTOR_CST
> +         && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE
> (arg1))
> +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
> +       {
> +         tree r = copy_node (arg1);
> +         TREE_TYPE (arg1) = type;
> +         return r;
> +       }
> +    }
>
>
> looks suspicious.  The issue here is that the vector elements will
> have the wrong type after this simple handling.

I was aiming to just handle simple cv-qualifier changes; that's why the 
TYPE_MAIN_VARIANT comparison is there.

> If you fix that you can as well handle all kind of element type
> changes via recursing to fold_convert_const (that includes
> float to int / int to float changes).

But I'll try this.

> Not sure if we can even
> write a testcase for such conversions with the GCC vector extensions
> though.

Jason


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09 19:28     ` Jason Merrill
@ 2015-11-09 20:55       ` Jason Merrill
  2015-11-10  9:02         ` Richard Biener
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2015-11-09 20:55 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches List, Marek Polacek

[-- Attachment #1: Type: text/plain, Size: 2633 bytes --]

On 11/09/2015 02:28 PM, Jason Merrill wrote:
> On 11/09/2015 04:08 AM, Richard Biener wrote:
>> On Mon, 9 Nov 2015, Jason Merrill wrote:
>>
>>> I'm planning to merge the C++ delayed folding branch this week, but I
>>> need to
>>> get approval of the back end changes (the first patch attached).
>>> Most of
>>> these are the introduction of non-folding variants of convert_to_*,
>>> but there
>>> are a few others.
>>>
>>> One question: The branch changes 'convert' to not fold its result,
>>> and it's
>>> not clear to me whether that's part of the expected behavior of a
>>> front end
>>> 'convert' function or not.
>>
>> History.  convert is purely frontend (but shared, unfortunately between
>> all frontends).  I would expect that FEs that do not do delayed folding
>> expect convert to fold.
>>
>>> Also, I'm a bit uncertain about merging this at the end of stage 1,
>>> since it's
>>> a large internal change with relatively small user impact; it just
>>> improves
>>> handling of constant expression corner cases.  I'm inclined to go
>>> ahead with
>>> it at this point, but I'm interested in contrary opinions.
>>
>> I welcome this change as it should allow cleaning up the FE-middle-end
>> interface a bit more.  It should be possible to remove all
>> NON_LVALUE_EXPR adding/removal from the middle-end folders.
>>
>> Looks like the backend patch included frontend parts but as far as I
>> skimmed it only
>>
>> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
>> index 5e32901..d754a90 100644
>> --- a/gcc/fold-const.c
>> +++ b/gcc/fold-const.c
>> @@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree
>> type,
>> tree arg1)
>>         else if (TREE_CODE (arg1) == REAL_CST)
>>          return fold_convert_const_fixed_from_real (type, arg1);
>>       }
>> +  else if (TREE_CODE (type) == VECTOR_TYPE)
>> +    {
>> +      if (TREE_CODE (arg1) == VECTOR_CST
>> +         && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE
>> (arg1))
>> +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
>> +       {
>> +         tree r = copy_node (arg1);
>> +         TREE_TYPE (arg1) = type;
>> +         return r;
>> +       }
>> +    }
>>
>>
>> looks suspicious.  The issue here is that the vector elements will
>> have the wrong type after this simple handling.
>
> I was aiming to just handle simple cv-qualifier changes; that's why the
> TYPE_MAIN_VARIANT comparison is there.
>
>> If you fix that you can as well handle all kind of element type
>> changes via recursing to fold_convert_const (that includes
>> float to int / int to float changes).
>
> But I'll try this.

Like so?

Jason


[-- Attachment #2: fold-vec.patch --]
[-- Type: text/x-patch, Size: 986 bytes --]

diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index ae16cfc..d8c7faf 100644
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index f9e5064..927e623 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2095,6 +2095,25 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
       else if (TREE_CODE (arg1) == REAL_CST)
 	return fold_convert_const_fixed_from_real (type, arg1);
     }
+  else if (TREE_CODE (type) == VECTOR_TYPE)
+    {
+      if (TREE_CODE (arg1) == VECTOR_CST
+	  && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
+	{
+	  int len = TYPE_VECTOR_SUBPARTS (type);
+	  tree elttype = TREE_TYPE (type);
+	  tree *v = XALLOCAVEC (tree, len);
+	  for (int i = 0; i < len; ++i)
+	    {
+	      tree elt = VECTOR_CST_ELT (arg1, i);
+	      tree cvt = fold_convert_const (code, elttype, elt);
+	      if (cvt == NULL_TREE)
+		return NULL_TREE;
+	      v[i] = cvt;
+	    }
+	  return build_vector (type, v);
+	}
+    }
   return NULL_TREE;
 }
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09 14:08     ` Jason Merrill
@ 2015-11-09 22:07       ` Eric Botcazou
  0 siblings, 0 replies; 13+ messages in thread
From: Eric Botcazou @ 2015-11-09 22:07 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Richard Biener, Marek Polacek

> Right, the change is just to the C++ front end 'convert'.

OK, thanks for the clarification.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09 20:55       ` Jason Merrill
@ 2015-11-10  9:02         ` Richard Biener
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Biener @ 2015-11-10  9:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List, Marek Polacek

On Mon, 9 Nov 2015, Jason Merrill wrote:

> On 11/09/2015 02:28 PM, Jason Merrill wrote:
> > On 11/09/2015 04:08 AM, Richard Biener wrote:
> > > On Mon, 9 Nov 2015, Jason Merrill wrote:
> > > 
> > > > I'm planning to merge the C++ delayed folding branch this week, but I
> > > > need to
> > > > get approval of the back end changes (the first patch attached).
> > > > Most of
> > > > these are the introduction of non-folding variants of convert_to_*,
> > > > but there
> > > > are a few others.
> > > > 
> > > > One question: The branch changes 'convert' to not fold its result,
> > > > and it's
> > > > not clear to me whether that's part of the expected behavior of a
> > > > front end
> > > > 'convert' function or not.
> > > 
> > > History.  convert is purely frontend (but shared, unfortunately between
> > > all frontends).  I would expect that FEs that do not do delayed folding
> > > expect convert to fold.
> > > 
> > > > Also, I'm a bit uncertain about merging this at the end of stage 1,
> > > > since it's
> > > > a large internal change with relatively small user impact; it just
> > > > improves
> > > > handling of constant expression corner cases.  I'm inclined to go
> > > > ahead with
> > > > it at this point, but I'm interested in contrary opinions.
> > > 
> > > I welcome this change as it should allow cleaning up the FE-middle-end
> > > interface a bit more.  It should be possible to remove all
> > > NON_LVALUE_EXPR adding/removal from the middle-end folders.
> > > 
> > > Looks like the backend patch included frontend parts but as far as I
> > > skimmed it only
> > > 
> > > diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> > > index 5e32901..d754a90 100644
> > > --- a/gcc/fold-const.c
> > > +++ b/gcc/fold-const.c
> > > @@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree
> > > type,
> > > tree arg1)
> > >         else if (TREE_CODE (arg1) == REAL_CST)
> > >          return fold_convert_const_fixed_from_real (type, arg1);
> > >       }
> > > +  else if (TREE_CODE (type) == VECTOR_TYPE)
> > > +    {
> > > +      if (TREE_CODE (arg1) == VECTOR_CST
> > > +         && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE
> > > (arg1))
> > > +         && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
> > > +       {
> > > +         tree r = copy_node (arg1);
> > > +         TREE_TYPE (arg1) = type;
> > > +         return r;
> > > +       }
> > > +    }
> > > 
> > > 
> > > looks suspicious.  The issue here is that the vector elements will
> > > have the wrong type after this simple handling.
> > 
> > I was aiming to just handle simple cv-qualifier changes; that's why the
> > TYPE_MAIN_VARIANT comparison is there.
> > 
> > > If you fix that you can as well handle all kind of element type
> > > changes via recursing to fold_convert_const (that includes
> > > float to int / int to float changes).
> > 
> > But I'll try this.
> 
> Like so?

Yes.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* teach delay folding in c++ about OACC_LOOPs
@ 2015-11-18 15:14 Cesar Philippidis
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
  2015-11-18 16:27 ` teach delay folding in c++ about OACC_LOOPs Nathan Sidwell
  0 siblings, 2 replies; 13+ messages in thread
From: Cesar Philippidis @ 2015-11-18 15:14 UTC (permalink / raw)
  To: gcc-patches, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 342 bytes --]

Jason,

Your recent delay folding patch broke libgomp.oacc-c++/loop-auto-1.c. It
looks like you forgot to handle OACC_LOOP in cp_fold_r. You probably
didn't notice this because Nathan committed his auto acc loop patch just
before you applied your patch. I'm not sure why only that test is
affected though.

Is this patch ok for trunk?

Cesar

[-- Attachment #2: cxx-folding.diff --]
[-- Type: text/x-patch, Size: 654 bytes --]

2015-11-17  Cesar Philippidis  <cesar@codesourcery.com>

	gcc/cp/
	* cp-gimplify.c (cp_fold_r): Add support for OACC_LOOP.

diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 8fe9e13..99d0cfb 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -933,7 +933,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
 
   code = TREE_CODE (stmt);
   if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
-      || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
+      || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD
+      || code == OACC_LOOP)
     {
       tree x;
       int i, n;

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: teach delay folding in c++ about OACC_LOOPs
  2015-11-18 15:14 teach delay folding in c++ about OACC_LOOPs Cesar Philippidis
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
@ 2015-11-18 16:27 ` Nathan Sidwell
  1 sibling, 0 replies; 13+ messages in thread
From: Nathan Sidwell @ 2015-11-18 16:27 UTC (permalink / raw)
  To: Cesar Philippidis, gcc-patches, Jason Merrill

On 11/18/15 10:14, Cesar Philippidis wrote:
> Jason,
>
> Your recent delay folding patch broke libgomp.oacc-c++/loop-auto-1.c. It
> looks like you forgot to handle OACC_LOOP in cp_fold_r. You probably
> didn't notice this because Nathan committed his auto acc loop patch just
> before you applied your patch. I'm not sure why only that test is
> affected though.
>
> Is this patch ok for trunk?

Hey, once again you've saved me an investigation :)

I'd say this counts as obvious, so go ahead and commit.

nathan

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
  2015-11-09  9:08   ` Richard Biener
  2015-11-09  9:24   ` Eric Botcazou
@ 2015-11-23  7:44   ` Thomas Schwinge
  2015-11-25 22:14     ` Jason Merrill
  2015-11-26  8:50   ` Thomas Schwinge
  3 siblings, 1 reply; 13+ messages in thread
From: Thomas Schwinge @ 2015-11-23  7:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List, Marek Polacek, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]

Hi Jason!

On Mon, 9 Nov 2015 01:30:34 -0500, Jason Merrill <jason@redhat.com> wrote:
> I'm planning to merge the C++ delayed folding branch this week [...]

Would be nice to get rid of the two following UNRESOLVEDs:

> --- a/gcc/testsuite/g++.dg/init/self1.C
> +++ b/gcc/testsuite/g++.dg/init/self1.C
> @@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) {
>  
>  int main()
>  {
> -  int* const savepos = sizeof(*savepos) ? 0 : 0;
> +  int* const savepos = sizeof(*savepos) ? 0 : 0;  /* { dg-error "invalid conversion" "convert" { target c++11 }  } */
>  
>    f (sizeof (*savepos));

    PASS: g++.dg/init/self1.C  -std=c++98 (test for excess errors)
    PASS: g++.dg/init/self1.C  -std=c++98 execution test
    {+PASS: g++.dg/init/self1.C  -std=c++11 convert (test for errors, line 13)+}
    PASS: g++.dg/init/self1.C  -std=c++11 (test for excess errors)
    [-PASS:-]{+UNRESOLVED:+} g++.dg/init/self1.C  -std=c++11 [-execution test-]{+compilation failed to produce executable+}
    {+PASS: g++.dg/init/self1.C  -std=c++14 convert (test for errors, line 13)+}
    PASS: g++.dg/init/self1.C  -std=c++14 (test for excess errors)
    [-PASS:-]{+UNRESOLVED:+} g++.dg/init/self1.C  -std=c++14 [-execution test-]{+compilation failed to produce executable+}


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-23  7:44   ` Thomas Schwinge
@ 2015-11-25 22:14     ` Jason Merrill
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Merrill @ 2015-11-25 22:14 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches List, Marek Polacek, Richard Biener

On 11/23/2015 02:23 AM, Thomas Schwinge wrote:
> Would be nice to get rid of the two following UNRESOLVEDs:
>
>      {+PASS: g++.dg/init/self1.C  -std=c++11 convert (test for errors, line 13)+}
>      [-PASS:-]{+UNRESOLVED:+} g++.dg/init/self1.C  -std=c++11 [-execution test-]{+compilation failed to produce executable+}

Done, thanks.

Jason


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: RFC: C++ delayed folding merge
  2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
                     ` (2 preceding siblings ...)
  2015-11-23  7:44   ` Thomas Schwinge
@ 2015-11-26  8:50   ` Thomas Schwinge
  3 siblings, 0 replies; 13+ messages in thread
From: Thomas Schwinge @ 2015-11-26  8:50 UTC (permalink / raw)
  To: Jason Merrill, Richard Biener, Jakub Jelinek
  Cc: gcc-patches List, Marek Polacek, Cesar Philippidis

[-- Attachment #1: Type: text/plain, Size: 3043 bytes --]

Hi!

On Mon, 9 Nov 2015 01:30:34 -0500, Jason Merrill <jason@redhat.com> wrote:
> I'm planning to merge the C++ delayed folding branch this week [...]

In r230554,
<http://news.gmane.org/find-root.php?message_id=%3C564C95C7.8090803%40codesourcery.com%3E>,
Cesar already fixed up cp_fold_r to also care for OACC_LOOP, but another
thing I just wondered about is whether this function also needs to do
something for operand 6 (OMP_FOR_ORIG_DECLS) of OMP_FOR and its variants?
If not, would it make sense to note that in a source code comment, given
that any other operand is being handled?

> --- a/gcc/cp/cp-gimplify.c
> +++ b/gcc/cp/cp-gimplify.c

> +/* Perform any pre-gimplification folding of C++ front end trees to
> +   GENERIC.
> +   Note:  The folding of none-omp cases is something to move into
> +     the middle-end.  As for now we have most foldings only on GENERIC
> +     in fold-const, we need to perform this before transformation to
> +     GIMPLE-form.  */
> +
> +static tree
> +cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
> +{
> +  tree stmt;
> +  struct cp_genericize_data *wtd = (struct cp_genericize_data *) data;
> +  enum tree_code code;
> +
> +  *stmt_p = stmt = cp_fold (*stmt_p, wtd->fold_hash);
> +
> +  code = TREE_CODE (stmt);
> +  if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
> +      || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
> +    {
> +      tree x;
> +      int i, n;
> +
> +      cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
> +      cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
> +      cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL);
> +      x = OMP_FOR_COND (stmt);
> +      if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison)
> +	{
> +	  cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL);
> +	  cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL);
> +	} 
> +      else if (x && TREE_CODE (x) == TREE_VEC)
> +	{
> +	  n = TREE_VEC_LENGTH (x);
> +	  for (i = 0; i < n; i++)
> +	    {
> +	      tree o = TREE_VEC_ELT (x, i);
> +	      if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison)
> +		cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
> +	    }
> +	}
> +      x = OMP_FOR_INCR (stmt);
> +      if (x && TREE_CODE (x) == TREE_VEC)
> +	{
> +	  n = TREE_VEC_LENGTH (x);
> +	  for (i = 0; i < n; i++)
> +	    {
> +	      tree o = TREE_VEC_ELT (x, i);
> +	      if (o && TREE_CODE (o) == MODIFY_EXPR)
> +		o = TREE_OPERAND (o, 1);
> +	      if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR
> +			|| TREE_CODE (o) == POINTER_PLUS_EXPR))
> +		{
> +		  cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL);
> +		  cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
> +		}
> +	    }
> +	}
> +      cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL);
> +      *walk_subtrees = 0;
> +    }
> +
> +  return NULL;
> +}


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2015-11-26  8:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-18 15:14 teach delay folding in c++ about OACC_LOOPs Cesar Philippidis
2015-11-09  6:31 ` RFC: C++ delayed folding merge Jason Merrill
2015-11-09  9:08   ` Richard Biener
2015-11-09 19:28     ` Jason Merrill
2015-11-09 20:55       ` Jason Merrill
2015-11-10  9:02         ` Richard Biener
2015-11-09  9:24   ` Eric Botcazou
2015-11-09 14:08     ` Jason Merrill
2015-11-09 22:07       ` Eric Botcazou
2015-11-23  7:44   ` Thomas Schwinge
2015-11-25 22:14     ` Jason Merrill
2015-11-26  8:50   ` Thomas Schwinge
2015-11-18 16:27 ` teach delay folding in c++ about OACC_LOOPs Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).