Am Mittwoch, dem 23.07.2025 um 12:58 -0700 schrieb Bill Wendling:
> On Tue, Jul 22, 2025 at 11:22 PM Martin Uecker <ma.uec...@gmail.com> wrote:
> > Am Montag, dem 21.07.2025 um 16:03 -0700 schrieb Bill Wendling:
> > > On Mon, Jul 21, 2025 at 2:19 PM Martin Uecker <ma.uec...@gmail.com> wrote:
> > > > 
...
> 
> > > Please give an example of array sizes in C. I need to see a concrete
> > > example before discussing how delayed parsing wouldn't work in that
> > > situation.
> > 
> > Consider example like this:
> > 
> > constexpr int E = 3;
> > 
> > void f()
> > {
> >   struct foo {
> >     int N;
> >     char buf1[E];
> >     enum { E = 1 } e;
> >     char buf2[E];
> >   } b;
> >   static_assert(3 == _Countof b.buf1);
> >   static_assert(1 == _Countof b.buf2);
> > };
> > 
> This doesn't compile for C or C++.

It does, but it used a C2Y feature (you could
replace it with sizeof):
https://godbolt.org/z/Gs8s6cTY9

> 
> <source>:8:12: error: declaration of 'E' changes meaning of 'E'
> [-Wchanges-meaning]
>     8 |     enum { E = 1 } e;
>       |            ^
> <source>:7:15: note: used here to mean 'constexpr const int E'
>     7 |     char buf1[E];

I think it is UB in C++. Clang accepts it though:

https://godbolt.org/z/438jsPWco

> 
...
> > For size expressions is a lot more complicated than for attribute
> > content, because you can inspect them inside the language. So now
> > you also have to deal with circular dependencies:
> > 
> > struct foo {
> >   int N;
> >   char buf1[sizeof(buf1)];
> >   char buf2[sizeof(buf2)];
> > } b;
> > 
> > Is this forbidden?  Under what exact circumstances?
> > 
> > In principle this also applied to __bdos and attributes
> > but I guess you could have the instrumentation added for
> > code that comes after  the structure is finished.  (This
> > would then leave some gaps where you may not have the code
> > instrumented.)
> 
> This is an issue that my RFC was never meant to cover. I don't claim
> that delayed parsing is a panacea for all issues. I claim that it
> works for the bounds safety attributes. You and John had an
> interesting discussion on how to support array sizes in C.  But how
> that would be implemented is still "yet to be seen", from what I
> gathered.

The the thing is that WG14 had (weak) consensus for parameter
forward declarations and  I think more consensus for [.N] 
syntax in structures already.  So I had hoped that we will be
able to make progress on this.

.
Martin

> 
> -bw
> 
> > Martin
> > > To summarize my point of view a bit:
> > > 
> > > - This isn't a new feature. I don't even believe it's a feature at
> > > all. It's just something the compiler does internally to support a
> > > feature.
> > > - Any context that would affect the outcome of parsing of the
> > > attribute's argument are either expected/wanted or should be isolated
> > > into its own object and saved at the point where the parser encounters
> > > the tokens that require delayed parsing.
> > > - Extending a delayed parsing scheme, like this one here, to other
> > > features has yet to be explored. It may or may not be useful to them,
> > > but that doesn't indicate that it's not useful for this use case.
> > > - Other proposals for forward declarations or [.N] syntax have either
> > > been specifically rejected by one compiler or the other, or, in the
> > > case of the [.N] syntax and a Clang proposal to the C committee, have
> > > yet to be standardized.
> > > 
> > > -bw
> > > 
> > > > Martin
> > > > 
> > > > > 
> > > > > -bw
> > > > > 
> > > > > > Martin
> > > > > > 
> > > > > > Am Sonntag, dem 20.07.2025 um 11:20 +0000 schrieb mo...@google.com:
> > > > > > > From: Bill Wendling <mo...@google.com>
> > > > > > > 
> > > > > > > Also, this code doesn't go further than parsing. I.e., it doesn't 
> > > > > > > generate the
> > > > > > > internal gimple code that accesses the struct fields. The code is 
> > > > > > > meant to show
> > > > > > > that it *is* possible to perform a delayed parsing with no 
> > > > > > > "double parsing" and
> > > > > > > still be performant.
> > > > > > > 
> > > > > > > Minor Nomenclature Change
> > > > > > > -------------------------
> > > > > > > 
> > > > > > > I (try to) use "bounds safety" instead of "counted_by" in the 
> > > > > > > code. This is
> > > > > > > because Clang has many more bounds safety attributes in the 
> > > > > > > pipeline and
> > > > > > > "bounds safety" seems like a better overall name for the set of 
> > > > > > > attributes.
> > > > > > > 
> > > > > > > Token-Based Delayed Parsing
> > > > > > > ---------------------------
> > > > > > > 
> > > > > > > The solution introduces a token capture and delayed parsing 
> > > > > > > mechanism that
> > > > > > > stores tokens during initial parsing and performs the actual 
> > > > > > > parse later when
> > > > > > > the struct context is available. This isn't a novel idea, as the 
> > > > > > > OMP code does
> > > > > > > something similar for directives.
> > > > > > > 
> > > > > > > After storing the tokens, the parsing continues as if the 
> > > > > > > expression was parsed
> > > > > > > (but it hasn't been yet). The parsing is delayed until the
> > > > > > > 'verify_counted_by_attribute ()' call, which performs the actual 
> > > > > > > parse and
> > > > > > > reports any semantic errors. (The actual parse is done simply by 
> > > > > > > creating a new
> > > > > > > 'c_parser' object and filling it with the delayed tokens.)
> > > > > > > 
> > > > > > > On a successful parse, the 'C_TOKEN_VEC' tree node is converted 
> > > > > > > into a tree
> > > > > > > node holding an expression. The token vector is freed afterwards.
> > > > > > > 
> > > > > > > If this approach is deemed worthy, I would like to incorporate 
> > > > > > > the "single
> > > > > > > identifier" parsing into the delayed parsing mechanism (a single 
> > > > > > > identifier is
> > > > > > > just a simple expression).
> > > > > > > 
> > > > > > > RFC
> > > > > > > ---
> > > > > > > 
> > > > > > > - Is this something that GCC is interested in to get us past this 
> > > > > > > hurdle
> > > > > > >   that's delaying the upstreaming of more bounds safety checks?
> > > > > > > - Will this solve the issues at hand? (For this implementation, 
> > > > > > > I'm
> > > > > > >   specifically focusing struct field attributes. I haven't 
> > > > > > > thought much about
> > > > > > >   parameter list attributes.)
> > > > > > > - I think there's a layering violation. The 'c-decl.cc' 
> > > > > > > "verifies" the
> > > > > > >   counted_by argument, but it's in essence performing an 
> > > > > > > identifier resolution,
> > > > > > >   which is something the parser should be doing. Perhaps that 
> > > > > > > code should be
> > > > > > >   moved into "finish_struct ()", or somewhere else in 
> > > > > > > "c/c-parser.cc"?
> > > > > > > - My GCC-fu isn't strong and I may have abused some parts of the 
> > > > > > > parser in
> > > > > > >   unholy ways. (I blame beer.)
> > > > > > > - Anything else you'd like to say or recommend.
> > > > > > > 
> > > > > > > Disclaimer
> > > > > > > ----------
> > > > > > > 
> > > > > > > No AI's were harmed in the making of this RFC, though one did 
> > > > > > > have its feelings
> > > > > > > hurt.
> > > > > > > 
> > > > > > > Share and enjoy!
> > > > > > > -bw
> > > > > > > 
> > > > > > > 
> > > > > > > [1] 
> > > > > > > https://discourse.llvm.org/t/rfc-bounds-safety-in-c-syntax-compatibility-with-gcc/85885
> > > > > > > 
> > > > > > > ---
> > > > > > > To: gcc-patches@gcc.gnu.org
> > > > > > > Cc: Kees Cook <k...@kernel.org>
> > > > > > > Cc: Nick Desaulniers <nick.desaulni...@gmail.com>
> > > > > > > Cc: Martin Uecker <uec...@tugraz.at>
> > > > > > > Cc: Qing Zhao <qing.z...@oracle.com>
> > > > > > > Cc: Jakub Jelinek <ja...@redhat.com>
> > > > > > > Cc: Richard Biener <richard.guent...@gmail.com>
> > > > > > > Cc: Yeoul Na <yeoul...@apple.com>
> > > > > > > Cc: John McCall <rjmcc...@apple.com>
> > > > > > > Cc: Aaron Ballman <aa...@aaronballman.com>
> > > > > > > Cc: Justin Stitt <justinst...@google.com>
> > > > > > > 
> > > > > > > v1: - Initial RFC submitted.
> > > > > > >     - Kees Cook's Linus asbestos suit borrowed.
> > > > > > > ---
> > > > > > >  gcc/attribs.cc            |   8 ++-
> > > > > > >  gcc/c-family/c-attribs.cc |  37 +++++++++---
> > > > > > >  gcc/c/c-decl.cc           |  97 ++++++++++++++++++++++--------
> > > > > > >  gcc/c/c-parser.cc         | 123 
> > > > > > > ++++++++++++++++++++++++++++++++++++--
> > > > > > >  gcc/c/c-parser.h          |   1 +
> > > > > > >  gcc/c/c-typeck.cc         |  21 +++++++
> > > > > > >  6 files changed, 246 insertions(+), 41 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> > > > > > > index 3fce9d625256..74001889c72a 100644
> > > > > > > --- a/gcc/attribs.cc
> > > > > > > +++ b/gcc/attribs.cc
> > > > > > > @@ -752,8 +752,10 @@ decl_attributes (tree *node, tree 
> > > > > > > attributes, int flags,
> > > > > > >       }
> > > > > > >        else
> > > > > > >       {
> > > > > > > -       int nargs = list_length (args);
> > > > > > > -       if (nargs < spec->min_length
> > > > > > > +          int nargs = args && TREE_CODE (args) == C_TOKEN_VEC
> > > > > > > +                          ? 1
> > > > > > > +                          : list_length (args);
> > > > > > > +          if (nargs < spec->min_length
> > > > > > >             || (spec->max_length >= 0
> > > > > > >                 && nargs > spec->max_length))
> > > > > > >           {
> > > > > > > @@ -771,7 +773,7 @@ decl_attributes (tree *node, tree attributes, 
> > > > > > > int flags,
> > > > > > >                       spec->min_length, spec->max_length, nargs);
> > > > > > >             continue;
> > > > > > >           }
> > > > > > > -     }
> > > > > > > +        }
> > > > > > >        gcc_assert (is_attribute_p (spec->name, name));
> > > > > > > 
> > > > > > >        if (spec->decl_required && !DECL_P (*anode))
> > > > > > > diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> > > > > > > index 1f4a0df12051..0e8c17440b9a 100644
> > > > > > > --- a/gcc/c-family/c-attribs.cc
> > > > > > > +++ b/gcc/c-family/c-attribs.cc
> > > > > > > @@ -2887,7 +2887,14 @@ handle_counted_by_attribute (tree *node, 
> > > > > > > tree name,
> > > > > > >                            bool *no_add_attrs)
> > > > > > >  {
> > > > > > >    tree decl = *node;
> > > > > > > -  tree argval = TREE_VALUE (args);
> > > > > > > +  tree argval;
> > > > > > > +
> > > > > > > +  /* Handle both C_TOKEN_VEC and regular argument formats.  */
> > > > > > > +  if (TREE_CODE (args) == C_TOKEN_VEC)
> > > > > > > +    argval = args;
> > > > > > > +  else
> > > > > > > +    argval = TREE_VALUE (args);
> > > > > > > +
> > > > > > >    tree old_counted_by = lookup_attribute ("counted_by", 
> > > > > > > DECL_ATTRIBUTES (decl));
> > > > > > > 
> > > > > > >    /* This attribute is not supported in C++.  */
> > > > > > > @@ -2922,11 +2929,13 @@ handle_counted_by_attribute (tree *node, 
> > > > > > > tree name,
> > > > > > >               " array member field", name);
> > > > > > >        *no_add_attrs = true;
> > > > > > >      }
> > > > > > > -  /* The argument should be an identifier.  */
> > > > > > > -  else if (TREE_CODE (argval) != IDENTIFIER_NODE)
> > > > > > > +  /* The argument should be an identifier or a C_TOKEN_VEC for 
> > > > > > > complex
> > > > > > > +     expressions.  */
> > > > > > > +  else if (TREE_CODE (argval) != IDENTIFIER_NODE
> > > > > > > +           && TREE_CODE (argval) != C_TOKEN_VEC)
> > > > > > >      {
> > > > > > >        error_at (DECL_SOURCE_LOCATION (decl),
> > > > > > > -             "%<counted_by%> argument is not an identifier");
> > > > > > > +                "%<counted_by%> argument is not an identifier or 
> > > > > > > expression");
> > > > > > >        *no_add_attrs = true;
> > > > > > >      }
> > > > > > >    /* Issue error when there is a counted_by attribute with a 
> > > > > > > different
> > > > > > > @@ -2934,14 +2943,28 @@ handle_counted_by_attribute (tree *node, 
> > > > > > > tree name,
> > > > > > >    else if (old_counted_by != NULL_TREE)
> > > > > > >      {
> > > > > > >        tree old_fieldname = TREE_VALUE (TREE_VALUE 
> > > > > > > (old_counted_by));
> > > > > > > -      if (strcmp (IDENTIFIER_POINTER (old_fieldname),
> > > > > > > -               IDENTIFIER_POINTER (argval)) != 0)
> > > > > > > -     {
> > > > > > > +      /* Only check conflicts for simple identifiers; complex 
> > > > > > > expressions
> > > > > > > +         will be validated during struct completion.  */
> > > > > > > +      if (TREE_CODE (argval) == IDENTIFIER_NODE
> > > > > > > +          && TREE_CODE (old_fieldname) == IDENTIFIER_NODE
> > > > > > > +          && strcmp (IDENTIFIER_POINTER (old_fieldname),
> > > > > > > +                     IDENTIFIER_POINTER (argval))
> > > > > > > +                 != 0)
> > > > > > > +        {
> > > > > > >         error_at (DECL_SOURCE_LOCATION (decl),
> > > > > > >                   "%<counted_by%> argument %qE conflicts with"
> > > > > > >                   " previous declaration %qE", argval, 
> > > > > > > old_fieldname);
> > > > > > >         *no_add_attrs = true;
> > > > > > >       }
> > > > > > > +      else if (TREE_CODE (argval) == C_TOKEN_VEC
> > > > > > > +               || TREE_CODE (old_fieldname) == C_TOKEN_VEC)
> > > > > > > +        {
> > > > > > > +          /* For complex expressions, defer conflict checking to 
> > > > > > > struct
> > > > > > > +             completion.  */
> > > > > > > +          warning_at (DECL_SOURCE_LOCATION (decl), 
> > > > > > > OPT_Wattributes,
> > > > > > > +                      "multiple %<counted_by%> attributes on the 
> > > > > > > same field; "
> > > > > > > +                      "only the last one will be used");
> > > > > > > +        }
> > > > > > >      }
> > > > > > > 
> > > > > > >    return NULL_TREE;
> > > > > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > > > > index acbe2b88e674..615d0f5a1e88 100644
> > > > > > > --- a/gcc/c/c-decl.cc
> > > > > > > +++ b/gcc/c/c-decl.cc
> > > > > > > @@ -9445,43 +9445,90 @@ verify_counted_by_attribute (tree 
> > > > > > > struct_type, tree field_decl)
> > > > > > >    if (!attr_counted_by)
> > > > > > >      return;
> > > > > > > 
> > > > > > > -  /* If there is an counted_by attribute attached to the field,
> > > > > > > +  /* If there is a counted_by attribute attached to the field,
> > > > > > >       verify it.  */
> > > > > > > 
> > > > > > > -  tree fieldname = TREE_VALUE (TREE_VALUE (attr_counted_by));
> > > > > > > +  tree argument;
> > > > > > > +  tree parsed_expr = NULL_TREE;
> > > > > > > 
> > > > > > > -  /* Verify the argument of the attrbute is a valid field of the
> > > > > > > -     containing structure.  */
> > > > > > > -
> > > > > > > -  tree counted_by_field = lookup_field (struct_type, fieldname);
> > > > > > > -
> > > > > > > -  /* Error when the field is not found in the containing 
> > > > > > > structure and
> > > > > > > -     remove the corresponding counted_by attribute from the 
> > > > > > > field_decl.  */
> > > > > > > -  if (!counted_by_field)
> > > > > > > -    {
> > > > > > > -      error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > -             "argument %qE to the %<counted_by%> attribute"
> > > > > > > -             " is not a field declaration in the same structure"
> > > > > > > -             " as %qD", fieldname, field_decl);
> > > > > > > -      DECL_ATTRIBUTES (field_decl)
> > > > > > > -     = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > -    }
> > > > > > > +  /* Handle both C_TOKEN_VEC and regular argument formats */
> > > > > > > +  tree args = TREE_VALUE (attr_counted_by);
> > > > > > > +  if (TREE_CODE (args) == C_TOKEN_VEC)
> > > > > > > +    argument = args; /* Direct C_TOKEN_VEC */
> > > > > > >    else
> > > > > > > -  /* Error when the field is not with an integer type.  */
> > > > > > > +    argument = TREE_VALUE (args); /* Standard tree list format */
> > > > > > > +
> > > > > > > +  /* Handle both simple identifiers and complex expressions.  */
> > > > > > > +  if (TREE_CODE (argument) == IDENTIFIER_NODE)
> > > > > > >      {
> > > > > > > +      /* Simple identifier case - existing logic.  */
> > > > > > > +      tree counted_by_field = lookup_field (struct_type, 
> > > > > > > argument);
> > > > > > > +
> > > > > > > +      if (!counted_by_field)
> > > > > > > +        {
> > > > > > > +          error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > +                    "argument %qE to the %<counted_by%> 
> > > > > > > attribute"
> > > > > > > +                    " is not a field declaration in the same 
> > > > > > > structure"
> > > > > > > +                    " as %qD",
> > > > > > > +                    argument, field_decl);
> > > > > > > +          DECL_ATTRIBUTES (field_decl)
> > > > > > > +              = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > +          return;
> > > > > > > +        }
> > > > > > > +
> > > > > > > +      /* Find the actual field declaration.  */
> > > > > > >        while (TREE_CHAIN (counted_by_field))
> > > > > > >       counted_by_field = TREE_CHAIN (counted_by_field);
> > > > > > >        tree real_field = TREE_VALUE (counted_by_field);
> > > > > > > 
> > > > > > >        if (!INTEGRAL_TYPE_P (TREE_TYPE (real_field)))
> > > > > > >       {
> > > > > > > -       error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > -                 "argument %qE to the %<counted_by%> attribute"
> > > > > > > -                 " is not a field declaration with an integer 
> > > > > > > type",
> > > > > > > -                 fieldname);
> > > > > > > -       DECL_ATTRIBUTES (field_decl)
> > > > > > > +          error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > +                    "argument %qE to the %<counted_by%> 
> > > > > > > attribute"
> > > > > > > +                    " is not a field declaration with an integer 
> > > > > > > type",
> > > > > > > +                    argument);
> > > > > > > +          DECL_ATTRIBUTES (field_decl)
> > > > > > > +              = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > +          return;
> > > > > > > +        }
> > > > > > > +    }
> > > > > > > +  else if (TREE_CODE (argument) == C_TOKEN_VEC)
> > > > > > > +    {
> > > > > > > +      /* Complex expression case - parse the stored tokens.  */
> > > > > > > +      parsed_expr
> > > > > > > +          = c_parse_token_vec_expression_with_struct (argument, 
> > > > > > > struct_type);
> > > > > > > +
> > > > > > > +      if (!parsed_expr)
> > > > > > > +        {
> > > > > > > +          error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > +                    "invalid expression in %<counted_by%> 
> > > > > > > attribute");
> > > > > > > +          DECL_ATTRIBUTES (field_decl)
> > > > > > >           = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > -     }
> > > > > > > +          return;
> > > > > > > +        }
> > > > > > > +
> > > > > > > +      /* Validate that the expression result is integer type.  */
> > > > > > > +      if (!INTEGRAL_TYPE_P (TREE_TYPE (parsed_expr)))
> > > > > > > +        {
> > > > > > > +          error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > +                    "expression in %<counted_by%> attribute does 
> > > > > > > not"
> > > > > > > +                    " have integer type");
> > > > > > > +          DECL_ATTRIBUTES (field_decl)
> > > > > > > +              = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > +          return;
> > > > > > > +        }
> > > > > > > +
> > > > > > > +      /* If we successfully parsed the expression, replace the 
> > > > > > > C_TOKEN_VEC
> > > > > > > +         with the parsed expression for later use.  */
> > > > > > > +      TREE_VALUE (attr_counted_by) = build_tree_list (NULL_TREE, 
> > > > > > > parsed_expr);
> > > > > > > +    }
> > > > > > > +  else
> > > > > > > +    {
> > > > > > > +      error_at (DECL_SOURCE_LOCATION (field_decl),
> > > > > > > +                "invalid argument to %<counted_by%> attribute");
> > > > > > > +      DECL_ATTRIBUTES (field_decl)
> > > > > > > +          = remove_attribute ("counted_by", DECL_ATTRIBUTES 
> > > > > > > (field_decl));
> > > > > > > +      return;
> > > > > > >      }
> > > > > > >  }
> > > > > > > 
> > > > > > > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> > > > > > > index 5119841a5895..a9c641151d39 100644
> > > > > > > --- a/gcc/c/c-parser.cc
> > > > > > > +++ b/gcc/c/c-parser.cc
> > > > > > > @@ -5623,6 +5623,30 @@ c_parser_attribute_arguments (c_parser 
> > > > > > > *parser, bool takes_identifier,
> > > > > > >    return attr_args;
> > > > > > >  }
> > > > > > > 
> > > > > > > +static bool
> > > > > > > +c_parser_bounds_safety_attr (tree attr_name)
> > > > > > > +{
> > > > > > > +  const char *name = IDENTIFIER_POINTER (attr_name);
> > > > > > > +  return !strcmp (name, "counted_by");
> > > > > > > +}
> > > > > > > +
> > > > > > > +/* Check if the bounds safety attribute needs complex expression 
> > > > > > > parsing.  */
> > > > > > > +static bool
> > > > > > > +c_parser_needs_complex_bounds_parsing (c_parser *parser)
> > > > > > > +{
> > > > > > > +  /* Look ahead to see if this is a simple identifier or a 
> > > > > > > complex
> > > > > > > +     expression.  */
> > > > > > > +  c_token *tok = c_parser_peek_token (parser);
> > > > > > > +  if (tok->type != CPP_NAME)
> > > > > > > +    return true;
> > > > > > > +
> > > > > > > +  c_token *next = c_parser_peek_2nd_token (parser);
> > > > > > > +  if (next->type == CPP_CLOSE_PAREN)
> > > > > > > +    return false;
> > > > > > > +
> > > > > > > +  return true;
> > > > > > > +}
> > > > > > > +
> > > > > > >  /* Parse (possibly empty) gnu-attributes.  This is a GNU 
> > > > > > > extension.
> > > > > > > 
> > > > > > >     gnu-attributes:
> > > > > > > @@ -5692,12 +5716,56 @@ c_parser_gnu_attribute (c_parser *parser, 
> > > > > > > tree attrs,
> > > > > > >      }
> > > > > > >    c_parser_consume_token (parser);
> > > > > > > 
> > > > > > > -  tree attr_args
> > > > > > > -    = c_parser_attribute_arguments (parser,
> > > > > > > -                                 attribute_takes_identifier_p 
> > > > > > > (attr_name),
> > > > > > > -                                 false,
> > > > > > > -                                 is_attribute_p ("assume", 
> > > > > > > attr_name),
> > > > > > > -                                 true);
> > > > > > > +  tree attr_args;
> > > > > > > +  if (!c_parser_bounds_safety_attr (attr_name)
> > > > > > > +      || !c_parser_needs_complex_bounds_parsing (parser))
> > > > > > > +    attr_args = c_parser_attribute_arguments (
> > > > > > > +        parser, attribute_takes_identifier_p (attr_name), false,
> > > > > > > +        is_attribute_p ("assume", attr_name), true);
> > > > > > > +  else
> > > > > > > +    {
> > > > > > > +      unsigned int n = 1;
> > > > > > > +      unsigned int paren_count = 0;
> > > > > > > +
> > > > > > > +      for (; true; ++n)
> > > > > > > +        {
> > > > > > > +          c_token *tok = c_parser_peek_nth_token (parser, n);
> > > > > > > +
> > > > > > > +          /* Safety check to avoid infinite loops.  */
> > > > > > > +          if (tok->type == CPP_EOF)
> > > > > > > +            {
> > > > > > > +              c_parser_error (parser, "expected identifier or 
> > > > > > > expression");
> > > > > > > +              return error_mark_node;
> > > > > > > +            }
> > > > > > > +
> > > > > > > +          if (tok->type == CPP_CLOSE_PAREN)
> > > > > > > +            {
> > > > > > > +              if (!paren_count)
> > > > > > > +                break;
> > > > > > > +              paren_count--;
> > > > > > > +            }
> > > > > > > +          else if (tok->type == CPP_OPEN_PAREN)
> > > > > > > +            paren_count++;
> > > > > > > +          else if (tok->type == CPP_SEMICOLON)
> > > > > > > +            {
> > > > > > > +              c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
> > > > > > > +                                         "expected identifier or 
> > > > > > > expression");
> > > > > > > +              return error_mark_node;
> > > > > > > +            }
> > > > > > > +        }
> > > > > > > +
> > > > > > > +      vec<c_token, va_gc> *v;
> > > > > > > +      vec_alloc (v, n - 1);
> > > > > > > +      for (--n; n; --n)
> > > > > > > +        {
> > > > > > > +          c_token *tok = c_parser_peek_token (parser);
> > > > > > > +          v->quick_push (*tok);
> > > > > > > +          c_parser_consume_token (parser);
> > > > > > > +        }
> > > > > > > +
> > > > > > > +      attr_args = make_node (C_TOKEN_VEC);
> > > > > > > +      C_TOKEN_VEC_TOKENS (attr_args) = v;
> > > > > > > +    }
> > > > > > > 
> > > > > > >    attr = build_tree_list (attr_name, attr_args);
> > > > > > >    if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
> > > > > > > @@ -27746,6 +27814,49 @@ c_maybe_parse_omp_decl (tree decl, tree 
> > > > > > > d)
> > > > > > >    return true;
> > > > > > >  }
> > > > > > > 
> > > > > > > +/* Context for parsing counted_by expressions within struct 
> > > > > > > scope.  */
> > > > > > > +tree bounds_safety_attr_struct_type = NULL_TREE;
> > > > > > > +
> > > > > > > +/* Parse an expression from a C_TOKEN_VEC.  This is used for 
> > > > > > > delayed
> > > > > > > +   parsing of counted_by attribute expressions.  */
> > > > > > > +
> > > > > > > +tree
> > > > > > > +c_parse_token_vec_expression (tree token_vec)
> > > > > > > +{
> > > > > > > +  vec<c_token, va_gc> *tokens = C_TOKEN_VEC_TOKENS (token_vec);
> > > > > > > +
> > > > > > > +  if (!tokens || vec_safe_is_empty (tokens))
> > > > > > > +    return NULL_TREE;
> > > > > > > +
> > > > > > > +  /* Create a parser for just the list of tokens.  */
> > > > > > > +  c_parser delay_parser = {};
> > > > > > > +  delay_parser.tokens = tokens->address ();
> > > > > > > +  delay_parser.tokens_avail = tokens->length ();
> > > > > > > +  delay_parser.raw_tokens = tokens;
> > > > > > > +
> > > > > > > +  /* Parse the expression.  */
> > > > > > > +  c_expr expr = c_parser_expr_no_commas (&delay_parser, NULL);
> > > > > > > +
> > > > > > > +  if (expr.value == error_mark_node)
> > > > > > > +    return NULL_TREE;
> > > > > > > +
> > > > > > > +  return expr.value;
> > > > > > > +}
> > > > > > > +
> > > > > > > +/* Parse an expression from a C_TOKEN_VEC with struct context.  
> > > > > > > */
> > > > > > > +
> > > > > > > +tree
> > > > > > > +c_parse_token_vec_expression_with_struct (tree token_vec, tree 
> > > > > > > struct_type)
> > > > > > > +{
> > > > > > > +  tree saved_struct_type = bounds_safety_attr_struct_type;
> > > > > > > +  bounds_safety_attr_struct_type = struct_type;
> > > > > > > +
> > > > > > > +  tree result = c_parse_token_vec_expression (token_vec);
> > > > > > > +
> > > > > > > +  bounds_safety_attr_struct_type = saved_struct_type;
> > > > > > > +  return result;
> > > > > > > +}
> > > > > > > +
> > > > > > >  /* OpenMP 4.0:
> > > > > > >     # pragma omp declare target new-line
> > > > > > >     declarations and definitions
> > > > > > > diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
> > > > > > > index a84779bcbf83..577644cef13a 100644
> > > > > > > --- a/gcc/c/c-parser.h
> > > > > > > +++ b/gcc/c/c-parser.h
> > > > > > > @@ -205,5 +205,6 @@ extern void c_parser_declspecs (c_parser *, 
> > > > > > > struct c_declspecs *, bool, bool,
> > > > > > >                               enum c_lookahead_kind);
> > > > > > >  extern struct c_type_name *c_parser_type_name (c_parser *, bool 
> > > > > > > = false);
> > > > > > >  extern bool c_maybe_parse_omp_decl (tree, tree);
> > > > > > > +extern tree c_parse_token_vec_expression_with_struct (tree, 
> > > > > > > tree);
> > > > > > > 
> > > > > > >  #endif
> > > > > > > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> > > > > > > index f161bd9d0e74..788c0fe3763f 100644
> > > > > > > --- a/gcc/c/c-typeck.cc
> > > > > > > +++ b/gcc/c/c-typeck.cc
> > > > > > > @@ -56,6 +56,9 @@ along with GCC; see the file COPYING3.  If not 
> > > > > > > see
> > > > > > >  #include "tree-pretty-print-markup.h"
> > > > > > >  #include "gcc-urlifier.h"
> > > > > > > 
> > > > > > > +/* Forward declaration for bounds safety attribute context.  */
> > > > > > > +extern tree bounds_safety_attr_struct_type;
> > > > > > > +
> > > > > > >  /* Possible cases of implicit conversions.  Used to select 
> > > > > > > diagnostic messages
> > > > > > >     and control folding initializers in convert_for_assignment.  
> > > > > > > */
> > > > > > >  enum impl_conv {
> > > > > > > @@ -3528,6 +3531,24 @@ build_external_ref (location_t loc, tree 
> > > > > > > id, bool fun, tree *type)
> > > > > > >      return error_mark_node;
> > > > > > >    else
> > > > > > >      {
> > > > > > > +      /* Check if we're parsing a counted_by expression and can 
> > > > > > > resolve
> > > > > > > +         the identifier as a struct field.  */
> > > > > > > +      if (bounds_safety_attr_struct_type)
> > > > > > > +        {
> > > > > > > +          tree field = lookup_field 
> > > > > > > (bounds_safety_attr_struct_type, id);
> > > > > > > +          if (field)
> > > > > > > +            {
> > > > > > > +              /* We found a field - create a reference to it */
> > > > > > > +              while (TREE_CHAIN (field))
> > > > > > > +                field = TREE_CHAIN (field);
> > > > > > > +              tree real_field = TREE_VALUE (field);
> > > > > > > +
> > > > > > > +              ref = real_field;
> > > > > > > +              *type = TREE_TYPE (ref);
> > > > > > > +              return ref;
> > > > > > > +            }
> > > > > > > +        }
> > > > > > > +
> > > > > > >        undeclared_variable (loc, id);
> > > > > > >        return error_mark_node;
> > > > > > >      }
> > > > > > 
> > > > 
> > 

Reply via email to