re PR c++/50608 (cannot apply 'offsetof' to a non-constant address)
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 4 Nov 2011 21:46:07 +0000 (21:46 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Fri, 4 Nov 2011 21:46:07 +0000 (21:46 +0000)
2011-11-04  Eric Botcazou  <ebotcazou@adacore.com>

PR c++/50608
* c-parser.c (c_parser_postfix_expression) <RID_OFFSETOF>: Adjust call
to fold_offsetof.
* c-typeck.c (build_unary_op) <ADDR_EXPR>: Call fold_offsetof_1.
c-family/
* c-common.c (c_fully_fold_internal) <ADDR_EXPR>: Call fold_offsetof_1.
(fold_offsetof_1): Make global.  Remove STOP_REF argument and adjust.
<INDIRECT_REF>: Return the argument.
<ARRAY_REF>: Remove special code for negative offset.
Call fold_build_pointer_plus instead of size_binop.
(fold_offsetof): Remove STOP_REF argument and adjust.
* c-common.h (fold_offsetof_1): Declare.
(fold_offsetof): Remove STOP_REF argument.
cp/
* semantics.c (finish_offsetof): Adjust call to fold_offsetof.
* typeck.c (cp_build_addr_expr_1): Call fold_offsetof_1.

From-SVN: r180986

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-parser.c
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/offsetof7.C [new file with mode: 0644]

index 2b9e5b35d18ea39d2d867c145d16fd9413a700b3..c0bdc1a1d234b49778b1d134ad5769d6f7a1bc01 100644 (file)
@@ -1,16 +1,23 @@
-2011-11-05  Alan Modra  <amodra@gmail.com>
+2011-11-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR c++/50608
+       * c-parser.c (c_parser_postfix_expression) <RID_OFFSETOF>: Adjust call
+       to fold_offsetof.
+       * c-typeck.c (build_unary_op) <ADDR_EXPR>: Call fold_offsetof_1.
+
+2011-11-04  Alan Modra  <amodra@gmail.com>
 
        * reload1.c (gen_reload): Don't use REGNO on SUBREGs.
        * print-rtl.c (print_rtx): Don't segfault on negative regno.
 
-2011-11-03  David S. Miller  <davem@davemloft.net>
+2011-11-04  David S. Miller  <davem@davemloft.net>
 
        PR target/49965
        * config/sparc/sparc.c (sparc_expand_conditional_move): Handle the
        fact that sparc_emit_float_lib_cmp modifies the comparison in
        operands[1].
 
-2011-11-05     Ralf Corsépius <ralf.corsepius@rtems.org>
+2011-11-04  Ralf Corsépius <ralf.corsepius@rtems.org>
 
        * config/lm32/t-rtems: New.
        * config.gcc (lm32-*-rtems*): Add t-rtems.
index 4a452c3495158a2c3b09a6d6c8f57b0b66efb48b..d7ff089d6ba5f2ec6631079fd9e8418719a32fda 100644 (file)
@@ -1,3 +1,15 @@
+2011-11-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR c++/50608
+       * c-common.c (c_fully_fold_internal) <ADDR_EXPR>: Call fold_offsetof_1.
+       (fold_offsetof_1): Make global.  Remove STOP_REF argument and adjust.
+       <INDIRECT_REF>: Return the argument.
+       <ARRAY_REF>: Remove special code for negative offset.
+       Call fold_build_pointer_plus instead of size_binop.
+       (fold_offsetof): Remove STOP_REF argument and adjust.
+       * c-common.h (fold_offsetof_1): Declare.
+       (fold_offsetof): Remove STOP_REF argument.
+
 2011-11-02  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/50810
index 2eefe03f390c1f2ac5d4e1643cac58e09ea32818..df8dda4a13b6a1ff5ae03431dd586780c9a7cacc 100644 (file)
@@ -1274,12 +1274,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
          && (op1 = get_base_address (op0)) != NULL_TREE
          && TREE_CODE (op1) == INDIRECT_REF
          && TREE_CONSTANT (TREE_OPERAND (op1, 0)))
-       {
-         tree offset = fold_offsetof (op0, op1);
-         op1
-           = fold_convert_loc (loc, TREE_TYPE (expr), TREE_OPERAND (op1, 0));
-         ret = fold_build_pointer_plus_loc (loc, op1, offset);
-       }
+       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)
@@ -8538,20 +8533,15 @@ c_common_to_target_charset (HOST_WIDE_INT c)
     return uc;
 }
 
-/* Build the result of __builtin_offsetof.  EXPR is a nested sequence of
-   component references, with STOP_REF, or alternatively an INDIRECT_REF of
-   NULL, at the bottom; much like the traditional rendering of offsetof as a
-   macro.  Returns the folded and properly cast result.  */
+/* Fold an offsetof-like expression.  EXPR is a nested sequence of component
+   references with an INDIRECT_REF of a constant at the bottom; much like the
+   traditional rendering of offsetof as a macro.  Return the folded result.  */
 
-static tree
-fold_offsetof_1 (tree expr, tree stop_ref)
+tree
+fold_offsetof_1 (tree expr)
 {
-  enum tree_code code = PLUS_EXPR;
   tree base, off, t;
 
-  if (expr == stop_ref && TREE_CODE (expr) != ERROR_MARK)
-    return size_zero_node;
-
   switch (TREE_CODE (expr))
     {
     case ERROR_MARK:
@@ -8568,15 +8558,15 @@ fold_offsetof_1 (tree expr, tree stop_ref)
 
     case NOP_EXPR:
     case INDIRECT_REF:
-      if (!integer_zerop (TREE_OPERAND (expr, 0)))
+      if (!TREE_CONSTANT (TREE_OPERAND (expr, 0)))
        {
          error ("cannot apply %<offsetof%> to a non constant address");
          return error_mark_node;
        }
-      return size_zero_node;
+      return TREE_OPERAND (expr, 0);
 
     case COMPONENT_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
       if (base == error_mark_node)
        return base;
 
@@ -8594,21 +8584,14 @@ fold_offsetof_1 (tree expr, tree stop_ref)
       break;
 
     case ARRAY_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref);
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0));
       if (base == error_mark_node)
        return base;
 
       t = TREE_OPERAND (expr, 1);
-      if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
-       {
-         code = MINUS_EXPR;
-         t = fold_build1_loc (input_location, NEGATE_EXPR, TREE_TYPE (t), t);
-       }
-      t = convert (sizetype, t);
-      off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
 
       /* Check if the offset goes beyond the upper bound of the array.  */
-      if (code == PLUS_EXPR && TREE_CODE (t) == INTEGER_CST)
+      if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) >= 0)
        {
          tree upbound = array_ref_up_bound (expr);
          if (upbound != NULL_TREE
@@ -8648,26 +8631,30 @@ fold_offsetof_1 (tree expr, tree stop_ref)
                }
            }
        }
+
+      t = convert (sizetype, t);
+      off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
       break;
 
     case COMPOUND_EXPR:
       /* Handle static members of volatile structs.  */
       t = TREE_OPERAND (expr, 1);
       gcc_assert (TREE_CODE (t) == VAR_DECL);
-      return fold_offsetof_1 (t, stop_ref);
+      return fold_offsetof_1 (t);
 
     default:
       gcc_unreachable ();
     }
 
-  return size_binop (code, base, off);
+  return fold_build_pointer_plus (base, off);
 }
 
+/* Likewise, but convert it to the return type of offsetof.  */
+
 tree
-fold_offsetof (tree expr, tree stop_ref)
+fold_offsetof (tree expr)
 {
-  /* Convert back from the internal sizetype to size_t.  */
-  return convert (size_type_node, fold_offsetof_1 (expr, stop_ref));
+  return convert (size_type_node, fold_offsetof_1 (expr));
 }
 
 /* Warn for A ?: C expressions (with B omitted) where A is a boolean 
index 71746a949d3e1a3340b5025747690fdf83e19e0c..7ecb57e5867d1ae53a77327283b9f22755c32bf8 100644 (file)
@@ -956,7 +956,8 @@ extern bool c_dump_tree (void *, tree);
 
 extern void verify_sequence_points (tree);
 
-extern tree fold_offsetof (tree, tree);
+extern tree fold_offsetof_1 (tree);
+extern tree fold_offsetof (tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
index af6cc149efc9fe73af42327a0f59d1fb2ceb1813..8db203ad6b38719d9e987d130ff269d4a66b677e 100644 (file)
@@ -6388,7 +6388,7 @@ c_parser_postfix_expression (c_parser *parser)
              c_parser_error (parser, "expected identifier");
            c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
                                       "expected %<)%>");
-           expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
+           expr.value = fold_offsetof (offsetof_ref);
          }
          break;
        case RID_CHOOSE_EXPR:
index 7dfdae2b38e071ad5266c9825dcf53867b9a205f..46363c0a165468b081493f7dc7029cb0cea29131 100644 (file)
@@ -3890,10 +3890,7 @@ build_unary_op (location_t location,
       if (val && TREE_CODE (val) == INDIRECT_REF
           && TREE_CONSTANT (TREE_OPERAND (val, 0)))
        {
-         tree op0 = fold_offsetof (arg, val), op1;
-
-         op1 = fold_convert_loc (location, argtype, TREE_OPERAND (val, 0));
-         ret = fold_build_pointer_plus_loc (location, op1, op0);
+         ret = fold_convert_loc (location, argtype, fold_offsetof_1 (arg));
          goto return_build_unary_op;
        }
 
index 2a1db7abdc2d459b6103089a1c9403ac56ea78a8..ffb085c4d9e81a8df87d5db66d33a78411573015 100644 (file)
@@ -1,3 +1,9 @@
+2011-11-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR c++/50608
+       * semantics.c (finish_offsetof): Adjust call to fold_offsetof.
+       * typeck.c (cp_build_addr_expr_1): Call fold_offsetof_1.
+
 2011-11-04  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * typeck.c (build_indirect_ref): Use ATTRIBUTE_UNUSED.
index a80aec6c52da6ae1a559a2a4733eda61d22a4b45..cebb7df2c3d403dd2d19fca134932035253dd5d2 100644 (file)
@@ -3568,7 +3568,7 @@ finish_offsetof (tree expr)
       if (!complete_type_or_else (TREE_TYPE (object), object))
        return error_mark_node;
     }
-  return fold_offsetof (expr, NULL_TREE);
+  return fold_offsetof (expr);
 }
 
 /* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR.  This
index f4e45b4f034ceb18a46a83c82c47ecea6a3a249c..386f3b89d4815a32f134827be00ed5d0ae1c2728 100644 (file)
@@ -4881,9 +4881,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
       && TREE_CONSTANT (TREE_OPERAND (val, 0)))
     {
       tree type = build_pointer_type (argtype);
-      tree op0 = fold_convert (type, TREE_OPERAND (val, 0));
-      tree op1 = fold_offsetof (arg, val);
-      return fold_build_pointer_plus (op0, op1);
+      return fold_convert (type, fold_offsetof_1 (arg));
     }
 
   /* Handle complex lvalues (when permitted)
index e39ed46636b8f963f9ef22184be501937c86535c..218a9d34a5924b1e901431463405f625114a7ec9 100644 (file)
@@ -1,3 +1,7 @@
+2011-11-04  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * g++.dg/other/offsetof7.C: New test.
+
 2011-11-04  Hans-Peter Nilsson  <hp@axis.com>
 
        * lib/gcc-dg.exp (gcc_force_conventional_output): New global
diff --git a/gcc/testsuite/g++.dg/other/offsetof7.C b/gcc/testsuite/g++.dg/other/offsetof7.C
new file mode 100644 (file)
index 0000000..0ce2ee0
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/50608
+// Testcase by <dberger@oubliette.org>
+// { dg-do compile }
+
+struct A {
+    int offset;
+};
+
+struct B: public A {
+};
+
+struct C {
+    A a;
+    B b;
+};
+
+int fails = __builtin_offsetof (C, b.offset);