Hi!

fold_offsetof_1 builds the base as usually INTEGER_CST with pointer type and
calls fold_build_pointer_plus with the offset gathered from the
COMPONENT_REF field offset or ARRAY_REF index or combination of them.
But most of the fold_* routines aren't recursive, they fold just one level,
so if the expression is more complex and with delayed folding we actually
can keep around POINTER_PLUS_EXPR of pointer-typed INTEGER_CST (usually 0)
and some large expression computing the offset.  In that case we reject it
as constant expression though, because we don't allow such arithmetics on
(null) pointers.

The following patch fixes it by only doing the pointer arithmetics if the
user actually wrote it that way (offsetof-like expression like &((struct S
*)0)->foo.bar[idx * 3 + 2]), but if it is __builtin_offsetof, uses integral
arithmetics from the beginning.  I think we should e.g. reject offsetof
when the expression inside of array index has undefined behavior, so we
don't want to cp_fold the fold_offsetof_1 result.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
What about release branches?

2018-05-06  Jakub Jelinek  <ja...@redhat.com>

        PR c++/85662
        * c-common.h (fold_offsetof_1): Add bool argument with false default
        argument.
        * c-common.c (fold_offsetof_1): Add NONPTR argument, if true, convert
        the pointer constant to sizetype and use size_binop with PLUS_EXPR
        instead of fold_build_pointer_plus.  Adjust recursive calls.
        (fold_offsetof): Pass true as NONPTR to fold_offsetof_1.

        * g++.dg/ext/offsetof2.C: New test.

--- gcc/c-family/c-common.h.jj  2018-03-13 00:38:23.846662269 +0100
+++ gcc/c-family/c-common.h     2018-05-05 10:43:53.069431079 +0200
@@ -1033,7 +1033,7 @@ extern bool c_dump_tree (void *, tree);
 
 extern void verify_sequence_points (tree);
 
-extern tree fold_offsetof_1 (tree, tree_code ctx = ERROR_MARK);
+extern tree fold_offsetof_1 (tree, bool = false, tree_code ctx = ERROR_MARK);
 extern tree fold_offsetof (tree);
 
 extern int complete_array_type (tree *, tree, bool);
--- gcc/c-family/c-common.c.jj  2018-03-27 21:58:55.598502113 +0200
+++ gcc/c-family/c-common.c     2018-05-05 10:55:47.951600802 +0200
@@ -6171,7 +6171,7 @@ c_common_to_target_charset (HOST_WIDE_IN
    traditional rendering of offsetof as a macro.  Return the folded result.  */
 
 tree
-fold_offsetof_1 (tree expr, enum tree_code ctx)
+fold_offsetof_1 (tree expr, bool nonptr, enum tree_code ctx)
 {
   tree base, off, t;
   tree_code code = TREE_CODE (expr);
@@ -6196,10 +6196,12 @@ fold_offsetof_1 (tree expr, enum tree_co
          error ("cannot apply %<offsetof%> to a non constant address");
          return error_mark_node;
        }
+      if (nonptr)
+       return convert (sizetype, TREE_OPERAND (expr, 0));
       return TREE_OPERAND (expr, 0);
 
     case COMPONENT_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), code);
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), nonptr, code);
       if (base == error_mark_node)
        return base;
 
@@ -6216,7 +6218,7 @@ fold_offsetof_1 (tree expr, enum tree_co
       break;
 
     case ARRAY_REF:
-      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), code);
+      base = fold_offsetof_1 (TREE_OPERAND (expr, 0), nonptr, code);
       if (base == error_mark_node)
        return base;
 
@@ -6273,12 +6275,14 @@ fold_offsetof_1 (tree expr, enum tree_co
       /* Handle static members of volatile structs.  */
       t = TREE_OPERAND (expr, 1);
       gcc_checking_assert (VAR_P (get_base_address (t)));
-      return fold_offsetof_1 (t);
+      return fold_offsetof_1 (t, nonptr);
 
     default:
       gcc_unreachable ();
     }
 
+  if (nonptr)
+    return size_binop (PLUS_EXPR, base, off);
   return fold_build_pointer_plus (base, off);
 }
 
@@ -6287,7 +6291,7 @@ fold_offsetof_1 (tree expr, enum tree_co
 tree
 fold_offsetof (tree expr)
 {
-  return convert (size_type_node, fold_offsetof_1 (expr));
+  return convert (size_type_node, fold_offsetof_1 (expr, true));
 }
 
 
--- gcc/testsuite/g++.dg/ext/offsetof2.C.jj     2018-05-05 10:58:22.796637643 
+0200
+++ gcc/testsuite/g++.dg/ext/offsetof2.C        2018-05-05 10:57:24.281623720 
+0200
@@ -0,0 +1,6 @@
+// PR c++/85662
+// { dg-do compile { target c++11 } }
+
+struct S { unsigned long x[31]; };
+struct T { bool b; S f; };
+static_assert (__builtin_offsetof (T, f.x[31 - 1]) == __builtin_offsetof (T, 
f.x[30]), "");

        Jakub

Reply via email to