Hi, Bill,

Thanks a lot for your effort to try to provide a consistent interface of 
counted_by attribute to the users.

Really appreciate for this.

However, given the current situation, I also think that provide two different 
interfaces from CLANG
and GCC might be the practical solution to this endless discussion. 

Can you explain a little bit on why “two versions will kill this feature in the 
Linux kernel”?

Qing

> On Jul 21, 2025, at 19:03, Bill Wendling <mo...@google.com> wrote:
> 
> On Mon, Jul 21, 2025 at 2:19 PM Martin Uecker <ma.uec...@gmail.com> wrote:
>> Am Montag, dem 21.07.2025 um 04:29 -0700 schrieb Bill Wendling:
>>> On Sun, Jul 20, 2025 at 4:41 AM Martin Uecker <ma.uec...@gmail.com> wrote:
>>> But first, as of this time, all of our efforts over the past several
>>> months to get an agreement on a syntax suitable for both Clang and GCC
>>> have failed, with both parties having issues with one or the others'
>>> suggestions. We're at loggerheads. If we can't get past this, then
>>> either there will be two competing versions of Clang's bounds safety
>>> checking (very bad), or only Clang will be able to support it (very
>>> very bad).
>> 
>> IMHO, having two versions may be preferable to dumping a lot of
>> technical debt all over the ecosystem.
> 
> Two versions will essentially kill this feature in the Linux kernel,
> as it's so much more difficult to maintain two diverging features,
> even behind macros.
> 
> And I don't see what I'm suggesting as technical debt of any kind. If
> approved, all issues about context and extent of use will be resolved.
> 
>>> Re original context: The 'struct c_parser' object doesn't have a lot
>>> of context in it. What I wrote below is a very simplified way of
>>> performing the delayed parsing, but it's just as valid to do something
>>> like:
>> 
>> You also need to worry about state outside of this object.
> 
> As I mentioned below, if there's more state outside of the c_parser
> object, I believe it should be consolidated into a 'struct
> c_context'-like object. Not having it in one place is itself technical
> debt, so it would be a nice cleanup.
> 
>>>  struct c_parser delayed_parser = *parser;
>>>  /* change the tokens and counts in 'delayed_parser' */
>>>  /* perform the delayed parsing */
>>> 
>>> Then 'parser' can go on its merry way, because it's not changed. If
>>> more context is needed, it's simple to push those onto a stack
>>> (probably defined in 'struct c_parser').
>>> 
>>>> For an attribute this may still be acceptable, but we need the same
>>>> thing for array sizes in C.  For a proper language feature, you
>>>> would  need to specify the context used to semantically interpret
>>>> the moved part of the program.  If you shuffle tokens around - which
>>>> we would also need to be able to do recursively, this becomes messy
>>>> quickly. And a C compiler would not just have to store tokens, but
>>>> has store and recreate the complete original semantic context, not
>>>> just for the current version of the language, but also for all
>>>> future versions. That simply sucks.
>>> 
>>> I didn't add a "Scope" section to my initial RFC, but I should have. I
>>> expect delayed parsing to be used for the bounds safety attributes.
>>> Full stop. If people want to expand it in the future, then great, we
>>> can burn that bridge when we come to it. :-)
>> 
>> In my experience, a bad precedent is terribly when trying to standardize
>> something better latter.
> 
> 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.
> 
>>> Semantic Analysis should be separate from parsing (I couldn't find any
>>> uses of 'struct c_parser' in c/c-decl.cc, but maybe that doesn't mean
>>> much). There shouldn't be anything interesting in the current 'struct
>>> c_parser' object that should interest SEMA. If there is, then it
>>> should probably reside in some type of 'struct c_context' object. (As
>>> I mentioned, though, I am not an expert on GCC's code base, so if
>>> there are other bits of context outside of 'struct c_parser' that
>>> should be accounted for, then they obviously will be added to the
>>> final implementation.)
>> 
>> It is not that other parts use state from c_parser but that the
>> parser drives semantic analyis by calling into the other parts,
>> which modify global state and all the types produced along the
>> way
> 
> We want types produced along the way. It's kind of the point of
> delayed parsing. :-) Otherwise, we could simply assume that all of the
> fields used in __counted_by have an integral type and, thus, have been
> seen already...maybe even generating a uniquely named temporary decl
> that would be replaced after the struct is parsed (not suggesting,
> because ew...). So in a sense, yes, we want the context to have
> changed by the time we do the actual parse of the attribute's
> contents. We need the struct and its contents to have proper types.
> The "proof of concept" below doesn't do it, but I would prefer this
> happen in 'finish_struct' or before it.
> 
>>> Keep in mind that the resolution performed on the single identifier
>>> operates with *no* context of how it was initially parsed. It performs
>>> a 'lookup_name' (with scope) and then runs through the TREE_CHAIN
>>> until it gets to the field.
>> 
>> If you only want delayed resolution of an identifier, then this is
>> not delayed parsing and one should limit it to looking up the
>> identifier later.  WG14 has  [.N] syntax under discussion and this
>> would do exactly this.
> 
> I disagree. It's definitely a form of delayed parsing, because a
> single identifier is an expression. The current implementation does a
> special check for it being a single identifier and then delays token
> resolution until the 'verify_counted_by_...' call. It just skips all
> of 'c_parse_...' calls that drill down to the 'CPP_ID_ID' case, which
> I think is why the code to skip through the TREE_CHAINs  exists.
> 
> I've asked before how forward declarations (or in this case the [.N]
> syntax) would solve the issues at hand, and didn't get a very good
> response (or perhaps I didn't understand it). It appears to me that it
> would simply allow name lookups to occur later on, but instead of
> sending the expression through the 'c_parser_*' routines, it would
> just loop through the parsed tree finding unresolved identifiers and
> performing the name lookups on them at that time. (I may be
> misrepresenting it, so please correct me.)
> 
> 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