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:
> > I think the question is not whether this could be done somehow,
> > but whether it should.  Why design a language feature that requires
> > storing tokens and parsing it outside the original context?
> 
> Fine, and I'm willing to have this discussion, but that wasn't the
> initial issue, which was that GCC's C parser isn't able to perform a
> "double parsing" of tokens. The issue is built into the design of
> GCC's parser, which is a one-pass parser. Delayed parsing isn't a new
> feature within the C parser (it's used by OMP for instance). If the
> worry is about context, I address that more below.

I think this is just for locally rewriting C23 attribute form
into pragma form in place.  I think it is not really delayed parsing,
but I am not very familiar with this part of the code.

> 
> 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.

> 
> 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.

> 
>   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.

> 
> 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

> 
> 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.

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