On Tue, Oct 6, 2026 at 12:58 PM Jasper Niebuhr <[email protected]> wrote:
>
> On Tue, Oct 6, 2026 at 9:21 AM Richard Biener
> <[email protected]> wrote:
> >
> > On Mon, Oct 5, 2026 at 6:01 PM Jasper Niebuhr <[email protected]> wrote:
> > >
> > > On Mon, Oct 5, 2026 at 4:04 PM Richard Biener
> > > <[email protected]> wrote:
> > > >
> > > > On Mon, Oct 5, 2026 at 3:13 PM York Jasper Niebuhr 
> > > > <[email protected]> wrote:
> > > > >
> > > > > Hi,
> > > > > as mentioned today at the plumbers toolchain track, here is my 
> > > > > approach
> > > > > to tackling constant-folding issues regarding eBPF CORE and runtime
> > > > > structure layout randomization. I developed it to support the next
> > > > > iteration of Selfpatch-SLR and its linux kernel version:
> > > > >
> > > > > https://lore.kernel.org/all/[email protected]/
> > > > >
> > > > > The problem this addresses is that the frontend folds e.g.
> > > > > offsetof-builtin calls to constants, erasing any information on what
> > > > > fields contributed to the constant, and even that the constant depends
> > > > > on field offsets at all. This is obviously a problem when you want to
> > > > > finalize field offsets at a later time.
> > > > >
> > > > > For marked structures, this patch makes the frontend construct
> > > > > DEFERRED_CST_COMPONENT_REF nodes instead of normal COMPONENT_REFs.
> > > > > Deferred cst in this context means that something would usually be a
> > > > > compile-time constant and still behaves as one at runtime, but is not
> > > > > yet known.
> > > > >
> > > > > When fold_offsetof encounters these deferred cst component refs, it 
> > > > > does
> > > > > not just return a constant integer, but a DEFERRED_CST_EXPR around a
> > > > > tree that still holds the relevant semantic information. In this tree,
> > > > > each contributing deferred cst field offset is represented by a call 
> > > > > to
> > > > > a corresponding IFN.
> > > > >
> > > > > Additionally, I adapted c_fully_fold to merge true surrounding 
> > > > > constants
> > > > > into the DEFERRED_CST_EXPRs. For example, "4 + DEFERRED_CST_EXPR<x>"
> > > > > becomes "DEFERRED_CST_EXPR<4 + x>". When checking for constness in 
> > > > > some
> > > > > contexts, like in static initializers, DEFERRED_CST_EXPRs act as 
> > > > > opaque
> > > > > and report as valid in that context if -fdeferred-cst-static is set.
> > > > > This allows code such as:
> > > > >
> > > > >     struct A {
> > > > >         int x;
> > > > >     } __attribute__((deferred_cst_layout));
> > > > >
> > > > >     static const size_t x_offset = offsetof(struct A, x);
> > > > >
> > > > > Or:
> > > > >
> > > > >     struct cred *init_cred_ptr = &init_task.cred;
> > > > >
> > > > > Which would usually break when transformed to expressions that are not
> > > > > compile-time constants.
> > > > >
> > > > > Deferred constants are supported up to the deferred_cst_barrier pass,
> > > > > which runs at the very beginning of the small IPA passes, immediately
> > > > > after lowering. By default, the barrier will replace all deferred
> > > > > constants in gimple and static initializers with their true 
> > > > > compile-time
> > > > > values. If -fdeferred-cst-barrier-hard is set, the barrier will error
> > > > > instead, if any deferred constants still exist.
> > > > >
> > > > > The big idea here is that an IPA pass right before the barrier pass 
> > > > > can
> > > > > iterate over all functions and static initializers and turn all 
> > > > > deferred
> > > > > constant nodes into whatever is needed. For static initializers
> > > > > specifically, that pass can generate functions that recalculate and
> > > > > update the static data at runtime, by essentially copy pasting the
> > > > > trees under the DEFERRED_CST_EXPR and generating the according
> > > > > MODIFY_EXPRs. In the case of CORE, I guess you could even generate 
> > > > > info
> > > > > for the JIT on how to calculate the static values and fill them in.
> > > > >
> > > > > Anyways, after this actual instrumentation pass there should be no
> > > > > deferred constant nodes left so the hard barrier is happy.
> > > > >
> > > > > The way this currently applies to field offsets and offsetof
> > > > > specifically, I believe this could be expanded to also work for enum
> > > > > values, by producing something along the lines of:
> > > > >
> > > > >     DEFERRED_CST_EXPR<IFN_DEFERRED_CST_ENUM_VALUE(...)>
> > > > >
> > > > > I am looking forward for your input on this, and feel free to approach
> > > > > me at plumbers any time to talk about this.
> > > >
> > > > GCC already supports 'runtime layout' via PLACEHOLDER_EXPR and
> > > > a non-constant offset in the FIELD_DECL/COMPONENT_REF.  I don't think
> > > > we want a second mechanism for this.
> > > >
> > > > Richard.
> > >
> > > Hi,
> > > I should have clarified this better: this patch is not about the
> > > DEFERRED_CST_COMPONENT_REF, rather about deferred constants as a
> > > general frontend feature. The C frontend's fold_offsetof does not
> > > inspect the cached field offset of a COMPONENT_REF, but makes it
> > > disappear entirely. That is what forces libbpf to provide alternatives
> > > to offsetof.
> > >
> > > Besides them being inconveneient, these alternatives can not occur in
> > > static initializers, because builtin calls do not qualify as compile-
> > > time constants.
> > >
> > > Apart from field offsets, David mentioned earlier that they could also
> > > use this to handle enum values. By turning enum values into
> > >
> > >     DEFERRED_CST_EXPR<something_enum_value(MY_ENUM_LITERAL)>
> > >
> > > and treating that expr the way I described, a middle-end pass can
> > > reliably recover what enum the expression refers to, not just 42.
> > >
> > > So this mechanism is supposed to provide a way to preserve semantic
> > > origins of otherwise folded constants through frontends, without the
> > > frontends producing errors because they expect fully folded constants
> > > in some places. It is not supposed to be the 100th way of supporting
> > > "runtime layouts".
> > >
> > > And as far as I can tell, PLACEHOLDER_EXPR will not solve this problem
> > > in the C/C++ frontend either.
> >
> > I suppose you need to explain then what "runtime structure layout
> > randomization" is.
>
> The prototype I built for runtime structure layout randomization in C
> programs generates metadata that describes what instructions and data
> of a program image have to be patched to reflect different structure
> layouts. When the program starts (or the kernel boots), the SLR
> runtime shuffles structure layouts and applies the corresponding
> patches in-memory (rewriting immediates/displacements in the
> instruction stream, reordering static instances of randomized types,
> updating static data leaves that depend on changed field offsets).
>
> For this to not turn the image into a buggy mess, it is necessary that
> the toolchain correctly identifies and tracks every single dependency
> on field offsets that can change at runtime. For the most part, this
> means instrumenting COMPONENT_REFs in the mid-/back-end. But the
> front-end irreversably eradicates some relevant dependencies.
>
> For example, consider:
>
>     #define container_of(ptr, type, member) ({
>         void *__mptr = (void *)(ptr);
>         ((type *)(__mptr - offsetof(type, member))); })
>
> The frontend turns
>
>     base_t *base_ptr = container_of(field_ptr, base_t, field);
>
> into
>
>     base_t *base_ptr = field_ptr - <integer constant>;
>
> No following pass can identify this field offset dependency. And not
> generating corresponding patch information causes the program image
> to end up in a semantically invalid state.
>
> The DEFERRED_CST_COMPONENT_REF is a method to let fold_offsetof know
> when special handling is required, and to make sure no COMPONENT_REFs
> are lost elsewhere. However, all other cases I could find in which
> COMPONENT_REFs are folded do not constitute runtime offset
> dependencies. For exampe, it is not a problem if a
>
>     COMPONENT_REF<CONSTRUCTOR<...>>
>
> is folded to the corresponding constructor element, because there is
> no logic dependency on the offset itself. If there is really no other
> case besides fold_offsetof in which field offset dependencies are
> lost, DEFERRED_CST_COMPONENT_REFs are not required at all because
> fold_offsetof can simply check if the accessed type has the according
> attribute.
>
> So the real substance of this patch is the DEFERRED_CST_EXPR node and
> the selective permission for those to occur in contexts that usually
> require compile-time constants (like initializers). This does not
> implement runtime structure layout randomization, but is a toolchain
> requirement for it.
>
> And eBPF is a potential additional user of this. They have run into
> the same problem (frontend folding relevant info), recently regarding
> enums. Since the C frontend turns
>
>     enum E {
>         A, B, C, D
>     };
>
>     int something_with_C()
>     {
>         int x = C;
>         return x;
>     }
>
> into
>
>     ;; Function something_with_C (null)
>     ;; enabled by -tree-original
>
>     {
>       int x = 2;
>
>         int x = 2;
>       return x;
>     }
>
> a normal pass can not iterate over that function body and identify
> that the integer constant needs to be replaced by the eBPF loader to
> reflect a potentially different value for that specific enum literal.
>
> The only existing way to make this kind of info persist through the
> frontend is custom parser hooks that replace these would-be-constants
> with something not constant (builtin calls). This inevitably makes
> the C frontend error in contexts that do not permit non-constant
> expressions. Stuff like
>
>     static enum E e = C;
>
> breaks under such instrumentation. Additionally, these parser hooks
> are uncomfortably hacky and the deferred constant mechanism could
> solve this issue in a unified matter that allows language-independent
> instrumentation in the early middle-end.
>
> I hope this makes my intentions with this clearer.

To me this sounds like having 'offset relocations' and having the runtime
loader do such patching would be less error-prone and this would map
easier to a compile-time variable-layout state.  Of course static initializers
will necessarily become runtime initializers unless you invent some other
clever scheme for patching that.

Of course I question the value of this given it's at most obfuscation
(similar to ASLR).

That said, I now defer to C frontend people (but expect me back if this
ever gets to the point the middle-end will be involved).

Richard.

>
> Jasper.
>
> > Richard.
> >
> > >
> > > Jasper.
> > >
> > > > > Jasper
> > > > >
> > > > > Signed-off-by: York Jasper Niebuhr <[email protected]>
> > > > > ---
> > > > >  gcc/Makefile.in           |   4 +-
> > > > >  gcc/alias.cc              |   1 +
> > > > >  gcc/c-family/c-attribs.cc |  30 +-
> > > > >  gcc/c-family/c-common.cc  | 107 ++++++-
> > > > >  gcc/c/c-decl.cc           |   1 +
> > > > >  gcc/c/c-fold.cc           | 157 +++++++++-
> > > > >  gcc/c/c-typeck.cc         |  40 ++-
> > > > >  gcc/common.opt            |   8 +
> > > > >  gcc/deferred-cst.cc       | 626 
> > > > > ++++++++++++++++++++++++++++++++++++++
> > > > >  gcc/deferred-cst.h        |  39 +++
> > > > >  gcc/expr.cc               |  35 ++-
> > > > >  gcc/fold-const.cc         |  14 +
> > > > >  gcc/gimple-expr.cc        |   5 +
> > > > >  gcc/gimple.cc             |   3 +-
> > > > >  gcc/gimplify.cc           |  54 +++-
> > > > >  gcc/internal-fn.cc        |   9 +
> > > > >  gcc/internal-fn.def       |   3 +
> > > > >  gcc/passes.def            |   1 +
> > > > >  gcc/tree-pass.h           |   1 +
> > > > >  gcc/tree-pretty-print.cc  |  31 +-
> > > > >  gcc/tree.cc               |  19 +-
> > > > >  gcc/tree.def              |  13 +
> > > > >  gcc/tree.h                |   1 +
> > > > >  gcc/varasm.cc             |  18 +-
> > > > >  24 files changed, 1176 insertions(+), 44 deletions(-)
> > > > >  create mode 100644 gcc/deferred-cst.cc
> > > > >  create mode 100644 gcc/deferred-cst.h
> > > > >
> > > > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> > > > > index 8ecef4ccdc7..e70fe8dc21b 100644
> > > > > --- a/gcc/Makefile.in
> > > > > +++ b/gcc/Makefile.in
> > > > > @@ -1464,6 +1464,7 @@ OBJS = \
> > > > >         dce.o \
> > > > >         ddg.o \
> > > > >         debug.o \
> > > > > +       deferred-cst.o \
> > > > >         hierarchical_discriminator.o \
> > > > >         dep-fusion.o \
> > > > >         df-core.o \
> > > > > @@ -3163,6 +3164,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h 
> > > > > $(srcdir)/coretypes.h \
> > > > >    $(srcdir)/internal-fn.h \
> > > > >    $(srcdir)/calls.cc \
> > > > >    $(srcdir)/analyzer/analyzer-language.cc \
> > > > > +  $(srcdir)/deferred-cst.cc \
> > > > >    @all_gtfiles@
> > > > >
> > > > >  # Compute the list of GT header files from the corresponding C 
> > > > > sources,
> > > > > @@ -4173,7 +4175,7 @@ PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) 
> > > > > $(SYSTEM_H) coretypes.h $(TM_H) \
> > > > >    lcm.h cfgloopmanip.h file-prefix-map.h builtins.def $(INSN_ATTR_H) 
> > > > > \
> > > > >    pass-instances.def params.list 
> > > > > $(srcdir)/../include/gomp-constants.h \
> > > > >    $(EXPR_H) $(srcdir)/analyzer/*.h $(srcdir)/diagnostics/*.h \
> > > > > -  $(srcdir)/text-art/*.h $(srcdir)/topics/*.h
> > > > > +  $(srcdir)/text-art/*.h $(srcdir)/topics/*.h deferred-cst.h
> > > > >
> > > > >  # generate the 'build fragment' b-header-vars
> > > > >  s-header-vars: Makefile
> > > > > diff --git a/gcc/alias.cc b/gcc/alias.cc
> > > > > index 6e16b21327f..2d5d672a520 100644
> > > > > --- a/gcc/alias.cc
> > > > > +++ b/gcc/alias.cc
> > > > > @@ -618,6 +618,7 @@ ends_tbaa_access_path_p (const_tree t)
> > > > >    switch (TREE_CODE (t))
> > > > >      {
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >        if (DECL_NONADDRESSABLE_P (TREE_OPERAND (t, 1)))
> > > > >         return true;
> > > > >        /* Permit type-punning when accessing a union, provided the 
> > > > > access
> > > > > diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> > > > > index d437c55285e..a8dae5e7f52 100644
> > > > > --- a/gcc/c-family/c-attribs.cc
> > > > > +++ b/gcc/c-family/c-attribs.cc
> > > > > @@ -193,6 +193,8 @@ static tree 
> > > > > handle_null_terminated_string_arg_attribute (tree *, tree, tree, int
> > > > >  static tree handle_btf_decl_tag_attribute (tree *, tree, tree, int, 
> > > > > bool *);
> > > > >  static tree handle_btf_type_tag_attribute (tree *, tree, tree, int, 
> > > > > bool *);
> > > > >
> > > > > +static tree handle_deferred_cst_access_attribute (tree *, tree, 
> > > > > tree, int, bool *);
> > > > > +
> > > > >  /* Helper to define attribute exclusions.  */
> > > > >  #define ATTR_EXCL(name, function, type, variable)      \
> > > > >    { name, function, type, variable }
> > > > > @@ -667,7 +669,9 @@ const struct attribute_spec 
> > > > > c_common_gnu_attributes[] =
> > > > >    { "btf_type_tag",          1, 1, false, true, false, false,
> > > > >                               handle_btf_type_tag_attribute, NULL},
> > > > >    { "btf_decl_tag",          1, 1, true, false, false, false,
> > > > > -                             handle_btf_decl_tag_attribute, NULL}
> > > > > +                             handle_btf_decl_tag_attribute, NULL},
> > > > > +  { "deferred_cst_access",    0, 0, false, true, false, false,
> > > > > +                             handle_deferred_cst_access_attribute, 
> > > > > NULL }
> > > > >  };
> > > > >
> > > > >  const struct scoped_attribute_specs c_common_gnu_attribute_table =
> > > > > @@ -5292,6 +5296,30 @@ handle_btf_type_tag_attribute (tree *node, 
> > > > > tree name, tree args,
> > > > >    return NULL_TREE;
> > > > >  }
> > > > >
> > > > > +// TODO
> > > > > +
> > > > > +/* Handle the "deferred_cst_access" struct attribute.  */
> > > > > +
> > > > > +static tree
> > > > > +handle_deferred_cst_access_attribute (tree *node,
> > > > > +                                     tree name,
> > > > > +                                     tree ARG_UNUSED (args),
> > > > > +                                     int ARG_UNUSED (flags),
> > > > > +                                     bool *no_add_attrs)
> > > > > +{
> > > > > +  tree type = *node;
> > > > > +
> > > > > +  if (TREE_CODE (type) != RECORD_TYPE)
> > > > > +    {
> > > > > +      warning (OPT_Wattributes,
> > > > > +             "%qE attribute only applies to struct types",
> > > > > +             name);
> > > > > +      *no_add_attrs = true;
> > > > > +    }
> > > > > +
> > > > > +  return NULL_TREE;
> > > > > +}
> > > > > +
> > > > >  /* Handle the "nonstring" variable attribute.  */
> > > > >
> > > > >  static tree
> > > > > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> > > > > index 5acb221d31f..34a4ea7a0de 100644
> > > > > --- a/gcc/c-family/c-common.cc
> > > > > +++ b/gcc/c-family/c-common.cc
> > > > > @@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "gcc-rich-location.h"
> > > > >  #include "gcc-urlifier.h"
> > > > >  #include "diagnostics/diagnostics-selftests.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  cpp_reader *parse_in;          /* Declared in c-pragma.h.  */
> > > > >
> > > > > @@ -7217,13 +7218,32 @@ c_common_to_target_charset (HOST_WIDE_INT c)
> > > > >      return uc;
> > > > >  }
> > > > >
> > > > > +/* Helper for fold_offsetof_internal.  Add OFFSET to the ACCUMULATOR
> > > > > +   tree.  */
> > > > > +static void
> > > > > +accumulate_offset (tree *accumulator, tree offset)
> > > > > +{
> > > > > +  gcc_assert (accumulator);
> > > > > +  gcc_assert (offset);
> > > > > +
> > > > > +  offset = convert (sizetype, offset);
> > > > > +
> > > > > +  if (*accumulator == NULL_TREE)
> > > > > +    *accumulator = offset;
> > > > > +  else
> > > > > +    *accumulator = size_binop_loc (
> > > > > +      input_location, PLUS_EXPR, *accumulator, offset);
> > > > > +}
> > > > > +
> > > > >  /* 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.  TYPE is the 
> > > > > desired type of
> > > > > -   the whole expression.  Return the folded result.  */
> > > > > +   the whole expression.  Return the folded result.  NON_CST is set 
> > > > > to the
> > > > > +   sum of all non-constant portions of the offset.  DEFERRED is set 
> > > > > to the
> > > > > +   deferred constant portion of the offset.  */
> > > > >
> > > > > -tree
> > > > > -fold_offsetof (tree expr, tree type, enum tree_code ctx)
> > > > > +static tree
> > > > > +fold_offsetof_internal (tree expr, tree type, enum tree_code ctx, 
> > > > > tree *non_cst, tree *deferred)
> > > > >  {
> > > > >    tree base, off, t;
> > > > >    tree_code code = TREE_CODE (expr);
> > > > > @@ -7233,10 +7253,10 @@ fold_offsetof (tree expr, tree type, enum 
> > > > > tree_code ctx)
> > > > >        return expr;
> > > > >
> > > > >      case REALPART_EXPR:
> > > > > -     return fold_offsetof (TREE_OPERAND (expr, 0), type, code);
> > > > > +     return fold_offsetof_internal (TREE_OPERAND (expr, 0), type, 
> > > > > code, non_cst, deferred);
> > > > >
> > > > >      case IMAGPART_EXPR:
> > > > > -     base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
> > > > > +     base = fold_offsetof_internal (TREE_OPERAND (expr, 0), type, 
> > > > > code, non_cst, deferred);
> > > > >       if (base == error_mark_node)
> > > > >         return base;
> > > > >       off = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (expr, 
> > > > > 0))));
> > > > > @@ -7261,7 +7281,7 @@ fold_offsetof (tree expr, tree type, enum 
> > > > > tree_code ctx)
> > > > >        return convert (type, TREE_OPERAND (expr, 0));
> > > > >
> > > > >      case COMPONENT_REF:
> > > > > -      base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
> > > > > +      base = fold_offsetof_internal (TREE_OPERAND (expr, 0), type, 
> > > > > code, non_cst, deferred);
> > > > >        if (base == error_mark_node)
> > > > >         return base;
> > > > >
> > > > > @@ -7277,8 +7297,24 @@ fold_offsetof (tree expr, tree type, enum 
> > > > > tree_code ctx)
> > > > >                                       / BITS_PER_UNIT));
> > > > >        break;
> > > > >
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      base = fold_offsetof_internal (TREE_OPERAND (expr, 0), type, 
> > > > > code, non_cst, deferred);
> > > > > +      if (base == error_mark_node)
> > > > > +       return base;
> > > > > +
> > > > > +      t = TREE_OPERAND (expr, 1);
> > > > > +      if (DECL_C_BIT_FIELD (t))
> > > > > +       {
> > > > > +         error_at (EXPR_LOCATION (expr),
> > > > > +                   "attempt to take address of bit-field structure 
> > > > > member");
> > > > > +         return error_mark_node;
> > > > > +       }
> > > > > +      t = deferred_cst_call_ifn_field_offset (EXPR_LOCATION (expr), 
> > > > > t);
> > > > > +      accumulate_offset (deferred, t);
> > > > > +      return base;
> > > > > +
> > > > >      case ARRAY_REF:
> > > > > -      base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
> > > > > +      base = fold_offsetof_internal (TREE_OPERAND (expr, 0), type, 
> > > > > code, non_cst, deferred);
> > > > >        if (base == error_mark_node)
> > > > >         return base;
> > > > >
> > > > > @@ -7330,13 +7366,26 @@ fold_offsetof (tree expr, tree type, enum 
> > > > > tree_code ctx)
> > > > >
> > > > >        t = convert (sizetype, t);
> > > > >        off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE 
> > > > > (expr)), t);
> > > > > +
> > > > > +      /* For classification as cst/non-cst, the array index has to be
> > > > > +         fully folded.  */
> > > > > +      off = c_fully_fold(off, false, NULL);
> > > > > +
> > > > > +      if (off == error_mark_node)
> > > > > +       return off;
> > > > > +
> > > > > +      if (!TREE_CONSTANT (off))
> > > > > +       {
> > > > > +         accumulate_offset (non_cst, off);
> > > > > +         return base;
> > > > > +       }
> > > > >        break;
> > > > >
> > > > >      case COMPOUND_EXPR:
> > > > >        /* Handle static members of volatile structs.  */
> > > > >        t = TREE_OPERAND (expr, 1);
> > > > >        gcc_checking_assert (VAR_P (get_base_address (t)));
> > > > > -      return fold_offsetof (t, type);
> > > > > +      return fold_offsetof_internal (t, type, ERROR_MARK, non_cst, 
> > > > > deferred);
> > > > >
> > > > >      default:
> > > > >        gcc_unreachable ();
> > > > > @@ -7346,6 +7395,48 @@ fold_offsetof (tree expr, tree type, enum 
> > > > > tree_code ctx)
> > > > >      return size_binop (PLUS_EXPR, base, convert (type, off));
> > > > >    return fold_build_pointer_plus (base, off);
> > > > >  }
> > > > > +
> > > > > +/* Like fold_offsetof_internal, but integrates deferred constant 
> > > > > components
> > > > > +   into the result.  If such components exist, the result is wrapped 
> > > > > in a
> > > > > +   DEFERRED_CST_EXPR node.  */
> > > > > +
> > > > > +tree
> > > > > +fold_offsetof (tree expr, tree type, enum tree_code ctx)
> > > > > +{
> > > > > +  tree res = NULL_TREE;
> > > > > +  tree non_cst = NULL_TREE;
> > > > > +  tree deferred = NULL_TREE;
> > > > > +  tree cst = fold_offsetof_internal (expr, type, ctx, &non_cst, 
> > > > > &deferred);
> > > > > +
> > > > > +  res = cst;
> > > > > +
> > > > > +  if (res == error_mark_node)
> > > > > +    return res;
> > > > > +
> > > > > +  /* DEFERRED_CST_EXPRs contain only ordinary constants and deferred
> > > > > +     constant components.  */
> > > > > +  if (deferred != NULL_TREE)
> > > > > +    {
> > > > > +      if (POINTER_TYPE_P (type))
> > > > > +       res = fold_build_pointer_plus (res, convert (sizetype, 
> > > > > deferred));
> > > > > +      else
> > > > > +       res = size_binop (PLUS_EXPR, res, convert (type, deferred));
> > > > > +
> > > > > +      res = deferred_cst_build_expr (res);
> > > > > +    }
> > > > > +
> > > > > +  /* Runtime-dependent terms are added only after the deferred
> > > > > +     boundary has been constructed.  */
> > > > > +  if (non_cst != NULL_TREE)
> > > > > +    {
> > > > > +      if (POINTER_TYPE_P (type))
> > > > > +       res = fold_build_pointer_plus (res, convert (type, non_cst));
> > > > > +      else
> > > > > +       res = size_binop (PLUS_EXPR, res, convert (type, non_cst));
> > > > > +    }
> > > > > +
> > > > > +  return res;
> > > > > +}
> > > > >
> > > > >  /* *PTYPE is an incomplete array.  Complete it with a domain based on
> > > > >     INITIAL_VALUE.  If INITIAL_VALUE is not present, use 1 if 
> > > > > DO_DEFAULT
> > > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > > index 8a894de3a1b..62da65e0efb 100644
> > > > > --- a/gcc/c/c-decl.cc
> > > > > +++ b/gcc/c/c-decl.cc
> > > > > @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "omp-offload.h"  /* For offload_vars.  */
> > > > >  #include "c-parser.h"
> > > > >  #include "gcc-urlifier.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  #include "tree-pretty-print.h"
> > > > >
> > > > > diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
> > > > > index 122049daf87..f333a33153c 100644
> > > > > --- a/gcc/c/c-fold.cc
> > > > > +++ b/gcc/c/c-fold.cc
> > > > > @@ -26,9 +26,11 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "c-tree.h"
> > > > >  #include "intl.h"
> > > > >  #include "gimplify.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  static tree c_fully_fold_internal (tree expr, bool, bool *, bool *, 
> > > > > bool,
> > > > >                                    bool);
> > > > > +static tree c_fully_fold_deferred_cst_internal (tree expr);
> > > > >
> > > > >  /* If DISABLE is true, stop issuing warnings.  This is used when
> > > > >     parsing code that we know will not be executed.  This function may
> > > > > @@ -125,6 +127,7 @@ c_fully_fold (tree expr, bool in_init, bool 
> > > > > *maybe_const, bool lval)
> > > > >      }
> > > > >    ret = c_fully_fold_internal (expr, in_init, maybe_const,
> > > > >                                &maybe_const_itself, false, lval);
> > > > > +  ret = c_fully_fold_deferred_cst_internal (ret);
> > > > >    if (eptype)
> > > > >      ret = fold_convert_loc (loc, eptype, ret);
> > > > >    *maybe_const &= maybe_const_itself;
> > > > > @@ -258,14 +261,22 @@ c_fully_fold_internal (tree expr, bool in_init, 
> > > > > bool *maybe_const_operands,
> > > > >        goto out;
> > > > >
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >        orig_op0 = op0 = TREE_OPERAND (expr, 0);
> > > > >        op1 = TREE_OPERAND (expr, 1);
> > > > > -      op2 = TREE_OPERAND (expr, 2);
> > > > > +      if (code == COMPONENT_REF)
> > > > > +       op2 = TREE_OPERAND (expr, 2);
> > > > >        op0 = c_fully_fold_internal (op0, in_init, 
> > > > > maybe_const_operands,
> > > > >                                    maybe_const_itself, for_int_const, 
> > > > > lval);
> > > > >        STRIP_TYPE_NOPS (op0);
> > > > >        if (op0 != orig_op0)
> > > > > -       ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2);
> > > > > +       {
> > > > > +         if (code == COMPONENT_REF)
> > > > > +           ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, 
> > > > > op2);
> > > > > +         else
> > > > > +           ret = deferred_cst_build_component_ref (TREE_TYPE (expr),
> > > > > +                                                   op0, op1);
> > > > > +       }
> > > > >        if (ret != expr)
> > > > >         {
> > > > >           TREE_READONLY (ret) = TREE_READONLY (expr);
> > > > > @@ -720,6 +731,148 @@ c_fully_fold_internal (tree expr, bool in_init, 
> > > > > bool *maybe_const_operands,
> > > > >    return ret;
> > > > >  }
> > > > >
> > > > > +/* Internal helper for c_fully_fold.  Fold surrounding constant
> > > > > +   operations into DEFERRED_CST_EXPR nodes.
> > > > > +
> > > > > +   An operation is absorbed when:
> > > > > +
> > > > > +     - its tree code is explicitly supported by
> > > > > +       deferred_cst_operator_p;
> > > > > +     - every operand is constant-like; and
> > > > > +     - at least one operand is a DEFERRED_CST_EXPR.
> > > > > +
> > > > > +   Existing deferred wrappers are removed when an operation is 
> > > > > absorbed,
> > > > > +   giving a single outer DEFERRED_CST_EXPR.  For example:
> > > > > +
> > > > > +       DEFERRED_CST_EXPR (A) + 1
> > > > > +        -> DEFERRED_CST_EXPR (A + 1)
> > > > > +
> > > > > +       (DEFERRED_CST_EXPR (A) + 1) * 2
> > > > > +        -> DEFERRED_CST_EXPR ((A + 1) * 2)
> > > > > +
> > > > > +       DEFERRED_CST_EXPR (A) + DEFERRED_CST_EXPR (B)
> > > > > +        -> DEFERRED_CST_EXPR (A + B)
> > > > > +
> > > > > +       DEFERRED_CST_EXPR (C) ? 1 : 2
> > > > > +        -> DEFERRED_CST_EXPR (C ? 1 : 2)
> > > > > +
> > > > > +   An operation involving a nonconstant operand is not absorbed:
> > > > > +
> > > > > +       X + DEFERRED_CST_EXPR (A)
> > > > > +        -> X + DEFERRED_CST_EXPR (A)  */
> > > > > +
> > > > > +static tree
> > > > > +c_fully_fold_deferred_cst_internal (tree expr)
> > > > > +{
> > > > > +  if (expr == NULL_TREE)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  enum tree_code code = TREE_CODE (expr);
> > > > > +
> > > > > +  /* The true constants inside deferred constants can be folded here,
> > > > > +     while the deferred components are represented as calls to
> > > > > +     internal functions and thus can not and should not be folded
> > > > > +     here.  */
> > > > > +  if (code == DEFERRED_CST_EXPR)
> > > > > +  {
> > > > > +    tree old_inner = TREE_OPERAND (expr, 0);
> > > > > +
> > > > > +    bool maybe_const_operands = true;
> > > > > +    bool maybe_const_itself = true;
> > > > > +
> > > > > +    tree inner
> > > > > +      = c_fully_fold_internal (old_inner, false,
> > > > > +                              &maybe_const_operands,
> > > > > +                              &maybe_const_itself,
> > > > > +                              false, false);
> > > > > +
> > > > > +    if (inner == old_inner)
> > > > > +      return expr;
> > > > > +
> > > > > +    return deferred_cst_build_expr (inner);
> > > > > +  }
> > > > > +
> > > > > +  /* Unsupported operations form a boundary for deferred folding.  */
> > > > > +  if (!deferred_cst_operator_p (code))
> > > > > +    return expr;
> > > > > +
> > > > > +  int nops = TREE_OPERAND_LENGTH (expr);
> > > > > +
> > > > > +  /* Every currently-supported operator has at most three operands.  
> > > > > */
> > > > > +  gcc_assert (nops >= 1 && nops <= 3);
> > > > > +
> > > > > +  tree ops[3];
> > > > > +  bool changed = false;
> > > > > +  bool has_deferred = false;
> > > > > +  bool all_constant = true;
> > > > > +  bool has_side_effects = false;
> > > > > +
> > > > > +  for (int i = 0; i < nops; ++i)
> > > > > +    {
> > > > > +      tree old_op = TREE_OPERAND (expr, i);
> > > > > +      tree op = c_fully_fold_deferred_cst_internal (old_op);
> > > > > +
> > > > > +      ops[i] = op;
> > > > > +
> > > > > +      if (op != old_op)
> > > > > +       changed = true;
> > > > > +
> > > > > +      if (TREE_CODE (op) == DEFERRED_CST_EXPR)
> > > > > +       has_deferred = true;
> > > > > +      else if (!TREE_CONSTANT (op))
> > > > > +       all_constant = false;
> > > > > +
> > > > > +      if (TREE_SIDE_EFFECTS (op))
> > > > > +       has_side_effects = true;
> > > > > +    }
> > > > > +
> > > > > +  /* There is no deferred expression directly participating in this
> > > > > +     operation, or there are non-constant operands or operands with
> > > > > +     side effects involved, so the operation itself must not become
> > > > > +     deferred.
> > > > > +
> > > > > +     We may nevertheless need to propagate a transformation made in 
> > > > > one
> > > > > +     of the operands.  */
> > > > > +  if (!has_deferred || !all_constant || has_side_effects)
> > > > > +    {
> > > > > +      if (!changed)
> > > > > +       return expr;
> > > > > +
> > > > > +      tree copy = copy_node (expr);
> > > > > +      for (int i = 0; i < nops; i++)
> > > > > +       TREE_OPERAND (copy, i) = ops[i];
> > > > > +
> > > > > +      return copy;
> > > > > +    }
> > > > > +
> > > > > +  /* Every operand is constant-like and at least one operand is
> > > > > +     deferred.  Move this complete operation inside one deferred
> > > > > +     wrapper.  */
> > > > > +
> > > > > +  tree inner = copy_node (expr);
> > > > > +  for (int i = 0; i < nops; i++)
> > > > > +    {
> > > > > +      bool op_deferred_cst = ops[i] != NULL_TREE
> > > > > +                            && TREE_CODE (ops[i]) == 
> > > > > DEFERRED_CST_EXPR;
> > > > > +      TREE_OPERAND (inner, i) = op_deferred_cst
> > > > > +                               ? TREE_OPERAND (ops[i], 0) : ops[i];
> > > > > +    }
> > > > > +
> > > > > +  bool maybe_const_operands = true;
> > > > > +  bool maybe_const_itself = true;
> > > > > +
> > > > > +  /* The true constants inside deferred constants can be folded here,
> > > > > +     while the deferred components are represented as calls to
> > > > > +     internal functions and thus can not and should not be folded
> > > > > +     here.  */
> > > > > +  inner = c_fully_fold_internal (inner, false,
> > > > > +                                &maybe_const_operands,
> > > > > +                                &maybe_const_itself,
> > > > > +                                false, false);
> > > > > +
> > > > > +  return deferred_cst_build_expr (inner);
> > > > > +}
> > > > > +
> > > > >  /* Fold X for consideration by one of the warning functions when 
> > > > > checking
> > > > >     whether an expression has a constant value.  */
> > > > >
> > > > > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> > > > > index aa368a6e95a..4d9c0179b29 100644
> > > > > --- a/gcc/c/c-typeck.cc
> > > > > +++ b/gcc/c/c-typeck.cc
> > > > > @@ -55,6 +55,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "realmpfr.h"
> > > > >  #include "tree-pretty-print-markup.h"
> > > > >  #include "gcc-urlifier.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  /* Possible cases of implicit conversions.  Used to select 
> > > > > diagnostic messages
> > > > >     and control folding initializers in convert_for_assignment.  */
> > > > > @@ -2290,6 +2291,19 @@ c_size_in_bytes (const_tree type)
> > > > >                                    / BITS_PER_UNIT));
> > > > >  }
> > > > >
> > > > > +/* Return true if INIT is a valid deferred constant initializer.  */
> > > > > +static bool
> > > > > +deferred_constant_initializer_p (tree init)
> > > > > +{
> > > > > +  if (!flag_deferred_cst_static
> > > > > +      || !init
> > > > > +      || !deferred_cst_present_p (init))
> > > > > +    return false;
> > > > > +
> > > > > +  return initializer_constant_valid_p (init, TREE_TYPE (init))
> > > > > +        != NULL_TREE;
> > > > > +}
> > > > > +
> > > > >  /* Return either DECL or its known constant value (if it has one).  
> > > > > */
> > > > >
> > > > >  tree
> > > > > @@ -2304,7 +2318,8 @@ decl_constant_value_1 (tree decl, bool in_init)
> > > > >        /* This is invalid if initial value is not constant.
> > > > >          If it has either a function call, a memory reference,
> > > > >          or a variable, then re-evaluating it could give different 
> > > > > results.  */
> > > > > -      && TREE_CONSTANT (DECL_INITIAL (decl))
> > > > > +      && (TREE_CONSTANT (DECL_INITIAL (decl))
> > > > > +         || deferred_constant_initializer_p (DECL_INITIAL (decl)))
> > > > >        /* Check for cases where this is sub-optimal, even though 
> > > > > valid.  */
> > > > >        && (in_init || TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR))
> > > > >      return DECL_INITIAL (decl);
> > > > > @@ -3199,9 +3214,14 @@ build_counted_by_ref (tree datum, tree 
> > > > > subdatum,
> > > > >        /* Get the TYPE of the counted_by field.  */
> > > > >        *counted_by_type = TREE_TYPE (counted_by_subdatum);
> > > > >
> > > > > -      counted_by_ref
> > > > > -       = build3 (COMPONENT_REF, TREE_TYPE (counted_by_subdatum),
> > > > > -                 datum, counted_by_subdatum, NULL_TREE);
> > > > > +      if (deferred_cst_field_p (counted_by_subdatum))
> > > > > +       counted_by_ref
> > > > > +         = deferred_cst_build_component_ref (TREE_TYPE 
> > > > > (counted_by_subdatum),
> > > > > +                                             datum, 
> > > > > counted_by_subdatum);
> > > > > +      else
> > > > > +       counted_by_ref
> > > > > +         = build3 (COMPONENT_REF, TREE_TYPE (counted_by_subdatum),
> > > > > +                   datum, counted_by_subdatum, NULL_TREE);
> > > > >
> > > > >        datum = counted_by_ref;
> > > > >        counted_by_field = TREE_CHAIN (counted_by_field);
> > > > > @@ -3422,8 +3442,11 @@ build_component_ref (location_t loc, tree 
> > > > > datum, tree component,
> > > > >             quals |= TYPE_QUALS (TREE_TYPE (datum));
> > > > >           subtype = c_build_qualified_type (TREE_TYPE (subdatum), 
> > > > > quals);
> > > > >
> > > > > -         ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
> > > > > -                       NULL_TREE);
> > > > > +         if (deferred_cst_field_p (subdatum))
> > > > > +           ref = deferred_cst_build_component_ref (subtype, datum, 
> > > > > subdatum);
> > > > > +         else
> > > > > +           ref = build3 (COMPONENT_REF, subtype, datum, subdatum,
> > > > > +                         NULL_TREE);
> > > > >           SET_EXPR_LOCATION (ref, loc);
> > > > >
> > > > >           check_counted_by_attribute (loc, ref);
> > > > > @@ -6364,6 +6387,7 @@ lvalue_p (const_tree ref)
> > > > >      case REALPART_EXPR:
> > > > >      case IMAGPART_EXPR:
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >        return lvalue_p (TREE_OPERAND (ref, 0));
> > > > >
> > > > >      case C_MAYBE_CONST_EXPR:
> > > > > @@ -10209,7 +10233,9 @@ digest_init (location_t init_loc, tree decl, 
> > > > > tree type, tree init,
> > > > >        /* Check to see if we have already given an error message.  */
> > > > >        if (inside_init == error_mark_node)
> > > > >         ;
> > > > > -      else if (require_constant && !TREE_CONSTANT (inside_init))
> > > > > +      else if (require_constant
> > > > > +              && !TREE_CONSTANT (inside_init)
> > > > > +              && !deferred_constant_initializer_p (inside_init))
> > > > >         {
> > > > >           error_init (init_loc, "initializer element is not 
> > > > > constant");
> > > > >           inside_init = error_mark_node;
> > > > > diff --git a/gcc/common.opt b/gcc/common.opt
> > > > > index 5d0e255a40d..648b0cb193f 100644
> > > > > --- a/gcc/common.opt
> > > > > +++ b/gcc/common.opt
> > > > > @@ -3675,6 +3675,14 @@ Enum(zero_init_padding_bits_kind) 
> > > > > String(unions) Value(ZERO_INIT_PADDING_BITS_UN
> > > > >  EnumValue
> > > > >  Enum(zero_init_padding_bits_kind) String(all) 
> > > > > Value(ZERO_INIT_PADDING_BITS_ALL)
> > > > >
> > > > > +fdeferred-cst-static
> > > > > +Common Var(flag_deferred_cst_static) Init(0)
> > > > > +Allow deferred constants to appear in static data.
> > > > > +
> > > > > +fdeferred-cst-barrier-hard
> > > > > +Common Var(flag_deferred_cst_barrier_hard) Init(0)
> > > > > +Make deferred-cst-barrier ICE if deferred constants remain.
> > > > > +
> > > > >  g
> > > > >  Common Driver RejectNegative JoinedOrMissing
> > > > >  Generate debug information in default format.
> > > > > diff --git a/gcc/deferred-cst.cc b/gcc/deferred-cst.cc
> > > > > new file mode 100644
> > > > > index 00000000000..bec14508484
> > > > > --- /dev/null
> > > > > +++ b/gcc/deferred-cst.cc
> > > > > @@ -0,0 +1,626 @@
> > > > > +#include "config.h"
> > > > > +#include "system.h"
> > > > > +#include "coretypes.h"
> > > > > +#include "tree.h"
> > > > > +#include "stringpool.h"
> > > > > +#include "fold-const.h"
> > > > > +#include "internal-fn.h"
> > > > > +#include "attribs.h"
> > > > > +#include "tree-pass.h"
> > > > > +#include "context.h"
> > > > > +#include "cgraph.h"
> > > > > +#include "function.h"
> > > > > +#include "cfg.h"
> > > > > +#include "basic-block.h"
> > > > > +#include "gimple.h"
> > > > > +#include "gimple-iterator.h"
> > > > > +#include "gimple-walk.h"
> > > > > +#include "diagnostic.h"
> > > > > +
> > > > > +#include "deferred-cst.h"
> > > > > +
> > > > > +/* Weak mapping from STRING_CST tokens used as arguments to
> > > > > +   IFN_DEFERRED_CST_FIELD_OFFSET to the FIELD_DECL whose byte offset
> > > > > +   the call represents.
> > > > > +
> > > > > +   For an ordinary field the value is that field's FIELD_DECL.
> > > > > +
> > > > > +   For a bit-field the value is DECL_BIT_FIELD_REPRESENTATIVE 
> > > > > (field),
> > > > > +   since IFN_DEFERRED_CST_FIELD_OFFSET describes the byte offset of
> > > > > +   the whole bit-field representative rather than the individual
> > > > > +   field.  */
> > > > > +static GTY((cache)) tree_cache_map *field_offset_field_decls;
> > > > > +
> > > > > +/* Used only to make STRING_CST contents unique.  The actual string 
> > > > > value has
> > > > > +   no semantic meaning; the STRING_CST node itself is the metadata 
> > > > > token.  */
> > > > > +static unsigned HOST_WIDE_INT next_field_offset_token = 0;
> > > > > +
> > > > > +/* Return true if TYPE is a record carrying
> > > > > +   __attribute__((deferred_cst_access)).  */
> > > > > +bool
> > > > > +deferred_cst_access_type_p (tree type)
> > > > > +{
> > > > > +  return (type
> > > > > +         && TREE_CODE (type) == RECORD_TYPE
> > > > > +         && lookup_attribute ("deferred_cst_access",
> > > > > +                              TYPE_ATTRIBUTES (type)) != NULL_TREE);
> > > > > +}
> > > > > +
> > > > > +bool
> > > > > +deferred_cst_field_p (tree field)
> > > > > +{
> > > > > +  if (!field || TREE_CODE (field) != FIELD_DECL)
> > > > > +    return false;
> > > > > +
> > > > > +  return deferred_cst_access_type_p (DECL_CONTEXT (field));
> > > > > +}
> > > > > +
> > > > > +/* Return true if CODE is an operation which may be absorbed into a
> > > > > +   DEFERRED_CST_EXPR.
> > > > > +
> > > > > +   This is deliberately an explicit whitelist.  In particular, do not
> > > > > +   absorb arbitrary unary/binary/reference tree codes merely because 
> > > > > all
> > > > > +   of their operands happen to be constant.  */
> > > > > +bool
> > > > > +deferred_cst_operator_p (enum tree_code code)
> > > > > +{
> > > > > +  switch (code)
> > > > > +    {
> > > > > +    /* Binary arithmetic operations.  */
> > > > > +    case PLUS_EXPR:
> > > > > +    case MINUS_EXPR:
> > > > > +    case MULT_EXPR:
> > > > > +    case POINTER_PLUS_EXPR:
> > > > > +    case POINTER_DIFF_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 LROTATE_EXPR:
> > > > > +    case RROTATE_EXPR:
> > > > > +    case BIT_IOR_EXPR:
> > > > > +    case BIT_XOR_EXPR:
> > > > > +    case BIT_AND_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    /* Comparisons.  */
> > > > > +    case LT_EXPR:
> > > > > +    case LE_EXPR:
> > > > > +    case GT_EXPR:
> > > > > +    case GE_EXPR:
> > > > > +    case EQ_EXPR:
> > > > > +    case NE_EXPR:
> > > > > +    case UNORDERED_EXPR:
> > > > > +    case ORDERED_EXPR:
> > > > > +    case UNLT_EXPR:
> > > > > +    case UNLE_EXPR:
> > > > > +    case UNGT_EXPR:
> > > > > +    case UNGE_EXPR:
> > > > > +    case UNEQ_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    /* Boolean operations.
> > > > > +
> > > > > +       TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR retain their 
> > > > > short-circuit
> > > > > +       semantics inside the deferred expression.  Nothing is 
> > > > > evaluated
> > > > > +       when absorbing expressions into deferred constants.  */
> > > > > +    case TRUTH_AND_EXPR:
> > > > > +    case TRUTH_OR_EXPR:
> > > > > +    case TRUTH_XOR_EXPR:
> > > > > +    case TRUTH_ANDIF_EXPR:
> > > > > +    case TRUTH_ORIF_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    /* Unary arithmetic and conversions.  */
> > > > > +    case FIX_TRUNC_EXPR:
> > > > > +    case FLOAT_EXPR:
> > > > > +    CASE_CONVERT:
> > > > > +    case ADDR_SPACE_CONVERT_EXPR:
> > > > > +    case NON_LVALUE_EXPR:
> > > > > +    case NEGATE_EXPR:
> > > > > +    case BIT_NOT_EXPR:
> > > > > +    case TRUTH_NOT_EXPR:
> > > > > +    case CONJ_EXPR:
> > > > > +    case REALPART_EXPR:
> > > > > +    case IMAGPART_EXPR:
> > > > > +    case VIEW_CONVERT_EXPR:
> > > > > +    case PAREN_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    case COMPLEX_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    /* Conditional expressions.  These are absorbed only when the
> > > > > +       condition and both alternatives are all constant-like.  */
> > > > > +    case COND_EXPR:
> > > > > +    case VEC_COND_EXPR:
> > > > > +      return true;
> > > > > +
> > > > > +    default:
> > > > > +      return false;
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +tree
> > > > > +deferred_cst_build_component_ref (tree type, tree base, tree field)
> > > > > +{
> > > > > +  gcc_assert (field);
> > > > > +  gcc_assert (TREE_CODE (field) == FIELD_DECL);
> > > > > +
> > > > > +  return build2 (DEFERRED_CST_COMPONENT_REF, type, base, field);
> > > > > +}
> > > > > +
> > > > > +tree
> > > > > +deferred_cst_build_expr (tree expr)
> > > > > +{
> > > > > +  /* TODO assert that expr is actually a deferred constant  */
> > > > > +  return build1_loc (EXPR_LOCATION (expr), DEFERRED_CST_EXPR,
> > > > > +                    TREE_TYPE (expr), expr);
> > > > > +}
> > > > > +
> > > > > +/* Create a unique STRING_CST to use as a metadata token.  */
> > > > > +static tree
> > > > > +make_token (const char *name, unsigned HOST_WIDE_INT id)
> > > > > +{
> > > > > +  char buf[128];
> > > > > +
> > > > > +  int len = snprintf (buf, sizeof (buf),
> > > > > +                     "__deferred_cst_token_%s_"
> > > > > +                     HOST_WIDE_INT_PRINT_UNSIGNED,
> > > > > +                     name, id);
> > > > > +
> > > > > +  gcc_assert (len > 0);
> > > > > +  gcc_assert ((unsigned int) len < sizeof (buf));
> > > > > +
> > > > > +  /* Include the trailing NUL.  */
> > > > > +  unsigned int string_len = len + 1;
> > > > > +
> > > > > +  tree token = build_string (string_len, buf);
> > > > > +
> > > > > +  TREE_TYPE (token)
> > > > > +    = build_array_type_nelts (char_type_node, string_len);
> > > > > +
> > > > > +  return token;
> > > > > +}
> > > > > +
> > > > > +/* Generate a new key token into field_offset_field_decls and store
> > > > > +   the FIELD_DECL FIELD under it.  Return the new token.  */
> > > > > +static tree
> > > > > +register_field_offset_field_decl (tree field)
> > > > > +{
> > > > > +  tree token = make_token ("field_offset", 
> > > > > next_field_offset_token++);
> > > > > +
> > > > > +  if (!field_offset_field_decls)
> > > > > +    field_offset_field_decls = tree_cache_map::create_ggc ();
> > > > > +
> > > > > +  bool existed = field_offset_field_decls->put (token, field);
> > > > > +
> > > > > +  /* Every token created above is unique.  */
> > > > > +  gcc_assert (!existed);
> > > > > +
> > > > > +  return token;
> > > > > +}
> > > > > +
> > > > > +/* Look up the field declaration associated with a token argument of
> > > > > +   IFN_DEFERRED_CST_FIELD_OFFSET.  */
> > > > > +static tree
> > > > > +lookup_field_offset_field_decl (tree token)
> > > > > +{
> > > > > +  if (!token)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  tree *slot
> > > > > +    = field_offset_field_decls
> > > > > +      ? field_offset_field_decls->get (token)
> > > > > +      : NULL;
> > > > > +
> > > > > +  return slot ? *slot : NULL_TREE;
> > > > > +}
> > > > > +
> > > > > +/* Create a call to IFN_DEFERRED_CST_FIELD_OFFSET for the physical,
> > > > > +   addressable FIELD whose byte offset is deferred.
> > > > > +
> > > > > +   FIELD must not be a bit-field.  Callers handling bit-fields must 
> > > > > pass
> > > > > +   DECL_BIT_FIELD_REPRESENTATIVE (field).
> > > > > +
> > > > > +   Internally, these call hold the field declarations in a side-map
> > > > > +   keyed by tokens used as call arguments.  */
> > > > > +tree
> > > > > +deferred_cst_call_ifn_field_offset (location_t loc, tree field)
> > > > > +{
> > > > > +  gcc_assert (field);
> > > > > +  gcc_assert (TREE_CODE (field) == FIELD_DECL);
> > > > > +  gcc_assert (!DECL_BIT_FIELD (field));
> > > > > +
> > > > > +  tree token = register_field_offset_field_decl (field);
> > > > > +
> > > > > +  return build_call_expr_internal_loc (loc,
> > > > > +                                      IFN_DEFERRED_CST_FIELD_OFFSET,
> > > > > +                                      sizetype, 1, token);
> > > > > +}
> > > > > +
> > > > > +tree
> > > > > +deferred_cst_ifn_field_offset_field (tree token)
> > > > > +{
> > > > > +  if (!token)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  return lookup_field_offset_field_decl (token);
> > > > > +}
> > > > > +
> > > > > +static tree
> > > > > +find_deferred_cst_node (tree *tp, int *walk_subtrees, void *)
> > > > > +{
> > > > > +  tree node = *tp;
> > > > > +
> > > > > +  if (!node)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  switch (TREE_CODE (node))
> > > > > +    {
> > > > > +    case DEFERRED_CST_EXPR:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      *walk_subtrees = 0;
> > > > > +      return node;
> > > > > +
> > > > > +    default:
> > > > > +      break;
> > > > > +    }
> > > > > +
> > > > > +  /* Declarations and types are metadata here. Do not walk into their
> > > > > +     contexts, types, or initializers.  */
> > > > > +  if (DECL_P (node) || TYPE_P (node))
> > > > > +    *walk_subtrees = 0;
> > > > > +
> > > > > +  return NULL_TREE;
> > > > > +}
> > > > > +
> > > > > +bool
> > > > > +deferred_cst_present_p (tree expr)
> > > > > +{
> > > > > +  if (!expr)
> > > > > +    return false;
> > > > > +
> > > > > +  tree root = expr;
> > > > > +
> > > > > +  return walk_tree_without_duplicates (
> > > > > +          &root,
> > > > > +          find_deferred_cst_node,
> > > > > +          NULL)
> > > > > +        != NULL_TREE;
> > > > > +}
> > > > > +
> > > > > +/* Replace deferred cst components under DEFERRED_CST_EXPR nodes with
> > > > > +   their compile-time values.
> > > > > +
> > > > > +   Calls to IFN_DEFERRED_CST_FIELD_OFFSET become the compile-time
> > > > > +   field offsets.
> > > > > +
> > > > > +   Return NULL_TREE if no operation took place.  ICE if a 
> > > > > substitution
> > > > > +   failed.  */
> > > > > +static tree
> > > > > +substitute_deferred_cst_component (tree expr)
> > > > > +{
> > > > > +  if (!expr)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  location_t loc = EXPR_LOCATION (expr);
> > > > > +
> > > > > +  if (TREE_CODE (expr) == CALL_EXPR)
> > > > > +    {
> > > > > +      if (CALL_EXPR_IFN (expr) == IFN_DEFERRED_CST_FIELD_OFFSET)
> > > > > +       {
> > > > > +         gcc_assert (call_expr_nargs (expr) == 1);
> > > > > +         tree field
> > > > > +           = deferred_cst_ifn_field_offset_field (
> > > > > +                           CALL_EXPR_ARG (expr, 0));
> > > > > +
> > > > > +         gcc_assert (field && TREE_CODE (field) == FIELD_DECL);
> > > > > +
> > > > > +         tree offset = byte_position (field);
> > > > > +         return fold_convert_loc (loc, TREE_TYPE (expr), offset);
> > > > > +       }
> > > > > +    }
> > > > > +
> > > > > +  return NULL_TREE;
> > > > > +}
> > > > > +
> > > > > +/* Replace all deferred cst components with their compile-time values
> > > > > +   and return the fully folded result.  */
> > > > > +static tree
> > > > > +substitute_deferred_cst_components (tree expr)
> > > > > +{
> > > > > +  if (CONSTANT_CLASS_P (expr))
> > > > > +    return expr;
> > > > > +
> > > > > +  tree deferred_component = substitute_deferred_cst_component (expr);
> > > > > +  if (deferred_component)
> > > > > +    return deferred_component;
> > > > > +
> > > > > +  gcc_assert (deferred_cst_operator_p (TREE_CODE (expr)));
> > > > > +
> > > > > +  switch (TREE_OPERAND_LENGTH (expr))
> > > > > +    {
> > > > > +    case 1:
> > > > > +      {
> > > > > +       tree op0
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 0));
> > > > > +
> > > > > +       return fold_build1_loc (EXPR_LOCATION (expr),
> > > > > +                               TREE_CODE (expr),
> > > > > +                               TREE_TYPE (expr),
> > > > > +                               op0);
> > > > > +      }
> > > > > +
> > > > > +    case 2:
> > > > > +      {
> > > > > +       tree op0
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 0));
> > > > > +       tree op1
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 1));
> > > > > +
> > > > > +       return fold_build2_loc (EXPR_LOCATION (expr),
> > > > > +                               TREE_CODE (expr),
> > > > > +                               TREE_TYPE (expr),
> > > > > +                               op0, op1);
> > > > > +      }
> > > > > +
> > > > > +    case 3:
> > > > > +      {
> > > > > +       tree op0
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 0));
> > > > > +       tree op1
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 1));
> > > > > +       tree op2
> > > > > +         = substitute_deferred_cst_components (TREE_OPERAND (expr, 
> > > > > 2));
> > > > > +
> > > > > +       return fold_build3_loc (EXPR_LOCATION (expr),
> > > > > +                               TREE_CODE (expr),
> > > > > +                               TREE_TYPE (expr),
> > > > > +                               op0, op1, op2);
> > > > > +      }
> > > > > +
> > > > > +    default:
> > > > > +      gcc_unreachable ();
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +/* Replace all deferred components in EXPR with their compile-time
> > > > > +   values and evaluate the result.  Return an actual constant.  */
> > > > > +static tree
> > > > > +evaluate_deferred_cst_now (tree expr)
> > > > > +{
> > > > > +  tree result = substitute_deferred_cst_components (expr);
> > > > > +  result = fold (result);
> > > > > +
> > > > > +  if (!CONSTANT_CLASS_P (result))
> > > > > +    internal_error ("invalid compile-time value of deferred 
> > > > > constant");
> > > > > +
> > > > > +  return result;
> > > > > +}
> > > > > +
> > > > > +/* Returns true if the given tree node may not exist past the 
> > > > > deferred
> > > > > +   constant barrier pass.  */
> > > > > +static bool
> > > > > +deferred_cst_barrier_applies (tree node)
> > > > > +{
> > > > > +  if (!node)
> > > > > +    return false;
> > > > > +
> > > > > +  switch (TREE_CODE (node))
> > > > > +    {
> > > > > +    case DEFERRED_CST_EXPR:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      return true;
> > > > > +
> > > > > +    default:
> > > > > +      return false;
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +/* On the deferred constant barrier pass, return the replacement for
> > > > > +   a tree node that may not exist beyond it.
> > > > > +
> > > > > +   DEFERRED_CST_COMPONENT_REFs are simpy replaced with a standard
> > > > > +   COMPONENT_REF node.
> > > > > +
> > > > > +   All deferred components under a DEFERRED_CST_EXPR are replaced 
> > > > > with
> > > > > +   their actual compile-time values.  Afterwards, the expression is
> > > > > +   fully evaluated to replace NODE.  */
> > > > > +static tree
> > > > > +deferred_cst_barrier_apply (tree node)
> > > > > +{
> > > > > +  gcc_assert (deferred_cst_barrier_applies (node));
> > > > > +
> > > > > +  if (flag_deferred_cst_barrier_hard)
> > > > > +    internal_error (
> > > > > +      "unresolved deferred constant reached hard barrier");
> > > > > +
> > > > > +  switch (TREE_CODE (node))
> > > > > +    {
> > > > > +    case DEFERRED_CST_EXPR:
> > > > > +      return evaluate_deferred_cst_now (TREE_OPERAND (node, 0));
> > > > > +
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      {
> > > > > +       tree ref
> > > > > +         = build3_loc (EXPR_LOCATION (node),
> > > > > +                       COMPONENT_REF,
> > > > > +                       TREE_TYPE (node),
> > > > > +                       TREE_OPERAND (node, 0),
> > > > > +                       TREE_OPERAND (node, 1),
> > > > > +                       NULL_TREE);
> > > > > +
> > > > > +       /* Preserve expression properties that may have been attached
> > > > > +          to the deferred reference during lowering.  */
> > > > > +       TREE_READONLY (ref) = TREE_READONLY (node);
> > > > > +       TREE_THIS_VOLATILE (ref) = TREE_THIS_VOLATILE (node);
> > > > > +       TREE_SIDE_EFFECTS (ref) = TREE_SIDE_EFFECTS (node);
> > > > > +
> > > > > +       return ref;
> > > > > +      }
> > > > > +
> > > > > +    default:
> > > > > +      gcc_unreachable ();
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +/* Walker to go through functions and initializers.  It applies the
> > > > > +   deferred constant barrier to all deferred constant tree nodes.  */
> > > > > +static tree
> > > > > +deferred_cst_barrier_walk (tree *tp, int *walk_subtrees, void *data)
> > > > > +{
> > > > > +  tree node = *tp;
> > > > > +
> > > > > +  if (!node)
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  if (TYPE_P (node) || DECL_P (node))
> > > > > +    {
> > > > > +      *walk_subtrees = 0;
> > > > > +      return NULL_TREE;
> > > > > +    }
> > > > > +
> > > > > +  if (!deferred_cst_barrier_applies (node))
> > > > > +    return NULL_TREE;
> > > > > +
> > > > > +  /*
> > > > > +     A deferred component can have another deferred component in its 
> > > > > base.
> > > > > +     Clean the base explicitly before replacing the outer node.  
> > > > > Operand 1
> > > > > +     is a FIELD_DECL and must not be walked.
> > > > > +  */
> > > > > +  if (TREE_CODE (node) == DEFERRED_CST_COMPONENT_REF)
> > > > > +    {
> > > > > +      tree base = TREE_OPERAND (node, 0);
> > > > > +
> > > > > +      walk_tree (&base,
> > > > > +                deferred_cst_barrier_walk,
> > > > > +                data,
> > > > > +                NULL);
> > > > > +
> > > > > +      TREE_OPERAND (node, 0) = base;
> > > > > +    }
> > > > > +
> > > > > +  *tp = deferred_cst_barrier_apply (node);
> > > > > +  *walk_subtrees = 0;
> > > > > +
> > > > > +  return NULL_TREE;
> > > > > +}
> > > > > +
> > > > > +static void
> > > > > +deferred_cst_barrier_function (function *fn)
> > > > > +{
> > > > > +  basic_block bb;
> > > > > +
> > > > > +  FOR_EACH_BB_FN (bb, fn)
> > > > > +    {
> > > > > +      for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> > > > > +          !gsi_end_p (gsi);
> > > > > +          gsi_next (&gsi))
> > > > > +       {
> > > > > +         gimple *stmt = gsi_stmt (gsi);
> > > > > +
> > > > > +         for (unsigned int i = 0; i < gimple_num_ops (stmt); ++i)
> > > > > +           {
> > > > > +             tree *operand = gimple_op_ptr (stmt, i);
> > > > > +
> > > > > +             if (!operand || !*operand)
> > > > > +               continue;
> > > > > +
> > > > > +             walk_tree (operand,
> > > > > +                        deferred_cst_barrier_walk,
> > > > > +                        NULL,
> > > > > +                        NULL);
> > > > > +           }
> > > > > +       }
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +static tree
> > > > > +deferred_cst_barrier_init (tree init)
> > > > > +{
> > > > > +  if (!init)
> > > > > +    return init;
> > > > > +
> > > > > +  walk_tree (&init, deferred_cst_barrier_walk, NULL, NULL);
> > > > > +
> > > > > +  return init;
> > > > > +}
> > > > > +
> > > > > +static void
> > > > > +deferred_cst_barrier_functions ()
> > > > > +{
> > > > > +  cgraph_node *node;
> > > > > +
> > > > > +  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
> > > > > +    {
> > > > > +      function *fn = DECL_STRUCT_FUNCTION (node->decl);
> > > > > +      gcc_assert (fn);
> > > > > +
> > > > > +      push_cfun (fn);
> > > > > +      deferred_cst_barrier_function (fn);
> > > > > +      pop_cfun ();
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +static void
> > > > > +deferred_cst_barrier_inits ()
> > > > > +{
> > > > > +  varpool_node *vnode;
> > > > > +
> > > > > +  FOR_EACH_VARIABLE (vnode)
> > > > > +    {
> > > > > +      tree decl = vnode->decl;
> > > > > +      tree init = DECL_INITIAL (decl);
> > > > > +
> > > > > +      if (!init || init == error_mark_node)
> > > > > +       continue;
> > > > > +
> > > > > +      tree clean_init = deferred_cst_barrier_init (init);
> > > > > +      if (clean_init != init)
> > > > > +       DECL_INITIAL (decl) = clean_init;
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +namespace {
> > > > > +
> > > > > +const pass_data pass_data_deferred_cst_barrier =
> > > > > +{
> > > > > +  SIMPLE_IPA_PASS,
> > > > > +  "deferred-cst-barrier",
> > > > > +  OPTGROUP_NONE,
> > > > > +  TV_NONE,
> > > > > +  0, 0, 0, 0, 0
> > > > > +};
> > > > > +
> > > > > +class pass_deferred_cst_barrier : public simple_ipa_opt_pass
> > > > > +{
> > > > > +public:
> > > > > +  pass_deferred_cst_barrier (gcc::context *ctxt)
> > > > > +    : simple_ipa_opt_pass (pass_data_deferred_cst_barrier, ctxt)
> > > > > +  {}
> > > > > +
> > > > > +  unsigned int execute (function *) final override;
> > > > > +};
> > > > > +
> > > > > +unsigned int
> > > > > +pass_deferred_cst_barrier::execute (function *)
> > > > > +{
> > > > > +  deferred_cst_barrier_functions ();
> > > > > +  deferred_cst_barrier_inits ();
> > > > > +  return 0;
> > > > > +}
> > > > > +
> > > > > +} // anonymous namespace
> > > > > +
> > > > > +simple_ipa_opt_pass *
> > > > > +make_pass_deferred_cst_barrier (gcc::context *ctxt)
> > > > > +{
> > > > > +  return new pass_deferred_cst_barrier (ctxt);
> > > > > +}
> > > > > +
> > > > > +#include "gt-deferred-cst.h"
> > > > > diff --git a/gcc/deferred-cst.h b/gcc/deferred-cst.h
> > > > > new file mode 100644
> > > > > index 00000000000..d475030de01
> > > > > --- /dev/null
> > > > > +++ b/gcc/deferred-cst.h
> > > > > @@ -0,0 +1,39 @@
> > > > > +#ifndef GCC_DEFERRED_CST_H
> > > > > +#define GCC_DEFERRED_CST_H
> > > > > +
> > > > > +/* Returns true of accesses to fields of this type should be based on
> > > > > +   deferred cst offsets.  This is the case on RECORD_TYPEs with
> > > > > +
> > > > > +     __attribute__((deferred_cst_access))  */
> > > > > +extern bool deferred_cst_access_type_p (tree type);
> > > > > +
> > > > > +/* Returns true if FIELD is part of a type that satisfies
> > > > > +   deferred_cst_access_type_p.  */
> > > > > +extern bool deferred_cst_field_p (tree field);
> > > > > +
> > > > > +/* Return true if CODE is an operation which may be absorbed into a
> > > > > +   DEFERRED_CST_EXPR.  */
> > > > > +extern bool deferred_cst_operator_p (enum tree_code code);
> > > > > +
> > > > > +/* Build DEFERRED_CST_COMPONENT_REF to FIELD in BASE.  */
> > > > > +extern tree deferred_cst_build_component_ref (tree type, tree base, 
> > > > > tree field);
> > > > > +
> > > > > +/* Build a DEFERRED_CST_EXPR around EXPR.  */
> > > > > +extern tree deferred_cst_build_expr (tree expr);
> > > > > +
> > > > > +/* Create a call to IFN_DEFERRED_CST_FIELD_OFFSET for the physical,
> > > > > +   addressable FIELD whose byte offset is deferred.
> > > > > +
> > > > > +   FIELD must not be a bit-field.  Callers handling bit-fields must 
> > > > > pass
> > > > > +   DECL_BIT_FIELD_REPRESENTATIVE (field).  */
> > > > > +extern tree deferred_cst_call_ifn_field_offset (location_t loc, tree 
> > > > > field);
> > > > > +
> > > > > +/* Get the FIELD_DECL associated with the argument TOKEN to a call of
> > > > > +   IFN_DEFERRED_CST_FIELD_OFFSET.  */
> > > > > +extern tree deferred_cst_ifn_field_offset_field (tree token);
> > > > > +
> > > > > +/* Return true if EXPR contains a DEFERRED_CST_EXPR or
> > > > > +   DEFERRED_CST_COMPONENT_REF.  */
> > > > > +extern bool deferred_cst_present_p (tree expr);
> > > > > +
> > > > > +#endif
> > > > > diff --git a/gcc/expr.cc b/gcc/expr.cc
> > > > > index 7ca5dd84ce9..d0925557cef 100644
> > > > > --- a/gcc/expr.cc
> > > > > +++ b/gcc/expr.cc
> > > > > @@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "tree-pretty-print.h"
> > > > >  #include "flags.h"
> > > > >  #include "internal-fn.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >
> > > > >  /* If this is nonzero, we do not bother generating VOLATILE
> > > > > @@ -8460,6 +8461,7 @@ store_field (rtx target, poly_int64 bitsize, 
> > > > > poly_int64 bitpos,
> > > > >      }
> > > > >  }
> > > > >
> > > > > +
> > > > >  /* Given an expression EXP that may be a COMPONENT_REF, a 
> > > > > BIT_FIELD_REF,
> > > > >     an ARRAY_REF, or an ARRAY_RANGE_REF, look for nested operations 
> > > > > of these
> > > > >     codes and find the ultimate containing object, which we return.
> > > > > @@ -8497,7 +8499,8 @@ get_inner_reference (tree exp, poly_int64 
> > > > > *pbitsize,
> > > > >    /* First get the mode, signedness, storage order and size.  We do 
> > > > > this from
> > > > >       just the outermost expression.  */
> > > > >    *pbitsize = -1;
> > > > > -  if (TREE_CODE (exp) == COMPONENT_REF)
> > > > > +  if (TREE_CODE (exp) == COMPONENT_REF
> > > > > +      || TREE_CODE (exp) == DEFERRED_CST_COMPONENT_REF)
> > > > >      {
> > > > >        tree field = TREE_OPERAND (exp, 1);
> > > > >        size_tree = DECL_SIZE (field);
> > > > > @@ -8585,6 +8588,36 @@ get_inner_reference (tree exp, poly_int64 
> > > > > *pbitsize,
> > > > >           }
> > > > >           break;
> > > > >
> > > > > +       case DEFERRED_CST_COMPONENT_REF:
> > > > > +         {
> > > > > +           tree field = TREE_OPERAND (exp, 1);
> > > > > +           tree deferred_cst_field = field;
> > > > > +
> > > > > +           if (DECL_BIT_FIELD (field))
> > > > > +             {
> > > > > +               deferred_cst_field = DECL_BIT_FIELD_REPRESENTATIVE 
> > > > > (field);
> > > > > +
> > > > > +               gcc_assert (deferred_cst_field);
> > > > > +               gcc_assert (TREE_CODE (deferred_cst_field) == 
> > > > > FIELD_DECL);
> > > > > +               gcc_assert (!DECL_BIT_FIELD (deferred_cst_field));
> > > > > +
> > > > > +               tree relative_bit_offset
> > > > > +                 = size_binop (MINUS_EXPR,
> > > > > +                               bit_position (field),
> > > > > +                               bit_position (deferred_cst_field));
> > > > > +
> > > > > +               gcc_assert (poly_int_tree_p (relative_bit_offset));
> > > > > +               bit_offset += wi::to_poly_offset 
> > > > > (relative_bit_offset);
> > > > > +             }
> > > > > +
> > > > > +           tree this_offset = deferred_cst_call_ifn_field_offset (
> > > > > +                                       EXPR_LOCATION (exp),
> > > > > +                                       deferred_cst_field);
> > > > > +           this_offset = deferred_cst_build_expr (this_offset);
> > > > > +           offset = size_binop (PLUS_EXPR, offset, this_offset);
> > > > > +         }
> > > > > +         break;
> > > > > +
> > > > >         case ARRAY_REF:
> > > > >         case ARRAY_RANGE_REF:
> > > > >           {
> > > > > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
> > > > > index 56503e570bc..2fb0287b927 100644
> > > > > --- a/gcc/fold-const.cc
> > > > > +++ b/gcc/fold-const.cc
> > > > > @@ -11139,6 +11139,20 @@ fold_binary_loc (location_t loc, enum 
> > > > > tree_code code, tree type,
> > > > >
> > > > >    switch (code)
> > > > >      {
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      if (TREE_CODE (arg0) == CONSTRUCTOR
> > > > > +         && ! type_contains_placeholder_p (TREE_TYPE (arg0)))
> > > > > +       {
> > > > > +         unsigned HOST_WIDE_INT idx;
> > > > > +         tree field;
> > > > > +         tree value;
> > > > > +
> > > > > +         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, 
> > > > > field, value)
> > > > > +           if (field == arg1)
> > > > > +             return value;
> > > > > +       }
> > > > > +      return NULL_TREE;
> > > > > +
> > > > >      case MEM_REF:
> > > > >        /* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2].  */
> > > > >        if (TREE_CODE (arg0) == ADDR_EXPR
> > > > > diff --git a/gcc/gimple-expr.cc b/gcc/gimple-expr.cc
> > > > > index 96f9fc720af..fabd6e10ea1 100644
> > > > > --- a/gcc/gimple-expr.cc
> > > > > +++ b/gcc/gimple-expr.cc
> > > > > @@ -846,6 +846,11 @@ is_gimple_val (tree t)
> > > > >        || TREE_CODE (t) == OMP_TARGET_DEVICE_MATCHES)
> > > > >      return true;
> > > > >
> > > > > +  /* Technically, deferred constant expressions act as min 
> > > > > invariants,
> > > > > +     but they do not survice to where that would be relevant.  */
> > > > > +  if (TREE_CODE (t) == DEFERRED_CST_EXPR)
> > > > > +    return true;
> > > > > +
> > > > >    return (is_gimple_variable (t) || is_gimple_min_invariant (t));
> > > > >  }
> > > > >
> > > > > diff --git a/gcc/gimple.cc b/gcc/gimple.cc
> > > > > index c791e041243..7918552fce1 100644
> > > > > --- a/gcc/gimple.cc
> > > > > +++ b/gcc/gimple.cc
> > > > > @@ -2564,7 +2564,8 @@ get_gimple_rhs_num_ops (enum tree_code code)
> > > > >        || (SYM) == WITH_SIZE_EXPR                                     
> > > > >       \
> > > > >        || (SYM) == SSA_NAME                                           
> > > > >       \
> > > > >        || (SYM) == OMP_NEXT_VARIANT                                   
> > > > >       \
> > > > > -      || (SYM) == OMP_TARGET_DEVICE_MATCHES) ? GIMPLE_SINGLE_RHS     
> > > > >       \
> > > > > +      || (SYM) == OMP_TARGET_DEVICE_MATCHES                          
> > > > >       \
> > > > > +      || (SYM) == DEFERRED_CST_EXPR) ? GIMPLE_SINGLE_RHS             
> > > > >       \
> > > > >     : GIMPLE_INVALID_RHS),
> > > > >  #define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS,
> > > > >
> > > > > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
> > > > > index 8bfc71315f9..6f55340dc34 100644
> > > > > --- a/gcc/gimplify.cc
> > > > > +++ b/gcc/gimplify.cc
> > > > > @@ -75,6 +75,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "recog.h"
> > > > >  #include "output.h"
> > > > >  #include "gimplify_reg_info.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  /* Identifier for a basic condition, mapping it to other basic 
> > > > > conditions of
> > > > >     its Boolean expression.  Basic conditions given the same uid (in 
> > > > > the same
> > > > > @@ -3497,8 +3498,8 @@ recalculate_side_effects (tree t)
> > > > >     }
> > > > >  }
> > > > >
> > > > > -/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or 
> > > > > IMAGPART_EXPR
> > > > > -   node *EXPR_P.
> > > > > +/* Gimplify the COMPONENT_REF, DEFERRED_CST_COMPONENT_REF, ARRAY_REF,
> > > > > +   REALPART_EXPR or IMAGPART_EXPR node *EXPR_P.
> > > > >
> > > > >        compound_lval
> > > > >               : min_lval '[' val ']'
> > > > > @@ -6086,7 +6087,7 @@ gimplify_init_ctor_preeval (tree *expr_p, 
> > > > > gimple_seq *pre_p, gimple_seq *post_p,
> > > > >     already been taken care of for us, in 
> > > > > gimplify_init_ctor_preeval().  */
> > > > >
> > > > >  static void gimplify_init_ctor_eval (tree, vec<constructor_elt, 
> > > > > va_gc> *,
> > > > > -                                    gimple_seq *, bool);
> > > > > +                                    gimple_seq *, bool, bool);
> > > > >
> > > > >  static void
> > > > >  gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
> > > > > @@ -6116,10 +6117,15 @@ gimplify_init_ctor_eval_range (tree object, 
> > > > > tree lower, tree upper,
> > > > >       the store.  Otherwise just assign value to the reference.  */
> > > > >
> > > > >    if (TREE_CODE (value) == CONSTRUCTOR)
> > > > > -    /* NB we might have to call ourself recursively through
> > > > > -       gimplify_init_ctor_eval if the value is a constructor.  */
> > > > > -    gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
> > > > > -                            pre_p, cleared);
> > > > > +    {
> > > > > +      /* NB we might have to call ourself recursively through
> > > > > +         gimplify_init_ctor_eval if the value is a constructor.  */
> > > > > +      bool deferred_cst_value
> > > > > +       = deferred_cst_access_type_p (TREE_TYPE (value));
> > > > > +
> > > > > +      gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
> > > > > +                              pre_p, cleared, deferred_cst_value);
> > > > > +    }
> > > > >    else
> > > > >      {
> > > > >        if (gimplify_expr (&value, pre_p, NULL, is_gimple_val, 
> > > > > fb_rvalue)
> > > > > @@ -6154,7 +6160,8 @@ gimplify_init_ctor_eval_range (tree object, 
> > > > > tree lower, tree upper,
> > > > >
> > > > >  static void
> > > > >  gimplify_init_ctor_eval (tree object, vec<constructor_elt, va_gc> 
> > > > > *elts,
> > > > > -                        gimple_seq *pre_p, bool cleared)
> > > > > +                        gimple_seq *pre_p, bool cleared,
> > > > > +                        bool deferred_cst)
> > > > >  {
> > > > >    tree array_elt_type = NULL;
> > > > >    unsigned HOST_WIDE_INT ix;
> > > > > @@ -6220,14 +6227,25 @@ gimplify_init_ctor_eval (tree object, 
> > > > > vec<constructor_elt, va_gc> *elts,
> > > > >        else
> > > > >         {
> > > > >           gcc_assert (TREE_CODE (purpose) == FIELD_DECL);
> > > > > -         cref = build3 (COMPONENT_REF, TREE_TYPE (purpose),
> > > > > -                        unshare_expr (object), purpose, NULL_TREE);
> > > > > +         tree base = unshare_expr (object);
> > > > > +
> > > > > +         if (deferred_cst)
> > > > > +           cref = deferred_cst_build_component_ref (TREE_TYPE 
> > > > > (purpose),
> > > > > +                                                    base, purpose);
> > > > > +         else
> > > > > +           cref = build3 (COMPONENT_REF, TREE_TYPE (purpose),
> > > > > +                          base, purpose, NULL_TREE);
> > > > >         }
> > > > >
> > > > >        if (TREE_CODE (value) == CONSTRUCTOR
> > > > >           && TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE)
> > > > > -       gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
> > > > > -                                pre_p, cleared);
> > > > > +       {
> > > > > +         bool value_deferred_cst
> > > > > +           = deferred_cst_access_type_p (TREE_TYPE (value));
> > > > > +
> > > > > +         gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
> > > > > +                                  pre_p, cleared, 
> > > > > value_deferred_cst);
> > > > > +       }
> > > > >        else if (TREE_CODE (value) == RAW_DATA_CST)
> > > > >         {
> > > > >           if (RAW_DATA_LENGTH (value) <= 32)
> > > > > @@ -6418,6 +6436,7 @@ gimplify_init_constructor (tree *expr_p, 
> > > > > gimple_seq *pre_p, gimple_seq *post_p,
> > > > >    bool cleared = false;
> > > > >    bool is_empty_ctor = false;
> > > > >    bool is_init_expr = (TREE_CODE (*expr_p) == INIT_EXPR);
> > > > > +  bool deferred_cst = false;
> > > > >
> > > > >    gcc_assert (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == CONSTRUCTOR);
> > > > >
> > > > > @@ -6434,6 +6453,8 @@ gimplify_init_constructor (tree *expr_p, 
> > > > > gimple_seq *pre_p, gimple_seq *post_p,
> > > > >      = optimize_compound_literals_in_ctor (TREE_OPERAND (*expr_p, 1));
> > > > >    type = TREE_TYPE (ctor);
> > > > >    elts = CONSTRUCTOR_ELTS (ctor);
> > > > > +  deferred_cst
> > > > > +    = deferred_cst_access_type_p (TREE_TYPE (ctor));
> > > > >    ret = GS_ALL_DONE;
> > > > >
> > > > >    switch (TREE_CODE (type))
> > > > > @@ -6698,7 +6719,8 @@ gimplify_init_constructor (tree *expr_p, 
> > > > > gimple_seq *pre_p, gimple_seq *post_p,
> > > > >         if (!cleared
> > > > >             || num_nonzero_elements > 0
> > > > >             || ctor_has_side_effects_p)
> > > > > -         gimplify_init_ctor_eval (object, elts, pre_p, cleared);
> > > > > +         gimplify_init_ctor_eval (object, elts, pre_p, cleared,
> > > > > +                                  deferred_cst);
> > > > >
> > > > >         *expr_p = NULL_TREE;
> > > > >        }
> > > > > @@ -20425,6 +20447,7 @@ gimplify_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p,
> > > > >         case REALPART_EXPR:
> > > > >         case IMAGPART_EXPR:
> > > > >         case COMPONENT_REF:
> > > > > +       case DEFERRED_CST_COMPONENT_REF:
> > > > >           ret = gimplify_compound_lval (expr_p, pre_p, post_p,
> > > > >                                         fallback ? fallback : 
> > > > > fb_rvalue);
> > > > >           break;
> > > > > @@ -20658,6 +20681,11 @@ gimplify_expr (tree *expr_p, gimple_seq 
> > > > > *pre_p, gimple_seq *post_p,
> > > > >           ret = GS_ALL_DONE;
> > > > >           break;
> > > > >
> > > > > +       case DEFERRED_CST_EXPR:
> > > > > +         /* DEFERRED_CST_EXPRs act as min invariants.  */
> > > > > +         ret = GS_ALL_DONE;
> > > > > +         break;
> > > > > +
> > > > >         case CONST_DECL:
> > > > >           /* If we require an lvalue, such as for ADDR_EXPR, retain 
> > > > > the
> > > > >              CONST_DECL node.  Otherwise the decl is replaceable by 
> > > > > its
> > > > > diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
> > > > > index 65be5aed35c..88a7334dadb 100644
> > > > > --- a/gcc/internal-fn.cc
> > > > > +++ b/gcc/internal-fn.cc
> > > > > @@ -4266,6 +4266,15 @@ expand_reduc_sbool_optab_fn (internal_fn fn, 
> > > > > gcall *stmt, direct_optab optab)
> > > > >      assign_call_lhs (lhs, lhs_rtx, &ops[0]);
> > > > >  }
> > > > >
> > > > > +/* IFN_DEFERRED_CST_FIELD_OFFSET should not survice GIMPLE.  */
> > > > > +
> > > > > +void
> > > > > +expand_DEFERRED_CST_FIELD_OFFSET (internal_fn, gcall *)
> > > > > +{
> > > > > +  internal_error (
> > > > > +    "IFN_DEFERRED_CST_FIELD_OFFSET reached RTL expansion without 
> > > > > being lowered");
> > > > > +}
> > > > > +
> > > > >  /* Expanders for optabs that can use expand_direct_optab_fn.  */
> > > > >
> > > > >  #define expand_unary_optab_fn(FN, STMT, OPTAB) \
> > > > > diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
> > > > > index 084a9271631..ce8aacf803f 100644
> > > > > --- a/gcc/internal-fn.def
> > > > > +++ b/gcc/internal-fn.def
> > > > > @@ -622,6 +622,9 @@ DEF_INTERNAL_FN (BITINTTOFLOAT, ECF_PURE | 
> > > > > ECF_LEAF, ". R . ")
> > > > >  DEF_INTERNAL_OPTAB_FN (BIT_ANDN, ECF_CONST, andn, binary)
> > > > >  DEF_INTERNAL_OPTAB_FN (BIT_IORN, ECF_CONST, iorn, binary)
> > > > >
> > > > > +/* Deferred constant functions.  */
> > > > > +DEF_INTERNAL_FN (DEFERRED_CST_FIELD_OFFSET, ECF_CONST | ECF_LEAF | 
> > > > > ECF_NOTHROW, NULL)
> > > > > +
> > > > >  #undef DEF_INTERNAL_WIDENING_OPTAB_FN
> > > > >  #undef DEF_INTERNAL_SIGNED_COND_FN
> > > > >  #undef DEF_INTERNAL_COND_FN
> > > > > diff --git a/gcc/passes.def b/gcc/passes.def
> > > > > index cdddb87302f..2b14864d200 100644
> > > > > --- a/gcc/passes.def
> > > > > +++ b/gcc/passes.def
> > > > > @@ -47,6 +47,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >
> > > > >    /* Interprocedural optimization passes.  */
> > > > >    INSERT_PASSES_AFTER (all_small_ipa_passes)
> > > > > +  NEXT_PASS (pass_deferred_cst_barrier);
> > > > >    /* auto_profile_offline uses dwarf_name hook that only
> > > > >       works before free_lang_data.  */
> > > > >    NEXT_PASS (pass_ipa_auto_profile_offline);
> > > > > diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
> > > > > index b3c97658a8f..eddec889dc2 100644
> > > > > --- a/gcc/tree-pass.h
> > > > > +++ b/gcc/tree-pass.h
> > > > > @@ -513,6 +513,7 @@ extern gimple_opt_pass 
> > > > > *make_pass_coroutine_early_expand_ifns (gcc::context *ctx
> > > > >  extern gimple_opt_pass *make_pass_adjust_alignment (gcc::context 
> > > > > *ctxt);
> > > > >
> > > > >  /* IPA Passes */
> > > > > +extern simple_ipa_opt_pass *make_pass_deferred_cst_barrier 
> > > > > (gcc::context *ctxt);
> > > > >  extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context 
> > > > > *ctxt);
> > > > >  extern simple_ipa_opt_pass 
> > > > > *make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt);
> > > > >  extern simple_ipa_opt_pass *make_pass_ipa_strub_mode (gcc::context 
> > > > > *ctxt);
> > > > > diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
> > > > > index 79e0a734dbb..79251619fbe 100644
> > > > > --- a/gcc/tree-pretty-print.cc
> > > > > +++ b/gcc/tree-pretty-print.cc
> > > > > @@ -2837,6 +2837,7 @@ dump_generic_node (pretty_printer *pp, tree 
> > > > > node, int spc, dump_flags_t flags,
> > > > >        break;
> > > > >
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >        op0 = TREE_OPERAND (node, 0);
> > > > >        str = ".";
> > > > >        if (op0
> > > > > @@ -2873,16 +2874,21 @@ dump_generic_node (pretty_printer *pp, tree 
> > > > > node, int spc, dump_flags_t flags,
> > > > >        if (op_prio (op0) < op_prio (node))
> > > > >         pp_right_paren (pp);
> > > > >        pp_string (pp, str);
> > > > > +      if (code == DEFERRED_CST_COMPONENT_REF)
> > > > > +       pp_string (pp, "DEFERRED<");
> > > > >        op1 = TREE_OPERAND (node, 1);
> > > > >        dump_generic_node (pp, op1, spc, flags, false);
> > > > > -      if (DECL_P (op1)) /* Not always a decl in the C++ FE.  */
> > > > > -       if (tree off = component_ref_field_offset (node))
> > > > > -         if (TREE_CODE (off) != INTEGER_CST)
> > > > > -           {
> > > > > -             pp_string (pp, "{off: ");
> > > > > -             dump_generic_node (pp, off, spc, flags, false);
> > > > > -             pp_right_brace (pp);
> > > > > -           }
> > > > > +      if (code == DEFERRED_CST_COMPONENT_REF)
> > > > > +       pp_string (pp, ">");
> > > > > +      else
> > > > > +       if (DECL_P (op1)) /* Not always a decl in the C++ FE.  */
> > > > > +         if (tree off = component_ref_field_offset (node))
> > > > > +           if (TREE_CODE (off) != INTEGER_CST)
> > > > > +             {
> > > > > +               pp_string (pp, "{off: ");
> > > > > +               dump_generic_node (pp, off, spc, flags, false);
> > > > > +               pp_right_brace (pp);
> > > > > +             }
> > > > >        break;
> > > > >
> > > > >      case BIT_FIELD_REF:
> > > > > @@ -4344,6 +4350,13 @@ dump_generic_node (pretty_printer *pp, tree 
> > > > > node, int spc, dump_flags_t flags,
> > > > >        }
> > > > >        break;
> > > > >
> > > > > +    case DEFERRED_CST_EXPR:
> > > > > +      pp_string (pp, "DEFERRED_CST_EXPR <");
> > > > > +      dump_generic_node (pp, TREE_OPERAND (node, 0),
> > > > > +                        spc, flags, false);
> > > > > +      pp_character (pp, '>');
> > > > > +      break;
> > > > > +
> > > > >      case OMP_TARGET_DEVICE_MATCHES:
> > > > >        pp_string (pp, "OMP_TARGET_DEVICE_MATCHES <");
> > > > >        dump_generic_node (pp, OMP_TARGET_DEVICE_MATCHES_SELECTOR 
> > > > > (node), spc,
> > > > > @@ -4790,6 +4803,7 @@ op_code_prio (enum tree_code code)
> > > > >      case ARRAY_REF:
> > > > >      case ARRAY_RANGE_REF:
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >        return 15;
> > > > >
> > > > >        /* Special expressions.  */
> > > > > @@ -5052,6 +5066,7 @@ print_call_name (pretty_printer *pp, tree node, 
> > > > > dump_flags_t flags)
> > > > >         }
> > > > >        /* Fallthru.  */
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >      case SSA_NAME:
> > > > >      case OBJ_TYPE_REF:
> > > > >        dump_generic_node (pp, op0, 0, flags, false);
> > > > > diff --git a/gcc/tree.cc b/gcc/tree.cc
> > > > > index 2868cb0867d..158c99b9aed 100644
> > > > > --- a/gcc/tree.cc
> > > > > +++ b/gcc/tree.cc
> > > > > @@ -76,6 +76,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "asan.h"
> > > > >  #include "ubsan.h"
> > > > >  #include "attr-callback.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  /* Names of tree components.
> > > > >     Used for printing out the tree and error messages.  */
> > > > > @@ -3908,7 +3909,13 @@ staticp (tree arg)
> > > > >               ? arg : NULL);
> > > > >
> > > > >      case CONSTRUCTOR:
> > > > > -      return TREE_STATIC (arg) ? arg : NULL;
> > > > > +      {
> > > > > +       if (!flag_deferred_cst_static
> > > > > +           && deferred_cst_access_type_p (TREE_TYPE (arg)))
> > > > > +         return NULL;
> > > > > +
> > > > > +       return TREE_STATIC (arg) ? arg : NULL;
> > > > > +      }
> > > > >
> > > > >      case LABEL_DECL:
> > > > >      case STRING_CST:
> > > > > @@ -3926,6 +3933,16 @@ staticp (tree arg)
> > > > >
> > > > >        return staticp (TREE_OPERAND (arg, 0));
> > > > >
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > > +      {
> > > > > +       /* Deferred cst references are only compatible with static 
> > > > > data if
> > > > > +          explicitly permitted by -fdeferred-cst-static  */
> > > > > +        if (flag_deferred_cst_static)
> > > > > +         return staticp (TREE_OPERAND (arg, 0));
> > > > > +       else
> > > > > +         return NULL;
> > > > > +      }
> > > > > +
> > > > >      case BIT_FIELD_REF:
> > > > >        return NULL;
> > > > >
> > > > > diff --git a/gcc/tree.def b/gcc/tree.def
> > > > > index ad8e676e942..43e94d0c361 100644
> > > > > --- a/gcc/tree.def
> > > > > +++ b/gcc/tree.def
> > > > > @@ -443,6 +443,11 @@ DEFTREECODE (TRANSLATION_UNIT_DECL, 
> > > > > "translation_unit_decl",\
> > > > >     in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  */
> > > > >  DEFTREECODE (COMPONENT_REF, "component_ref", tcc_reference, 3)
> > > > >
> > > > > +/* Value is a structure component with a deferred constant offset.
> > > > > +   Operand 0 is the structure expression.
> > > > > +   Operand 1 is the field (a node of type FIELD_DECL).  */
> > > > > +DEFTREECODE (DEFERRED_CST_COMPONENT_REF, 
> > > > > "deferred_cst_component_ref", tcc_reference, 2)
> > > > > +
> > > > >  /* Reference to a group of bits within an object.  Similar to 
> > > > > COMPONENT_REF
> > > > >     except the position is given explicitly rather than via a 
> > > > > FIELD_DECL.
> > > > >     Operand 0 is the structure or union expression;
> > > > > @@ -1610,6 +1615,14 @@ DEFTREECODE (TARGET_OPTION_NODE, 
> > > > > "target_option_node", tcc_exceptional, 0)
> > > > >     Operand 2 is additional data.  */
> > > > >  DEFTREECODE (ANNOTATE_EXPR, "annotate_expr", tcc_expression, 3)
> > > > >
> > > > > +/* DEFERRED_CST_EXPR.
> > > > > +   Operand 0 is an expression with deferred const-ness.
> > > > > +   Such expressions are not constant at compile-time, but become
> > > > > +   constant before the normal runtime.  For example, a
> > > > > +   DEFERRED_CST_EXPR may wrap offsetof-like expressions that depend
> > > > > +   on DEFERRED_CST_COMPONENT_REFs.  */
> > > > > +DEFTREECODE (DEFERRED_CST_EXPR, "deferred_cst_expr", tcc_expression, 
> > > > > 1)
> > > > > +
> > > > >  /*
> > > > >  Local variables:
> > > > >  mode:c
> > > > > diff --git a/gcc/tree.h b/gcc/tree.h
> > > > > index f8b2d718b7e..386a62051a8 100644
> > > > > --- a/gcc/tree.h
> > > > > +++ b/gcc/tree.h
> > > > > @@ -5545,6 +5545,7 @@ handled_component_p (const_tree t)
> > > > >    switch (TREE_CODE (t))
> > > > >      {
> > > > >      case COMPONENT_REF:
> > > > > +    case DEFERRED_CST_COMPONENT_REF:
> > > > >      case BIT_FIELD_REF:
> > > > >      case ARRAY_REF:
> > > > >      case ARRAY_RANGE_REF:
> > > > > diff --git a/gcc/varasm.cc b/gcc/varasm.cc
> > > > > index 5999f1e5420..c955670c7e7 100644
> > > > > --- a/gcc/varasm.cc
> > > > > +++ b/gcc/varasm.cc
> > > > > @@ -64,6 +64,7 @@ along with GCC; see the file COPYING3.  If not see
> > > > >  #include "asan.h"
> > > > >  #include "recog.h"
> > > > >  #include "gimple-expr.h"
> > > > > +#include "deferred-cst.h"
> > > > >
> > > > >  /* The (assembler) name of the first globally-visible object output. 
> > > > >  */
> > > > >  extern GTY(()) const char *first_global_object_name;
> > > > > @@ -5056,7 +5057,12 @@ initializer_constant_valid_p_1 (tree value, 
> > > > > tree endtype, tree *cache)
> > > > >    switch (TREE_CODE (value))
> > > > >      {
> > > > >      case CONSTRUCTOR:
> > > > > -      if (constructor_static_from_elts_p (value))
> > > > > +      if (!flag_deferred_cst_static
> > > > > +         && deferred_cst_access_type_p (TREE_TYPE (value)))
> > > > > +       return NULL_TREE;
> > > > > +
> > > > > +      if (constructor_static_from_elts_p (value)
> > > > > +         || flag_deferred_cst_static)
> > > > >         {
> > > > >           unsigned HOST_WIDE_INT idx;
> > > > >           tree elt;
> > > > > @@ -5107,6 +5113,16 @@ initializer_constant_valid_p_1 (tree value, 
> > > > > tree endtype, tree *cache)
> > > > >      case RAW_DATA_CST:
> > > > >        return null_pointer_node;
> > > > >
> > > > > +    case DEFERRED_CST_EXPR:
> > > > > +      {
> > > > > +       /* Deferred constants are only allowed in static initializers
> > > > > +          if explicitly permitted by -fdeferred-cst-static  */
> > > > > +        if (flag_deferred_cst_static)
> > > > > +         return null_pointer_node;
> > > > > +       else
> > > > > +         return NULL_TREE;
> > > > > +      }
> > > > > +
> > > > >      case ADDR_EXPR:
> > > > >      case FDESC_EXPR:
> > > > >        {
> > > > > --
> > > > > 2.43.0
> > > > >

Reply via email to