re PR c/66066 (r222889 causes bogus error: initializer element is not constant)
authorMarek Polacek <polacek@redhat.com>
Thu, 14 May 2015 11:42:53 +0000 (11:42 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Thu, 14 May 2015 11:42:53 +0000 (11:42 +0000)
PR c/66066
PR c/66127
* c-common.c (c_fully_fold): Pass false down to c_fully_fold_internal.
(c_fully_fold_internal): Fold C_MAYBE_CONST_EXPRs with
C_MAYBE_CONST_EXPR_INT_OPERANDS set.  Add FOR_INT_CONST argument and
use it.  If FOR_INT_CONST, require that all evaluated operands be
INTEGER_CSTs.

* c-typeck.c (digest_init): Call pedwarn_init with OPT_Wpedantic
rather than with 0.

* gcc.dg/pr14649-1.c: Add -Wpedantic.
* gcc.dg/pr19984.c: Likewise.
* gcc.dg/pr66066-1.c: New test.
* gcc.dg/pr66066-2.c: New test.
* gcc.dg/pr66066-3.c: New test.

From-SVN: r223193

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr14649-1.c
gcc/testsuite/gcc.dg/pr19984.c
gcc/testsuite/gcc.dg/pr66066-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr66066-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr66066-3.c [new file with mode: 0644]

index 52b4d5cb7a40b824671fff8504a7e701f635df5b..48d483e7b1b3c23322e24171ba06cb4b0e1a6831 100644 (file)
@@ -1,3 +1,13 @@
+2015-05-14  Marek Polacek  <polacek@redhat.com>
+
+       PR c/66066
+       PR c/66127
+       * c-common.c (c_fully_fold): Pass false down to c_fully_fold_internal.
+       (c_fully_fold_internal): Fold C_MAYBE_CONST_EXPRs with
+       C_MAYBE_CONST_EXPR_INT_OPERANDS set.  Add FOR_INT_CONST argument and
+       use it.  If FOR_INT_CONST, require that all evaluated operands be
+       INTEGER_CSTs.
+
 2015-05-12  David Malcolm  <dmalcolm@redhat.com>
 
        * c-common.h (warn_for_misleading_indentation): New prototype.
index 7e5ac72900b6f83e58f5dee45b098ef32196a4fb..31c4c0d16e01bd9b0ebb4be193285fdc4adf1a54 100644 (file)
@@ -315,7 +315,7 @@ 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 *);
+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 *);
 
@@ -1148,7 +1148,7 @@ c_fully_fold (tree expr, bool in_init, bool *maybe_const)
       expr = TREE_OPERAND (expr, 0);
     }
   ret = c_fully_fold_internal (expr, in_init, maybe_const,
-                              &maybe_const_itself);
+                              &maybe_const_itself, false);
   if (eptype)
     ret = fold_convert_loc (loc, eptype, ret);
   *maybe_const &= maybe_const_itself;
@@ -1161,11 +1161,13 @@ c_fully_fold (tree expr, bool in_init, bool *maybe_const)
    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).  */
+   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 *maybe_const_itself, bool for_int_const)
 {
   tree ret = expr;
   enum tree_code code = TREE_CODE (expr);
@@ -1209,7 +1211,11 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       if (C_MAYBE_CONST_EXPR_NON_CONST (expr))
        *maybe_const_operands = false;
       if (C_MAYBE_CONST_EXPR_INT_OPERANDS (expr))
-       *maybe_const_itself = false;
+       {
+         *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
@@ -1259,7 +1265,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       op1 = TREE_OPERAND (expr, 1);
       op2 = TREE_OPERAND (expr, 2);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-                                  maybe_const_itself);
+                                  maybe_const_itself, for_int_const);
       STRIP_TYPE_NOPS (op0);
       if (op0 != orig_op0)
        ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
@@ -1276,10 +1282,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       op2 = TREE_OPERAND (expr, 2);
       op3 = TREE_OPERAND (expr, 3);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-                                  maybe_const_itself);
+                                  maybe_const_itself, for_int_const);
       STRIP_TYPE_NOPS (op0);
       op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands,
-                                  maybe_const_itself);
+                                  maybe_const_itself, for_int_const);
       STRIP_TYPE_NOPS (op1);
       op1 = decl_constant_value_for_optimization (op1);
       if (op0 != orig_op0 || op1 != orig_op1)
@@ -1336,7 +1342,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       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);
+                                  maybe_const_itself, for_int_const);
       STRIP_TYPE_NOPS (op0);
       if (code != MODIFY_EXPR
          && code != PREDECREMENT_EXPR
@@ -1348,9 +1354,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
         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);
+                                    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)
@@ -1420,10 +1431,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       /* Unary operations.  */
       orig_op0 = op0 = TREE_OPERAND (expr, 0);
       op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands,
-                                  maybe_const_itself);
+                                  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
@@ -1468,17 +1483,25 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
         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);
+      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);
+      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)
@@ -1506,19 +1529,30 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
       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);
+      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);
+      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);
+      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
index f1c40738b41e7f3f188ff6fcb1c5096b7c2b958d..ebf9759bc9b699b1b2d24c95fabf60bd6d48bd9d 100644 (file)
@@ -1,3 +1,10 @@
+2015-05-14  Marek Polacek  <polacek@redhat.com>
+
+       PR c/66066
+       PR c/66127
+       * c-typeck.c (digest_init): Call pedwarn_init with OPT_Wpedantic
+       rather than with 0.
+
 2015-05-12  David Malcolm  <dmalcolm@redhat.com>
 
        * c-parser.c (c_parser_if_body): Add param "if_loc", use it
index 3fcb7c2c5e7d67766a0b8a5999c0a0ba87e7bb92..9b883a22f2ba3e97eb080c482b9c0e9eb6023ba9 100644 (file)
@@ -6864,7 +6864,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype,
          inside_init = error_mark_node;
        }
       else if (require_constant && !maybe_const)
-       pedwarn_init (init_loc, 0,
+       pedwarn_init (init_loc, OPT_Wpedantic,
                      "initializer element is not a constant expression");
 
       /* Added to enable additional -Wsuggest-attribute=format warnings.  */
index 5daa442ba994401942bf72fe7bc4e00c2facf9b1..ef46d503bf5ad972223605aa7d7b0f5024101071 100644 (file)
@@ -1,3 +1,13 @@
+2015-05-14  Marek Polacek  <polacek@redhat.com>
+
+       PR c/66066
+       PR c/66127
+       * gcc.dg/pr14649-1.c: Add -Wpedantic.
+       * gcc.dg/pr19984.c: Likewise.
+       * gcc.dg/pr66066-1.c: New test.
+       * gcc.dg/pr66066-2.c: New test.
+       * gcc.dg/pr66066-3.c: New test.
+
 2015-05-13  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        * gcc.target/aarch64/pow-sqrt-synth-1.c: New test.
index 34f42f08f2cadef0f5c3a6b5663d005b0ed58094..b9fc4b9461637176aaccd00738d8548b99f1c30e 100644 (file)
@@ -1,6 +1,6 @@
 /* PR c/14649 */
 /* { dg-do compile } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wpedantic" } */
 
 double atan(double);
 
index 5323c461fb0f8bb9a4ff6691eedadefdde6a028b..a628e0e91eac28d7b99fa1f86d225c74d3ab324b 100644 (file)
@@ -1,6 +1,6 @@
 /* PR c/19984 */
 /* { dg-do compile } */
-/* { dg-options "-O2 -std=c99" } */
+/* { dg-options "-O2 -std=c99 -Wpedantic" } */
 
 
 double nan (const char *);
diff --git a/gcc/testsuite/gcc.dg/pr66066-1.c b/gcc/testsuite/gcc.dg/pr66066-1.c
new file mode 100644 (file)
index 0000000..7a1d342
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR c/66066 */
+/* { dg-do compile } */
+/* { dg-options "-Wno-div-by-zero" } */
+
+/* Accept these unless -pedantic-errors/-Werror.  */
+int a1 = -1 << 0;
+int a2 = -1 << 0 | 0;
+int a3 = -1 << 0 & 1;
+int a4 = -1 << 2 ^ 1;
+int a5 = 4 & -1 << 2;
+int a6 = (-1 << 2) ^ (1 >> 1);
+int a7 = 0 || (-1 << 1);
+int a8 = 0 ? 2 : (-1 << 1);
+int a9 = 1 && -1 << 0;
+int a10 = !(-1 << 0);
+
+/* Don't accept these.  */
+int b1 = 1 / 0;                /* { dg-error "initializer element is not constant" } */
+int b2 = 1 / (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b3 = 0 ? 2 : 1 / 0;        /* { dg-error "initializer element is not constant" } */
+int b4 = 0 || 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b5 = 0 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b6 = 1 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b7 = (1 / 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int b8 = (1 / 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int b9 = 1 && 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b10 = !(1 / 0);    /* { dg-error "initializer element is not constant" } */
+int c1 = 1 % 0;                /* { dg-error "initializer element is not constant" } */
+int c2 = 1 / (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c3 = 0 ? 2 : 1 % 0;        /* { dg-error "initializer element is not constant" } */
+int c4 = 0 || 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c5 = 0 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c6 = 1 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c7 = (1 % 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int c8 = (1 % 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int c9 = 1 && 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c10 = !(1 % 0);    /* { dg-error "initializer element is not constant" } */
diff --git a/gcc/testsuite/gcc.dg/pr66066-2.c b/gcc/testsuite/gcc.dg/pr66066-2.c
new file mode 100644 (file)
index 0000000..848fe85
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR c/66066 */
+/* { dg-do compile } */
+/* { dg-options "-Wno-div-by-zero -Wpedantic" } */
+
+/* Accept these unless -pedantic-errors/-Werror.  */
+int a1 = -1 << 0;              /* { dg-warning "initializer element is not a constant expression" } */
+int a2 = -1 << 0 | 0;          /* { dg-warning "initializer element is not a constant expression" } */
+int a3 = -1 << 0 & 1;          /* { dg-warning "initializer element is not a constant expression" } */
+int a4 = -1 << 2 ^ 1;          /* { dg-warning "initializer element is not a constant expression" } */
+int a5 = 4 & -1 << 2;          /* { dg-warning "initializer element is not a constant expression" } */
+int a6 = (-1 << 2) ^ (1 >> 1); /* { dg-warning "initializer element is not a constant expression" } */
+int a7 = 0 || (-1 << 1);       /* { dg-warning "initializer element is not a constant expression" } */
+int a8 = 0 ? 2 : (-1 << 1);    /* { dg-warning "initializer element is not a constant expression" } */
+int a9 = 1 && -1 << 0;         /* { dg-warning "initializer element is not a constant expression" } */
+int a10 = !(-1 << 0);          /* { dg-warning "initializer element is not a constant expression" } */
+
+/* Don't accept these.  */
+int b1 = 1 / 0;                /* { dg-error "initializer element is not constant" } */
+int b2 = 1 / (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b3 = 0 ? 2 : 1 / 0;        /* { dg-error "initializer element is not constant" } */
+int b4 = 0 || 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b5 = 0 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b6 = 1 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b7 = (1 / 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int b8 = (1 / 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int b9 = 1 && 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b10 = !(1 / 0);    /* { dg-error "initializer element is not constant" } */
+int c1 = 1 % 0;                /* { dg-error "initializer element is not constant" } */
+int c2 = 1 / (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c3 = 0 ? 2 : 1 % 0;        /* { dg-error "initializer element is not constant" } */
+int c4 = 0 || 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c5 = 0 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c6 = 1 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c7 = (1 % 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int c8 = (1 % 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int c9 = 1 && 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c10 = !(1 % 0);    /* { dg-error "initializer element is not constant" } */
diff --git a/gcc/testsuite/gcc.dg/pr66066-3.c b/gcc/testsuite/gcc.dg/pr66066-3.c
new file mode 100644 (file)
index 0000000..99ffec6
--- /dev/null
@@ -0,0 +1,37 @@
+/* PR c/66066 */
+/* { dg-do compile } */
+/* { dg-options "-Wno-div-by-zero -pedantic-errors" } */
+
+/* Accept these unless -pedantic-errors/-Werror.  */
+int a1 = -1 << 0;              /* { dg-error "initializer element is not a constant expression" } */
+int a2 = -1 << 0 | 0;          /* { dg-error "initializer element is not a constant expression" } */
+int a3 = -1 << 0 & 1;          /* { dg-error "initializer element is not a constant expression" } */
+int a4 = -1 << 2 ^ 1;          /* { dg-error "initializer element is not a constant expression" } */
+int a5 = 4 & -1 << 2;          /* { dg-error "initializer element is not a constant expression" } */
+int a6 = (-1 << 2) ^ (1 >> 1); /* { dg-error "initializer element is not a constant expression" } */
+int a7 = 0 || (-1 << 1);       /* { dg-error "initializer element is not a constant expression" } */
+int a8 = 0 ? 2 : (-1 << 1);    /* { dg-error "initializer element is not a constant expression" } */
+int a9 = 1 && -1 << 0;         /* { dg-error "initializer element is not a constant expression" } */
+int a10 = !(-1 << 0);          /* { dg-error "initializer element is not a constant expression" } */
+
+/* Don't accept these.  */
+int b1 = 1 / 0;                /* { dg-error "initializer element is not constant" } */
+int b2 = 1 / (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b3 = 0 ? 2 : 1 / 0;        /* { dg-error "initializer element is not constant" } */
+int b4 = 0 || 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b5 = 0 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b6 = 1 * (1 / 0);  /* { dg-error "initializer element is not constant" } */
+int b7 = (1 / 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int b8 = (1 / 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int b9 = 1 && 1 / 0;   /* { dg-error "initializer element is not constant" } */
+int b10 = !(1 / 0);    /* { dg-error "initializer element is not constant" } */
+int c1 = 1 % 0;                /* { dg-error "initializer element is not constant" } */
+int c2 = 1 / (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c3 = 0 ? 2 : 1 % 0;        /* { dg-error "initializer element is not constant" } */
+int c4 = 0 || 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c5 = 0 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c6 = 1 * (1 % 0);  /* { dg-error "initializer element is not constant" } */
+int c7 = (1 % 0) * 0;  /* { dg-error "initializer element is not constant" } */
+int c8 = (1 % 0) * 1;  /* { dg-error "initializer element is not constant" } */
+int c9 = 1 && 1 % 0;   /* { dg-error "initializer element is not constant" } */
+int c10 = !(1 % 0);    /* { dg-error "initializer element is not constant" } */