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