On 12/02/2015 12:50 PM, Joseph Myers wrote:
On Wed, 2 Dec 2015, Jason Merrill wrote:

As richi pointed out in another thread, calling fold in warn_tautological_cmp
is problematic because fold expects operands of its argument to have already
been folded; we really need to call *_fully_fold.

The first patch moves c_fully_fold into the C front end, and defines it for
C++ as well.

The new file needs copyright and license notices.

So it does, thanks.

The second patch defines fold_for_warn to call c_fully_fold and uses it in
places in the warn_* functions that want to know if the operand has a constant
value.

Joseph, are these changes OK for C?  The extra folding isn't currently
necessary for C, should fold_for_warn check c_dialect_cxx()?

I think it should check that, yes.

Done.

Are these OK?

Jason

commit 4facfe1ac9fe192fbfc0ac57868652af2ca2be16
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Nov 26 07:45:03 2015 -0500

    	Define c_fully_fold separately for C and C++.
    
    gcc/c-family/
    	* c-common.c (c_disable_warnings, c_enable_warnings, c_fully_fold)
    	(c_fully_fold_internal, decl_constant_value_for_optimization):
    	Move to c/c-fold.c.
    	* c-common.h: Don't declare decl_constant_value_for_optimization.
    gcc/c/
    	* c-fold.c (c_disable_warnings, c_enable_warnings, c_fully_fold)
    	(c_fully_fold_internal, decl_constant_value_for_optimization):
    	Move from c-common.c.
    	* c-tree.h: Declare decl_constant_value_for_optimization.
    	* Make-lang.in (C_AND_OBJC_OBJS): Add c-fold.o.
    gcc/cp/
    	* cp-gimplify.c (c_fully_fold): Define.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 7a9e3b9..40f86e3 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -299,7 +299,6 @@ const struct fname_var_t fname_vars[] =
 /* Global visibility options.  */
 struct visibility_flags visibility_options;
 
-static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool);
 static tree check_case_value (location_t, tree);
 static bool check_case_bounds (location_t, tree, tree, tree *, tree *,
 			       bool *);
@@ -1095,582 +1094,6 @@ fix_string_type (tree value)
   return value;
 }
 
-/* If DISABLE is true, stop issuing warnings.  This is used when
-   parsing code that we know will not be executed.  This function may
-   be called multiple times, and works as a stack.  */
-
-static void
-c_disable_warnings (bool disable)
-{
-  if (disable)
-    {
-      ++c_inhibit_evaluation_warnings;
-      fold_defer_overflow_warnings ();
-    }
-}
-
-/* If ENABLE is true, reenable issuing warnings.  */
-
-static void
-c_enable_warnings (bool enable)
-{
-  if (enable)
-    {
-      --c_inhibit_evaluation_warnings;
-      fold_undefer_and_ignore_overflow_warnings ();
-    }
-}
-
-/* Fully fold EXPR, an expression that was not folded (beyond integer
-   constant expressions and null pointer constants) when being built
-   up.  If IN_INIT, this is in a static initializer and certain
-   changes are made to the folding done.  Clear *MAYBE_CONST if
-   MAYBE_CONST is not NULL and EXPR is definitely not a constant
-   expression because it contains an evaluated operator (in C99) or an
-   operator outside of sizeof returning an integer constant (in C90)
-   not permitted in constant expressions, or because it contains an
-   evaluated arithmetic overflow.  (*MAYBE_CONST should typically be
-   set to true by callers before calling this function.)  Return the
-   folded expression.  Function arguments have already been folded
-   before calling this function, as have the contents of SAVE_EXPR,
-   TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and
-   C_MAYBE_CONST_EXPR.  */
-
-tree
-c_fully_fold (tree expr, bool in_init, bool *maybe_const)
-{
-  tree ret;
-  tree eptype = NULL_TREE;
-  bool dummy = true;
-  bool maybe_const_itself = true;
-  location_t loc = EXPR_LOCATION (expr);
-
-  /* This function is not relevant to C++ because C++ folds while
-     parsing, and may need changes to be correct for C++ when C++
-     stops folding while parsing.  */
-  if (c_dialect_cxx ())
-    gcc_unreachable ();
-
-  if (!maybe_const)
-    maybe_const = &dummy;
-  if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
-    {
-      eptype = TREE_TYPE (expr);
-      expr = TREE_OPERAND (expr, 0);
-    }
-  ret = c_fully_fold_internal (expr, in_init, maybe_const,
-			       &maybe_const_itself, false);
-  if (eptype)
-    ret = fold_convert_loc (loc, eptype, ret);
-  *maybe_const &= maybe_const_itself;
-  return ret;
-}
-
-/* Internal helper for c_fully_fold.  EXPR and IN_INIT are as for
-   c_fully_fold.  *MAYBE_CONST_OPERANDS is cleared because of operands
-   not permitted, while *MAYBE_CONST_ITSELF is cleared because of
-   arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from
-   both evaluated and unevaluated subexpressions while
-   *MAYBE_CONST_ITSELF is carried from only evaluated
-   subexpressions).  FOR_INT_CONST indicates if EXPR is an expression
-   with integer constant operands, and if any of the operands doesn't
-   get folded to an integer constant, don't fold the expression itself.  */
-
-static tree
-c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
-		       bool *maybe_const_itself, bool for_int_const)
-{
-  tree ret = expr;
-  enum tree_code code = TREE_CODE (expr);
-  enum tree_code_class kind = TREE_CODE_CLASS (code);
-  location_t loc = EXPR_LOCATION (expr);
-  tree op0, op1, op2, op3;
-  tree orig_op0, orig_op1, orig_op2;
-  bool op0_const = true, op1_const = true, op2_const = true;
-  bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
-  bool nowarning = TREE_NO_WARNING (expr);
-  bool unused_p;
-  source_range old_range;
-
-  /* This function is not relevant to C++ because C++ folds while
-     parsing, and may need changes to be correct for C++ when C++
-     stops folding while parsing.  */
-  if (c_dialect_cxx ())
-    gcc_unreachable ();
-
-  /* Constants, declarations, statements, errors, SAVE_EXPRs and
-     anything else not counted as an expression cannot usefully be
-     folded further at this point.  */
-  if (!IS_EXPR_CODE_CLASS (kind)
-      || kind == tcc_statement
-      || code == SAVE_EXPR)
-    return expr;
-
-  if (IS_EXPR_CODE_CLASS (kind))
-    old_range = EXPR_LOCATION_RANGE (expr);
-
-  /* Operands of variable-length expressions (function calls) have
-     already been folded, as have __builtin_* function calls, and such
-     expressions cannot occur in constant expressions.  */
-  if (kind == tcc_vl_exp)
-    {
-      *maybe_const_operands = false;
-      ret = fold (expr);
-      goto out;
-    }
-
-  if (code == C_MAYBE_CONST_EXPR)
-    {
-      tree pre = C_MAYBE_CONST_EXPR_PRE (expr);
-      tree inner = C_MAYBE_CONST_EXPR_EXPR (expr);
-      if (C_MAYBE_CONST_EXPR_NON_CONST (expr))
-	*maybe_const_operands = false;
-      if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr))
-	{
-	  *maybe_const_itself = false;
-	  inner = c_fully_fold_internal (inner, in_init, maybe_const_operands,
-					 maybe_const_itself, true);
-	}
-      if (pre && !in_init)
-	ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner);
-      else
-	ret = inner;
-      goto out;
-    }
-
-  /* Assignment, increment, decrement, function call and comma
-     operators, and statement expressions, cannot occur in constant
-     expressions if evaluated / outside of sizeof.  (Function calls
-     were handled above, though VA_ARG_EXPR is treated like a function
-     call here, and statement expressions are handled through
-     C_MAYBE_CONST_EXPR to avoid folding inside them.)  */
-  switch (code)
-    {
-    case MODIFY_EXPR:
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case COMPOUND_EXPR:
-      *maybe_const_operands = false;
-      break;
-
-    case VA_ARG_EXPR:
-    case TARGET_EXPR:
-    case BIND_EXPR:
-    case OBJ_TYPE_REF:
-      *maybe_const_operands = false;
-      ret = fold (expr);
-      goto out;
-
-    default:
-      break;
-    }
-
-  /* Fold individual tree codes as appropriate.  */
-  switch (code)
-    {
-    case COMPOUND_LITERAL_EXPR:
-      /* Any non-constancy will have been marked in a containing
-	 C_MAYBE_CONST_EXPR; there is no more folding to do here.  */
-      goto out;
-
-    case COMPONENT_REF:
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      op1 = TREE_OPERAND (expr, 1);
-      op2 = TREE_OPERAND (expr, 2);
-      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-				   maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op0);
-      if (op0 != orig_op0)
-	ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
-      if (ret != expr)
-	{
-	  TREE_READONLY (ret) = TREE_READONLY (expr);
-	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
-	}
-      goto out;
-
-    case ARRAY_REF:
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      orig_op1 = op1 = TREE_OPERAND (expr, 1);
-      op2 = TREE_OPERAND (expr, 2);
-      op3 = TREE_OPERAND (expr, 3);
-      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-				   maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op0);
-      op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
-				   maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op1);
-      op1 = decl_constant_value_for_optimization (op1);
-      if (op0 != orig_op0 || op1 != orig_op1)
-	ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3);
-      if (ret != expr)
-	{
-	  TREE_READONLY (ret) = TREE_READONLY (expr);
-	  TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
-	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
-	}
-      ret = fold (ret);
-      goto out;
-
-    case COMPOUND_EXPR:
-    case MODIFY_EXPR:
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case POINTER_PLUS_EXPR:
-    case TRUNC_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case TRUNC_MOD_EXPR:
-    case RDIV_EXPR:
-    case EXACT_DIV_EXPR:
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-    case BIT_AND_EXPR:
-    case LT_EXPR:
-    case LE_EXPR:
-    case GT_EXPR:
-    case GE_EXPR:
-    case EQ_EXPR:
-    case NE_EXPR:
-    case COMPLEX_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-    case UNLT_EXPR:
-    case UNLE_EXPR:
-    case UNGT_EXPR:
-    case UNGE_EXPR:
-    case UNEQ_EXPR:
-      /* Binary operations evaluating both arguments (increment and
-	 decrement are binary internally in GCC).  */
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      orig_op1 = op1 = TREE_OPERAND (expr, 1);
-      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-				   maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op0);
-      if (code != MODIFY_EXPR
-	  && code != PREDECREMENT_EXPR
-	  && code != PREINCREMENT_EXPR
-	  && code != POSTDECREMENT_EXPR
-	  && code != POSTINCREMENT_EXPR)
-	op0 = decl_constant_value_for_optimization (op0);
-      /* The RHS of a MODIFY_EXPR was fully folded when building that
-	 expression for the sake of conversion warnings.  */
-      if (code != MODIFY_EXPR)
-	op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
-				     maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op1);
-      op1 = decl_constant_value_for_optimization (op1);
-
-      if (for_int_const && (TREE_CODE (op0) != INTEGER_CST
-			    || TREE_CODE (op1) != INTEGER_CST))
-	goto out;
-
-      if (op0 != orig_op0 || op1 != orig_op1 || in_init)
-	ret = in_init
-	  ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
-	  : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
-      else
-	ret = fold (expr);
-      if (TREE_OVERFLOW_P (ret)
-	  && !TREE_OVERFLOW_P (op0)
-	  && !TREE_OVERFLOW_P (op1))
-	overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret);
-      if (code == LSHIFT_EXPR
-	  && TREE_CODE (orig_op0) != INTEGER_CST
-	  && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
-	  && TREE_CODE (op0) == INTEGER_CST
-	  && c_inhibit_evaluation_warnings == 0
-	  && tree_int_cst_sgn (op0) < 0)
-	warning_at (loc, OPT_Wshift_negative_value,
-		    "left shift of negative value");
-      if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
-	  && TREE_CODE (orig_op1) != INTEGER_CST
-	  && TREE_CODE (op1) == INTEGER_CST
-	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
-	      || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
-	  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
-	  && c_inhibit_evaluation_warnings == 0)
-	{
-	  if (tree_int_cst_sgn (op1) < 0)
-	    warning_at (loc, OPT_Wshift_count_negative,
-			(code == LSHIFT_EXPR
-			 ? G_("left shift count is negative")
-			 : G_("right shift count is negative")));
-	  else if (compare_tree_int (op1,
-				     TYPE_PRECISION (TREE_TYPE (orig_op0)))
-		   >= 0)
-	    warning_at (loc, OPT_Wshift_count_overflow,
-			(code == LSHIFT_EXPR
-			 ? G_("left shift count >= width of type")
-			 : G_("right shift count >= width of type")));
-	}
-      if (code == LSHIFT_EXPR
-	  /* If either OP0 has been folded to INTEGER_CST...  */
-	  && ((TREE_CODE (orig_op0) != INTEGER_CST
-	       && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
-	       && TREE_CODE (op0) == INTEGER_CST)
-	      /* ...or if OP1 has been folded to INTEGER_CST...  */
-	      || (TREE_CODE (orig_op1) != INTEGER_CST
-		  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
-		  && TREE_CODE (op1) == INTEGER_CST))
-	  && c_inhibit_evaluation_warnings == 0)
-	/* ...then maybe we can detect an overflow.  */
-	maybe_warn_shift_overflow (loc, op0, op1);
-      if ((code == TRUNC_DIV_EXPR
-	   || code == CEIL_DIV_EXPR
-	   || code == FLOOR_DIV_EXPR
-	   || code == EXACT_DIV_EXPR
-	   || code == TRUNC_MOD_EXPR)
-	  && TREE_CODE (orig_op1) != INTEGER_CST
-	  && TREE_CODE (op1) == INTEGER_CST
-	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
-	      || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
-	  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE)
-	warn_for_div_by_zero (loc, op1);
-      goto out;
-
-    case INDIRECT_REF:
-    case FIX_TRUNC_EXPR:
-    case FLOAT_EXPR:
-    CASE_CONVERT:
-    case ADDR_SPACE_CONVERT_EXPR:
-    case VIEW_CONVERT_EXPR:
-    case NON_LVALUE_EXPR:
-    case NEGATE_EXPR:
-    case BIT_NOT_EXPR:
-    case TRUTH_NOT_EXPR:
-    case ADDR_EXPR:
-    case CONJ_EXPR:
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-      /* Unary operations.  */
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-				   maybe_const_itself, for_int_const);
-      STRIP_TYPE_NOPS (op0);
-      if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
-	op0 = decl_constant_value_for_optimization (op0);
-
-      if (for_int_const && TREE_CODE (op0) != INTEGER_CST)
-	goto out;
-
-      /* ??? Cope with user tricks that amount to offsetof.  The middle-end is
-	 not prepared to deal with them if they occur in initializers.  */
-      if (op0 != orig_op0
-	  && code == ADDR_EXPR
-	  && (op1 = get_base_address (op0)) != NULL_TREE
-	  && INDIRECT_REF_P (op1)
-	  && TREE_CONSTANT (TREE_OPERAND (op1, 0)))
-	ret = fold_convert_loc (loc, TREE_TYPE (expr), fold_offsetof_1 (op0));
-      else if (op0 != orig_op0 || in_init)
-	ret = in_init
-	  ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0)
-	  : fold_build1_loc (loc, code, TREE_TYPE (expr), op0);
-      else
-	ret = fold (expr);
-      if (code == INDIRECT_REF
-	  && ret != expr
-	  && INDIRECT_REF_P (ret))
-	{
-	  TREE_READONLY (ret) = TREE_READONLY (expr);
-	  TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
-	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
-	}
-      switch (code)
-	{
-	case FIX_TRUNC_EXPR:
-	case FLOAT_EXPR:
-	CASE_CONVERT:
-	  /* Don't warn about explicit conversions.  We will already
-	     have warned about suspect implicit conversions.  */
-	  break;
-
-	default:
-	  if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0))
-	    overflow_warning (EXPR_LOCATION (expr), ret);
-	  break;
-	}
-      goto out;
-
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      /* Binary operations not necessarily evaluating both
-	 arguments.  */
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      orig_op1 = op1 = TREE_OPERAND (expr, 1);
-      op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self,
-				   for_int_const);
-      STRIP_TYPE_NOPS (op0);
-
-      unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
-			  ? truthvalue_false_node
-			  : truthvalue_true_node));
-      c_disable_warnings (unused_p);
-      op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self,
-				   for_int_const);
-      STRIP_TYPE_NOPS (op1);
-      c_enable_warnings (unused_p);
-
-      if (for_int_const
-	  && (TREE_CODE (op0) != INTEGER_CST
-	      /* Require OP1 be an INTEGER_CST only if it's evaluated.  */
-	      || (!unused_p && TREE_CODE (op1) != INTEGER_CST)))
-	goto out;
-
-      if (op0 != orig_op0 || op1 != orig_op1 || in_init)
-	ret = in_init
-	  ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
-	  : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
-      else
-	ret = fold (expr);
-      *maybe_const_operands &= op0_const;
-      *maybe_const_itself &= op0_const_self;
-      if (!(flag_isoc99
-	    && op0_const
-	    && op0_const_self
-	    && (code == TRUTH_ANDIF_EXPR
-		? op0 == truthvalue_false_node
-		: op0 == truthvalue_true_node)))
-	*maybe_const_operands &= op1_const;
-      if (!(op0_const
-	    && op0_const_self
-	    && (code == TRUTH_ANDIF_EXPR
-		? op0 == truthvalue_false_node
-		: op0 == truthvalue_true_node)))
-	*maybe_const_itself &= op1_const_self;
-      goto out;
-
-    case COND_EXPR:
-      orig_op0 = op0 = TREE_OPERAND (expr, 0);
-      orig_op1 = op1 = TREE_OPERAND (expr, 1);
-      orig_op2 = op2 = TREE_OPERAND (expr, 2);
-      op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self,
-				   for_int_const);
-
-      STRIP_TYPE_NOPS (op0);
-      c_disable_warnings (op0 == truthvalue_false_node);
-      op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self,
-				   for_int_const);
-      STRIP_TYPE_NOPS (op1);
-      c_enable_warnings (op0 == truthvalue_false_node);
-
-      c_disable_warnings (op0 == truthvalue_true_node);
-      op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self,
-				   for_int_const);
-      STRIP_TYPE_NOPS (op2);
-      c_enable_warnings (op0 == truthvalue_true_node);
-
-      if (for_int_const
-	  && (TREE_CODE (op0) != INTEGER_CST
-	      /* Only the evaluated operand must be an INTEGER_CST.  */
-	      || (op0 == truthvalue_true_node
-		  ? TREE_CODE (op1) != INTEGER_CST
-		  : TREE_CODE (op2) != INTEGER_CST)))
-	goto out;
-
-      if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
-	ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2);
-      else
-	ret = fold (expr);
-      *maybe_const_operands &= op0_const;
-      *maybe_const_itself &= op0_const_self;
-      if (!(flag_isoc99
-	    && op0_const
-	    && op0_const_self
-	    && op0 == truthvalue_false_node))
-	*maybe_const_operands &= op1_const;
-      if (!(op0_const
-	    && op0_const_self
-	    && op0 == truthvalue_false_node))
-	*maybe_const_itself &= op1_const_self;
-      if (!(flag_isoc99
-	    && op0_const
-	    && op0_const_self
-	    && op0 == truthvalue_true_node))
-	*maybe_const_operands &= op2_const;
-      if (!(op0_const
-	    && op0_const_self
-	    && op0 == truthvalue_true_node))
-	*maybe_const_itself &= op2_const_self;
-      goto out;
-
-    case EXCESS_PRECISION_EXPR:
-      /* Each case where an operand with excess precision may be
-	 encountered must remove the EXCESS_PRECISION_EXPR around
-	 inner operands and possibly put one around the whole
-	 expression or possibly convert to the semantic type (which
-	 c_fully_fold does); we cannot tell at this stage which is
-	 appropriate in any particular case.  */
-      gcc_unreachable ();
-
-    default:
-      /* Various codes may appear through folding built-in functions
-	 and their arguments.  */
-      goto out;
-    }
-
- out:
-  /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks
-     have been done by this point, so remove them again.  */
-  nowarning |= TREE_NO_WARNING (ret);
-  STRIP_TYPE_NOPS (ret);
-  if (nowarning && !TREE_NO_WARNING (ret))
-    {
-      if (!CAN_HAVE_LOCATION_P (ret))
-	ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
-      TREE_NO_WARNING (ret) = 1;
-    }
-  if (ret != expr)
-    {
-      protected_set_expr_location (ret, loc);
-      if (IS_EXPR_CODE_CLASS (kind))
-	set_source_range (ret, old_range.m_start, old_range.m_finish);
-    }
-  return ret;
-}
-
-/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type,
-   return EXP.  Otherwise, return either EXP or its known constant
-   value (if it has one), but return EXP if EXP has mode BLKmode.  ???
-   Is the BLKmode test appropriate?  */
-
-tree
-decl_constant_value_for_optimization (tree exp)
-{
-  tree ret;
-
-  /* This function is only used by C, for c_fully_fold and other
-     optimization, and may not be correct for C++.  */
-  if (c_dialect_cxx ())
-    gcc_unreachable ();
-
-  if (!optimize
-      || !VAR_P (exp)
-      || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
-      || DECL_MODE (exp) == BLKmode)
-    return exp;
-
-  ret = decl_constant_value (exp);
-  /* Avoid unwanted tree sharing between the initializer and current
-     function's body where the tree can be modified e.g. by the
-     gimplifier.  */
-  if (ret != exp && TREE_STATIC (exp))
-    ret = unshare_expr (ret);
-  return ret;
-}
-
 /* Print a warning if a constant expression had overflow in folding.
    Invoke this function on every expression that the language
    requires to be a constant expression.
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index bad8d05..c8a3dfe 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -809,7 +809,6 @@ extern enum conversion_safety unsafe_conversion_p (location_t, tree, tree,
 						   bool);
 extern bool decl_with_nonnull_addr_p (const_tree);
 extern tree c_fully_fold (tree, bool, bool *);
-extern tree decl_constant_value_for_optimization (tree);
 extern tree c_wrap_maybe_const (tree, bool);
 extern tree c_save_expr (tree);
 extern tree c_common_truthvalue_conversion (location_t, tree);
diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in
index 85365fd..b1d0e91 100644
--- a/gcc/c/Make-lang.in
+++ b/gcc/c/Make-lang.in
@@ -51,7 +51,7 @@ CFLAGS-c/gccspec.o += $(DRIVER_DEFINES)
 # Language-specific object files for C and Objective C.
 C_AND_OBJC_OBJS = attribs.o c/c-errors.o c/c-decl.o c/c-typeck.o \
   c/c-convert.o c/c-aux-info.o c/c-objc-common.o c/c-parser.o \
-  c/c-array-notation.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
+  c/c-array-notation.o c/c-fold.o $(C_COMMON_OBJS) $(C_TARGET_OBJS)
 
 # Language-specific object files for C.
 C_OBJS = c/c-lang.o c-family/stub-objc.o $(C_AND_OBJC_OBJS)
diff --git a/gcc/c/c-fold.c b/gcc/c/c-fold.c
new file mode 100644
index 0000000..7d5abb9
--- /dev/null
+++ b/gcc/c/c-fold.c
@@ -0,0 +1,589 @@
+/* Support for fully folding sub-trees of an expression for C compiler.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "function.h"
+#include "bitmap.h"
+#include "c-tree.h"
+#include "intl.h"
+#include "gimplify.h"
+
+static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, bool);
+
+/* If DISABLE is true, stop issuing warnings.  This is used when
+   parsing code that we know will not be executed.  This function may
+   be called multiple times, and works as a stack.  */
+
+static void
+c_disable_warnings (bool disable)
+{
+  if (disable)
+    {
+      ++c_inhibit_evaluation_warnings;
+      fold_defer_overflow_warnings ();
+    }
+}
+
+/* If ENABLE is true, reenable issuing warnings.  */
+
+static void
+c_enable_warnings (bool enable)
+{
+  if (enable)
+    {
+      --c_inhibit_evaluation_warnings;
+      fold_undefer_and_ignore_overflow_warnings ();
+    }
+}
+
+/* Fully fold EXPR, an expression that was not folded (beyond integer
+   constant expressions and null pointer constants) when being built
+   up.  If IN_INIT, this is in a static initializer and certain
+   changes are made to the folding done.  Clear *MAYBE_CONST if
+   MAYBE_CONST is not NULL and EXPR is definitely not a constant
+   expression because it contains an evaluated operator (in C99) or an
+   operator outside of sizeof returning an integer constant (in C90)
+   not permitted in constant expressions, or because it contains an
+   evaluated arithmetic overflow.  (*MAYBE_CONST should typically be
+   set to true by callers before calling this function.)  Return the
+   folded expression.  Function arguments have already been folded
+   before calling this function, as have the contents of SAVE_EXPR,
+   TARGET_EXPR, BIND_EXPR, VA_ARG_EXPR, OBJ_TYPE_REF and
+   C_MAYBE_CONST_EXPR.  */
+
+tree
+c_fully_fold (tree expr, bool in_init, bool *maybe_const)
+{
+  tree ret;
+  tree eptype = NULL_TREE;
+  bool dummy = true;
+  bool maybe_const_itself = true;
+  location_t loc = EXPR_LOCATION (expr);
+
+  if (!maybe_const)
+    maybe_const = &dummy;
+  if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+    {
+      eptype = TREE_TYPE (expr);
+      expr = TREE_OPERAND (expr, 0);
+    }
+  ret = c_fully_fold_internal (expr, in_init, maybe_const,
+			       &maybe_const_itself, false);
+  if (eptype)
+    ret = fold_convert_loc (loc, eptype, ret);
+  *maybe_const &= maybe_const_itself;
+  return ret;
+}
+
+/* Internal helper for c_fully_fold.  EXPR and IN_INIT are as for
+   c_fully_fold.  *MAYBE_CONST_OPERANDS is cleared because of operands
+   not permitted, while *MAYBE_CONST_ITSELF is cleared because of
+   arithmetic overflow (for C90, *MAYBE_CONST_OPERANDS is carried from
+   both evaluated and unevaluated subexpressions while
+   *MAYBE_CONST_ITSELF is carried from only evaluated
+   subexpressions).  FOR_INT_CONST indicates if EXPR is an expression
+   with integer constant operands, and if any of the operands doesn't
+   get folded to an integer constant, don't fold the expression itself.  */
+
+static tree
+c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
+		       bool *maybe_const_itself, bool for_int_const)
+{
+  tree ret = expr;
+  enum tree_code code = TREE_CODE (expr);
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+  location_t loc = EXPR_LOCATION (expr);
+  tree op0, op1, op2, op3;
+  tree orig_op0, orig_op1, orig_op2;
+  bool op0_const = true, op1_const = true, op2_const = true;
+  bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
+  bool nowarning = TREE_NO_WARNING (expr);
+  bool unused_p;
+  source_range old_range;
+
+  /* Constants, declarations, statements, errors, SAVE_EXPRs and
+     anything else not counted as an expression cannot usefully be
+     folded further at this point.  */
+  if (!IS_EXPR_CODE_CLASS (kind)
+      || kind == tcc_statement
+      || code == SAVE_EXPR)
+    return expr;
+
+  if (IS_EXPR_CODE_CLASS (kind))
+    old_range = EXPR_LOCATION_RANGE (expr);
+
+  /* Operands of variable-length expressions (function calls) have
+     already been folded, as have __builtin_* function calls, and such
+     expressions cannot occur in constant expressions.  */
+  if (kind == tcc_vl_exp)
+    {
+      *maybe_const_operands = false;
+      ret = fold (expr);
+      goto out;
+    }
+
+  if (code == C_MAYBE_CONST_EXPR)
+    {
+      tree pre = C_MAYBE_CONST_EXPR_PRE (expr);
+      tree inner = C_MAYBE_CONST_EXPR_EXPR (expr);
+      if (C_MAYBE_CONST_EXPR_NON_CONST (expr))
+	*maybe_const_operands = false;
+      if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr))
+	{
+	  *maybe_const_itself = false;
+	  inner = c_fully_fold_internal (inner, in_init, maybe_const_operands,
+					 maybe_const_itself, true);
+	}
+      if (pre && !in_init)
+	ret = build2 (COMPOUND_EXPR, TREE_TYPE (expr), pre, inner);
+      else
+	ret = inner;
+      goto out;
+    }
+
+  /* Assignment, increment, decrement, function call and comma
+     operators, and statement expressions, cannot occur in constant
+     expressions if evaluated / outside of sizeof.  (Function calls
+     were handled above, though VA_ARG_EXPR is treated like a function
+     call here, and statement expressions are handled through
+     C_MAYBE_CONST_EXPR to avoid folding inside them.)  */
+  switch (code)
+    {
+    case MODIFY_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case COMPOUND_EXPR:
+      *maybe_const_operands = false;
+      break;
+
+    case VA_ARG_EXPR:
+    case TARGET_EXPR:
+    case BIND_EXPR:
+    case OBJ_TYPE_REF:
+      *maybe_const_operands = false;
+      ret = fold (expr);
+      goto out;
+
+    default:
+      break;
+    }
+
+  /* Fold individual tree codes as appropriate.  */
+  switch (code)
+    {
+    case COMPOUND_LITERAL_EXPR:
+      /* Any non-constancy will have been marked in a containing
+	 C_MAYBE_CONST_EXPR; there is no more folding to do here.  */
+      goto out;
+
+    case COMPONENT_REF:
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      op1 = TREE_OPERAND (expr, 1);
+      op2 = TREE_OPERAND (expr, 2);
+      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				   maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op0);
+      if (op0 != orig_op0)
+	ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
+      if (ret != expr)
+	{
+	  TREE_READONLY (ret) = TREE_READONLY (expr);
+	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+	}
+      goto out;
+
+    case ARRAY_REF:
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      orig_op1 = op1 = TREE_OPERAND (expr, 1);
+      op2 = TREE_OPERAND (expr, 2);
+      op3 = TREE_OPERAND (expr, 3);
+      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				   maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op0);
+      op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
+				   maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op1);
+      op1 = decl_constant_value_for_optimization (op1);
+      if (op0 != orig_op0 || op1 != orig_op1)
+	ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3);
+      if (ret != expr)
+	{
+	  TREE_READONLY (ret) = TREE_READONLY (expr);
+	  TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
+	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+	}
+      ret = fold (ret);
+      goto out;
+
+    case COMPOUND_EXPR:
+    case MODIFY_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case POINTER_PLUS_EXPR:
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case RDIV_EXPR:
+    case EXACT_DIV_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+    case COMPLEX_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+      /* Binary operations evaluating both arguments (increment and
+	 decrement are binary internally in GCC).  */
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      orig_op1 = op1 = TREE_OPERAND (expr, 1);
+      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				   maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op0);
+      if (code != MODIFY_EXPR
+	  && code != PREDECREMENT_EXPR
+	  && code != PREINCREMENT_EXPR
+	  && code != POSTDECREMENT_EXPR
+	  && code != POSTINCREMENT_EXPR)
+	op0 = decl_constant_value_for_optimization (op0);
+      /* The RHS of a MODIFY_EXPR was fully folded when building that
+	 expression for the sake of conversion warnings.  */
+      if (code != MODIFY_EXPR)
+	op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
+				     maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op1);
+      op1 = decl_constant_value_for_optimization (op1);
+
+      if (for_int_const && (TREE_CODE (op0) != INTEGER_CST
+			    || TREE_CODE (op1) != INTEGER_CST))
+	goto out;
+
+      if (op0 != orig_op0 || op1 != orig_op1 || in_init)
+	ret = in_init
+	  ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
+	  : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
+      else
+	ret = fold (expr);
+      if (TREE_OVERFLOW_P (ret)
+	  && !TREE_OVERFLOW_P (op0)
+	  && !TREE_OVERFLOW_P (op1))
+	overflow_warning (EXPR_LOC_OR_LOC (expr, input_location), ret);
+      if (code == LSHIFT_EXPR
+	  && TREE_CODE (orig_op0) != INTEGER_CST
+	  && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	  && TREE_CODE (op0) == INTEGER_CST
+	  && c_inhibit_evaluation_warnings == 0
+	  && tree_int_cst_sgn (op0) < 0)
+	warning_at (loc, OPT_Wshift_negative_value,
+		    "left shift of negative value");
+      if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+	  && TREE_CODE (orig_op1) != INTEGER_CST
+	  && TREE_CODE (op1) == INTEGER_CST
+	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
+	  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+	  && c_inhibit_evaluation_warnings == 0)
+	{
+	  if (tree_int_cst_sgn (op1) < 0)
+	    warning_at (loc, OPT_Wshift_count_negative,
+			(code == LSHIFT_EXPR
+			 ? G_("left shift count is negative")
+			 : G_("right shift count is negative")));
+	  else if (compare_tree_int (op1,
+				     TYPE_PRECISION (TREE_TYPE (orig_op0)))
+		   >= 0)
+	    warning_at (loc, OPT_Wshift_count_overflow,
+			(code == LSHIFT_EXPR
+			 ? G_("left shift count >= width of type")
+			 : G_("right shift count >= width of type")));
+	}
+      if (code == LSHIFT_EXPR
+	  /* If either OP0 has been folded to INTEGER_CST...  */
+	  && ((TREE_CODE (orig_op0) != INTEGER_CST
+	       && TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	       && TREE_CODE (op0) == INTEGER_CST)
+	      /* ...or if OP1 has been folded to INTEGER_CST...  */
+	      || (TREE_CODE (orig_op1) != INTEGER_CST
+		  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE
+		  && TREE_CODE (op1) == INTEGER_CST))
+	  && c_inhibit_evaluation_warnings == 0)
+	/* ...then maybe we can detect an overflow.  */
+	maybe_warn_shift_overflow (loc, op0, op1);
+      if ((code == TRUNC_DIV_EXPR
+	   || code == CEIL_DIV_EXPR
+	   || code == FLOOR_DIV_EXPR
+	   || code == EXACT_DIV_EXPR
+	   || code == TRUNC_MOD_EXPR)
+	  && TREE_CODE (orig_op1) != INTEGER_CST
+	  && TREE_CODE (op1) == INTEGER_CST
+	  && (TREE_CODE (TREE_TYPE (orig_op0)) == INTEGER_TYPE
+	      || TREE_CODE (TREE_TYPE (orig_op0)) == FIXED_POINT_TYPE)
+	  && TREE_CODE (TREE_TYPE (orig_op1)) == INTEGER_TYPE)
+	warn_for_div_by_zero (loc, op1);
+      goto out;
+
+    case INDIRECT_REF:
+    case FIX_TRUNC_EXPR:
+    case FLOAT_EXPR:
+    CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
+    case VIEW_CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case ADDR_EXPR:
+    case CONJ_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      /* Unary operations.  */
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
+				   maybe_const_itself, for_int_const);
+      STRIP_TYPE_NOPS (op0);
+      if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR)
+	op0 = decl_constant_value_for_optimization (op0);
+
+      if (for_int_const && TREE_CODE (op0) != INTEGER_CST)
+	goto out;
+
+      /* ??? Cope with user tricks that amount to offsetof.  The middle-end is
+	 not prepared to deal with them if they occur in initializers.  */
+      if (op0 != orig_op0
+	  && code == ADDR_EXPR
+	  && (op1 = get_base_address (op0)) != NULL_TREE
+	  && INDIRECT_REF_P (op1)
+	  && TREE_CONSTANT (TREE_OPERAND (op1, 0)))
+	ret = fold_convert_loc (loc, TREE_TYPE (expr), fold_offsetof_1 (op0));
+      else if (op0 != orig_op0 || in_init)
+	ret = in_init
+	  ? fold_build1_initializer_loc (loc, code, TREE_TYPE (expr), op0)
+	  : fold_build1_loc (loc, code, TREE_TYPE (expr), op0);
+      else
+	ret = fold (expr);
+      if (code == INDIRECT_REF
+	  && ret != expr
+	  && INDIRECT_REF_P (ret))
+	{
+	  TREE_READONLY (ret) = TREE_READONLY (expr);
+	  TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
+	  TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
+	}
+      switch (code)
+	{
+	case FIX_TRUNC_EXPR:
+	case FLOAT_EXPR:
+	CASE_CONVERT:
+	  /* Don't warn about explicit conversions.  We will already
+	     have warned about suspect implicit conversions.  */
+	  break;
+
+	default:
+	  if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0))
+	    overflow_warning (EXPR_LOCATION (expr), ret);
+	  break;
+	}
+      goto out;
+
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      /* Binary operations not necessarily evaluating both
+	 arguments.  */
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      orig_op1 = op1 = TREE_OPERAND (expr, 1);
+      op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self,
+				   for_int_const);
+      STRIP_TYPE_NOPS (op0);
+
+      unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
+			  ? truthvalue_false_node
+			  : truthvalue_true_node));
+      c_disable_warnings (unused_p);
+      op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self,
+				   for_int_const);
+      STRIP_TYPE_NOPS (op1);
+      c_enable_warnings (unused_p);
+
+      if (for_int_const
+	  && (TREE_CODE (op0) != INTEGER_CST
+	      /* Require OP1 be an INTEGER_CST only if it's evaluated.  */
+	      || (!unused_p && TREE_CODE (op1) != INTEGER_CST)))
+	goto out;
+
+      if (op0 != orig_op0 || op1 != orig_op1 || in_init)
+	ret = in_init
+	  ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
+	  : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
+      else
+	ret = fold (expr);
+      *maybe_const_operands &= op0_const;
+      *maybe_const_itself &= op0_const_self;
+      if (!(flag_isoc99
+	    && op0_const
+	    && op0_const_self
+	    && (code == TRUTH_ANDIF_EXPR
+		? op0 == truthvalue_false_node
+		: op0 == truthvalue_true_node)))
+	*maybe_const_operands &= op1_const;
+      if (!(op0_const
+	    && op0_const_self
+	    && (code == TRUTH_ANDIF_EXPR
+		? op0 == truthvalue_false_node
+		: op0 == truthvalue_true_node)))
+	*maybe_const_itself &= op1_const_self;
+      goto out;
+
+    case COND_EXPR:
+      orig_op0 = op0 = TREE_OPERAND (expr, 0);
+      orig_op1 = op1 = TREE_OPERAND (expr, 1);
+      orig_op2 = op2 = TREE_OPERAND (expr, 2);
+      op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self,
+				   for_int_const);
+
+      STRIP_TYPE_NOPS (op0);
+      c_disable_warnings (op0 == truthvalue_false_node);
+      op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self,
+				   for_int_const);
+      STRIP_TYPE_NOPS (op1);
+      c_enable_warnings (op0 == truthvalue_false_node);
+
+      c_disable_warnings (op0 == truthvalue_true_node);
+      op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self,
+				   for_int_const);
+      STRIP_TYPE_NOPS (op2);
+      c_enable_warnings (op0 == truthvalue_true_node);
+
+      if (for_int_const
+	  && (TREE_CODE (op0) != INTEGER_CST
+	      /* Only the evaluated operand must be an INTEGER_CST.  */
+	      || (op0 == truthvalue_true_node
+		  ? TREE_CODE (op1) != INTEGER_CST
+		  : TREE_CODE (op2) != INTEGER_CST)))
+	goto out;
+
+      if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
+	ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2);
+      else
+	ret = fold (expr);
+      *maybe_const_operands &= op0_const;
+      *maybe_const_itself &= op0_const_self;
+      if (!(flag_isoc99
+	    && op0_const
+	    && op0_const_self
+	    && op0 == truthvalue_false_node))
+	*maybe_const_operands &= op1_const;
+      if (!(op0_const
+	    && op0_const_self
+	    && op0 == truthvalue_false_node))
+	*maybe_const_itself &= op1_const_self;
+      if (!(flag_isoc99
+	    && op0_const
+	    && op0_const_self
+	    && op0 == truthvalue_true_node))
+	*maybe_const_operands &= op2_const;
+      if (!(op0_const
+	    && op0_const_self
+	    && op0 == truthvalue_true_node))
+	*maybe_const_itself &= op2_const_self;
+      goto out;
+
+    case EXCESS_PRECISION_EXPR:
+      /* Each case where an operand with excess precision may be
+	 encountered must remove the EXCESS_PRECISION_EXPR around
+	 inner operands and possibly put one around the whole
+	 expression or possibly convert to the semantic type (which
+	 c_fully_fold does); we cannot tell at this stage which is
+	 appropriate in any particular case.  */
+      gcc_unreachable ();
+
+    default:
+      /* Various codes may appear through folding built-in functions
+	 and their arguments.  */
+      goto out;
+    }
+
+ out:
+  /* Some folding may introduce NON_LVALUE_EXPRs; all lvalue checks
+     have been done by this point, so remove them again.  */
+  nowarning |= TREE_NO_WARNING (ret);
+  STRIP_TYPE_NOPS (ret);
+  if (nowarning && !TREE_NO_WARNING (ret))
+    {
+      if (!CAN_HAVE_LOCATION_P (ret))
+	ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+      TREE_NO_WARNING (ret) = 1;
+    }
+  if (ret != expr)
+    {
+      protected_set_expr_location (ret, loc);
+      if (IS_EXPR_CODE_CLASS (kind))
+	set_source_range (ret, old_range.m_start, old_range.m_finish);
+    }
+  return ret;
+}
+
+/* If not optimizing, EXP is not a VAR_DECL, or EXP has array type,
+   return EXP.  Otherwise, return either EXP or its known constant
+   value (if it has one), but return EXP if EXP has mode BLKmode.  ???
+   Is the BLKmode test appropriate?  */
+
+tree
+decl_constant_value_for_optimization (tree exp)
+{
+  tree ret;
+
+  if (!optimize
+      || !VAR_P (exp)
+      || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
+      || DECL_MODE (exp) == BLKmode)
+    return exp;
+
+  ret = decl_constant_value (exp);
+  /* Avoid unwanted tree sharing between the initializer and current
+     function's body where the tree can be modified e.g. by the
+     gimplifier.  */
+  if (ret != exp && TREE_STATIC (exp))
+    ret = unshare_expr (ret);
+  return ret;
+}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 848131e..1c07065 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -728,4 +728,7 @@ extern void
 set_c_expr_source_range (c_expr *expr,
 			 source_range src_range);
 
+/* In c-fold.c */
+extern tree decl_constant_value_for_optimization (tree);
+
 #endif /* ! GCC_C_TREE_H */
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 86fef9e..2c54d85 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -1883,6 +1883,17 @@ cp_fully_fold (tree x)
   return cp_fold (x);
 }
 
+/* c-common interface to cp_fold.  If IN_INIT, this is in a static initializer
+   and certain changes are made to the folding done.  Or should be (FIXME).  We
+   never touch maybe_const, as it is only used for the C front-end
+   C_MAYBE_CONST_EXPR.  */
+
+tree
+c_fully_fold (tree x, bool /*in_init*/, bool */*maybe_const*/)
+{
+  return cp_fold (x);
+}
+
 static GTY((cache, deletable)) cache_map fold_cache;
 
 /*  This function tries to fold an expression X.
commit db32d5c6336bcbdb22561eeea047a273897d097f
Author: Jason Merrill <ja...@redhat.com>
Date:   Tue Dec 1 15:51:19 2015 -0500

    	Do constant folding in warn_* functions.
    
    gcc/c-family/
    	* c-common.c (fold_for_warn): New.
    	(warn_logical_operator, warn_tautological_cmp)
    	(check_function_arguments_recurse, maybe_warn_bool_compare): Use it.
    gcc/cp/
    	* call.c (build_new_op_1): Don't fold arguments to
    	warn_logical_operator or maybe_warn_bool_compare.
    fold-for-warn

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 40f86e3..a8122b3 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -1094,6 +1094,19 @@ fix_string_type (tree value)
   return value;
 }
 
+/* Fold X for consideration by one of the warning functions when checking
+   whether an expression has a constant value.  */
+
+static tree
+fold_for_warn (tree x)
+{
+  if (c_dialect_cxx ())
+    return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL);
+  else
+    /* The C front-end has already folded X appropriately.  */
+    return x;
+}
+
 /* Print a warning if a constant expression had overflow in folding.
    Invoke this function on every expression that the language
    requires to be a constant expression.
@@ -1207,6 +1220,9 @@ warn_logical_operator (location_t location, enum tree_code code, tree type,
      programmer. That is, an expression such as op && MASK
      where op should not be any boolean expression, nor a
      constant, and mask seems to be a non-boolean integer constant.  */
+  if (TREE_CODE (op_right) == CONST_DECL)
+    /* An enumerator counts as a constant.  */
+    op_right = DECL_INITIAL (op_right);
   if (!truth_value_p (code_left)
       && INTEGRAL_TYPE_P (TREE_TYPE (op_left))
       && !CONSTANT_CLASS_P (op_left)
@@ -1227,7 +1243,8 @@ warn_logical_operator (location_t location, enum tree_code code, tree type,
 
   /* We do not warn for constants because they are typical of macro
      expansions that test for features.  */
-  if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right))
+  if (CONSTANT_CLASS_P (fold_for_warn (op_left))
+      || CONSTANT_CLASS_P (fold_for_warn (op_right)))
     return;
 
   /* This warning only makes sense with logical operands.  */
@@ -1347,7 +1364,8 @@ warn_tautological_cmp (location_t loc, enum tree_code code, tree lhs, tree rhs)
 
   /* We do not warn for constants because they are typical of macro
      expansions that test for features, sizeof, and similar.  */
-  if (CONSTANT_CLASS_P (fold (lhs)) || CONSTANT_CLASS_P (fold (rhs)))
+  if (CONSTANT_CLASS_P (fold_for_warn (lhs))
+      || CONSTANT_CLASS_P (fold_for_warn (rhs)))
     return;
 
   /* Don't warn for e.g.
@@ -9701,11 +9719,14 @@ check_function_arguments_recurse (void (*callback)
 
   if (TREE_CODE (param) == COND_EXPR)
     {
+      tree cond = fold_for_warn (TREE_OPERAND (param, 0));
       /* Check both halves of the conditional expression.  */
-      check_function_arguments_recurse (callback, ctx,
-					TREE_OPERAND (param, 1), param_num);
-      check_function_arguments_recurse (callback, ctx,
-					TREE_OPERAND (param, 2), param_num);
+      if (!integer_zerop (cond))
+	check_function_arguments_recurse (callback, ctx,
+					  TREE_OPERAND (param, 1), param_num);
+      if (!integer_nonzerop (cond))
+	check_function_arguments_recurse (callback, ctx,
+					  TREE_OPERAND (param, 2), param_num);
       return;
     }
 
@@ -11984,9 +12005,14 @@ maybe_warn_bool_compare (location_t loc, enum tree_code code, tree op0,
   if (TREE_CODE_CLASS (code) != tcc_comparison)
     return;
 
-  tree cst = (TREE_CODE (op0) == INTEGER_CST)
-	     ? op0 : (TREE_CODE (op1) == INTEGER_CST) ? op1 : NULL_TREE;
-  if (!cst)
+  tree f, cst;
+  if (f = fold_for_warn (op0),
+      TREE_CODE (f) == INTEGER_CST)
+    cst = op0 = f;
+  else if (f = fold_for_warn (op1),
+	   TREE_CODE (f) == INTEGER_CST)
+    cst = op1 = f;
+  else
     return;
 
   if (!integer_zerop (cst) && !integer_onep (cst))
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8cdda62..117dd79 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5687,8 +5687,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, fold (arg1),
-				       code_orig_arg2, fold (arg2));
+				       code_orig_arg1, arg1,
+				       code_orig_arg2, arg2);
 
 	      arg2 = convert_like (conv, arg2, complain);
 	    }
@@ -5726,8 +5726,8 @@ 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, fold (arg1),
-			       code_orig_arg2, fold (arg2));
+			       code_orig_arg1, arg1,
+			       code_orig_arg2, arg2);
       /* Fall through.  */
     case GT_EXPR:
     case LT_EXPR:
@@ -5738,8 +5738,7 @@ 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, fold (arg1),
-				 fold (arg2));
+	maybe_warn_bool_compare (loc, code, arg1, arg2);
       if (complain & tf_warning && warn_tautological_compare)
 	warn_tautological_cmp (loc, code, arg1, arg2);
       /* Fall through.  */
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull1.C b/gcc/testsuite/g++.dg/warn/Wnonnull1.C
new file mode 100644
index 0000000..0f610f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wnonnull1.C
@@ -0,0 +1,7 @@
+// { dg-options -Wnonnull }
+
+void g(void *) __attribute__ ((nonnull (1)));
+void f(void *p)
+{
+  g(1 == 1 ? p : 0);
+}

Reply via email to