$NetBSD: patch-gcc_cp_parser.cc,v 1.2 2025/06/08 07:37:45 wiz Exp $

Support Darwin/aarch64, from https://github.com/Homebrew/formula-patches.

--- gcc/cp/parser.cc.orig	2025-05-23 11:02:04.548201561 +0000
+++ gcc/cp/parser.cc
@@ -705,6 +705,91 @@ cp_lexer_handle_early_pragma (cp_lexer *
 static cp_parser *cp_parser_new (cp_lexer *);
 static GTY (()) cp_parser *the_parser;
 
+/* Context-sensitive parse-checking for clang-style attributes.  */
+
+enum clang_attr_state {
+  CA_NONE = 0,
+  CA_ATTR,
+  CA_BR1, CA_BR2,
+  CA_LIST,
+  CA_LIST_ARGS,
+  CA_IS_CA,
+  CA_CA_ARGS,
+  CA_LIST_CONT
+};
+
+/* State machine tracking context of attribute lexing.  */
+
+static enum clang_attr_state
+cp_lexer_attribute_state (cp_token& token, enum clang_attr_state attr_state)
+{
+  /* Implement a context-sensitive parser for clang attributes.
+     We detect __attribute__((clang_style_attribute (ARGS))) and lex the
+     args ARGS with the following differences from GNU attributes:
+	(a) number-like values are lexed as strings [this allows lexing XX.YY.ZZ
+	   version numbers].
+	(b) we concatenate strings, since clang attributes allow this too.  */
+  switch (attr_state)
+    {
+    case CA_NONE:
+      if (token.type == CPP_KEYWORD
+	  && token.keyword == RID_ATTRIBUTE)
+	attr_state = CA_ATTR;
+      break;
+    case CA_ATTR:
+      if (token.type == CPP_OPEN_PAREN)
+	attr_state = CA_BR1;
+      else
+	attr_state = CA_NONE;
+      break;
+    case CA_BR1:
+      if (token.type == CPP_OPEN_PAREN)
+	attr_state = CA_BR2;
+      else
+	attr_state = CA_NONE;
+      break;
+    case CA_BR2:
+      if (token.type == CPP_NAME)
+	{
+	  tree identifier = (token.type == CPP_KEYWORD)
+	    /* For keywords, use the canonical spelling, not the
+	       parsed identifier.  */
+	    ? ridpointers[(int) token.keyword]
+	    : token.u.value;
+	  identifier = canonicalize_attr_name (identifier);
+	  if (attribute_clang_form_p (identifier))
+	    attr_state = CA_IS_CA;
+	  else
+	    attr_state = CA_LIST;
+	}
+      else
+	attr_state = CA_NONE;
+      break;
+    case CA_IS_CA:
+    case CA_LIST:
+      if (token.type == CPP_COMMA)
+	attr_state = CA_BR2; /* Back to the list outer.  */
+      else if (token.type == CPP_OPEN_PAREN)
+	attr_state = attr_state == CA_IS_CA ? CA_CA_ARGS
+					    : CA_LIST_ARGS;
+      else
+	attr_state = CA_NONE;
+      break;
+    case CA_CA_ARGS: /* We will special-case args in this state.  */
+    case CA_LIST_ARGS:
+      if (token.type == CPP_CLOSE_PAREN)
+	attr_state = CA_LIST_CONT;
+      break;
+    case CA_LIST_CONT:
+      if (token.type == CPP_COMMA)
+	attr_state = CA_BR2; /* Back to the list outer.  */
+      else
+	attr_state = CA_NONE;
+      break;
+    }
+  return attr_state;
+}
+
 /* Create a new main C++ lexer, the lexer that gets tokens from the
    preprocessor, and also create the main parser.  */
 
@@ -721,6 +806,8 @@ cp_lexer_new_main (void)
   c_common_no_more_pch ();
 
   cp_lexer *lexer = cp_lexer_alloc ();
+  enum clang_attr_state attr_state = CA_NONE;
+
   /* Put the first token in the buffer.  */
   cp_token *tok = lexer->buffer->quick_push (token);
 
@@ -744,8 +831,14 @@ cp_lexer_new_main (void)
       if (tok->type == CPP_PRAGMA_EOL)
 	cp_lexer_handle_early_pragma (lexer);
 
+      attr_state = cp_lexer_attribute_state (*tok, attr_state);
       tok = vec_safe_push (lexer->buffer, cp_token ());
-      cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok);
+      unsigned int flags = C_LEX_STRING_NO_JOIN;
+      /* If we are processing clang-style attribute args, lex numbers as
+         potential version strings; NN .. NN.MM .. NN.MM.OO */
+      if (attr_state == CA_CA_ARGS)
+	flags |= C_LEX_NUMBER_AS_STRING;
+      cp_lexer_get_preprocessor_token (flags, tok);
     }
 
   lexer->next_token = lexer->buffer->address ();
@@ -962,7 +1055,7 @@ cp_lexer_get_preprocessor_token (unsigne
 {
   static int is_extern_c = 0;
 
-   /* Get a new token from the preprocessor.  */
+   /* Get a new token from the preprocessor. */
   token->type
     = c_lex_with_flags (&token->u.value, &token->location, &token->flags,
 			flags);
@@ -23390,9 +23483,16 @@ cp_parser_init_declarator (cp_parser* pa
 		      "an %<asm%> specification is not allowed "
 		      "on a function-definition");
 	  if (attributes)
-	    error_at (attributes_start_token->location,
-		      "attributes are not allowed "
-		      "on a function-definition");
+	    {
+	      /* When we are allowing attributes in this position, then add
+		 them to the prefix ones.  */
+	      if (flag_allow_ext_attr_placement)
+		prefix_attributes = chainon (prefix_attributes, attributes);
+	      else
+		error_at (attributes_start_token->location,
+			  "attributes are not allowed "
+			  "on a function-definition");
+	    }
 	  /* This is a function-definition.  */
 	  *function_definition_p = true;
 
@@ -29781,6 +29881,91 @@ cp_parser_gnu_attributes_opt (cp_parser*
   return attributes;
 }
 
+/* Parse the arguments list for a clang attribute.   */
+static tree
+cp_parser_clang_attribute (cp_parser *parser, tree/*attr_id*/)
+{
+  /* Each entry can be :
+     identifier
+     identifier=N.MM.Z
+     identifier="string"
+     followed by ',' or ) for the last entry*/
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return NULL;
+
+  bool save_translate_strings_p = parser->translate_strings_p;
+  parser->translate_strings_p = false;
+  tree attr_args = NULL_TREE;
+  cp_token *token;
+  do
+    {
+      tree name = NULL_TREE;
+      tree value = NULL_TREE;
+
+      token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_NAME)
+	name = token->u.value;
+      else if (token->type == CPP_KEYWORD)
+	name = ridpointers[(int) token->keyword];
+      else if (token->flags & NAMED_OP)
+	name = get_identifier (cpp_type2name (token->type, token->flags));
+      else
+	{
+	  /* FIXME: context-sensitive for that attrib.  */
+	  error_at (token->location, "expected an attribute keyword");
+	  cp_parser_skip_to_closing_parenthesis (parser,
+						 /*recovering=*/true,
+						 /*or_comma=*/false,
+						 /*consume_paren=*/false);
+	  attr_args = error_mark_node;
+	  break;
+	}
+      cp_lexer_consume_token (parser->lexer);
+
+      if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+	{
+	  cp_lexer_consume_token (parser->lexer); /* eat the '=' */
+	  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+	      && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+	    {
+	      token = cp_lexer_peek_token (parser->lexer);
+	      if (token->type == CPP_STRING)
+		value = cp_parser_string_literal (parser, /*translate=*/false,
+					    /*wide_ok=*/false);
+	      else
+		{
+		  value = token->u.value;
+		  cp_lexer_consume_token (parser->lexer);
+		}
+	    }
+	  /* else value is missing.  */
+	}
+      else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+	       && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+	{
+	  error_at (token->location, "expected %<,%>, %<=%> or %<)%>");
+	  cp_parser_skip_to_closing_parenthesis (parser,
+						 /*recovering=*/true,
+						 /*or_comma=*/false,
+						 /*consume_paren=*/false);
+	  attr_args = error_mark_node;
+	  break;
+	}
+    if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+      cp_lexer_consume_token (parser->lexer);
+    tree t = tree_cons (value, name, NULL_TREE);
+    attr_args = chainon (attr_args, t);
+  } while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN));
+
+  parser->translate_strings_p = save_translate_strings_p;
+  if (!parens.require_close (parser))
+    return error_mark_node;
+
+  return attr_args;
+}
+
 /* Parse a GNU attribute-list.
 
    attribute-list:
@@ -29840,9 +30025,12 @@ cp_parser_gnu_attribute_list (cp_parser*
 
 	  /* Peek at the next token.  */
 	  token = cp_lexer_peek_token (parser->lexer);
-	  /* If it's an `(', then parse the attribute arguments.  */
-	  if (token->type == CPP_OPEN_PAREN)
+	  if (token->type == CPP_OPEN_PAREN
+	      && attribute_clang_form_p (identifier))
+	    arguments = cp_parser_clang_attribute (parser, identifier);
+	  else if (token->type == CPP_OPEN_PAREN)
 	    {
+	      /* If it's an `(', then parse the attribute arguments.  */
 	      vec<tree, va_gc> *vec;
 	      int attr_flag = (attribute_takes_identifier_p (identifier)
 			       ? id_attr : normal_attr);
@@ -29859,12 +30047,12 @@ cp_parser_gnu_attribute_list (cp_parser*
 		  arguments = build_tree_list_vec (vec);
 		  release_tree_vector (vec);
 		}
-	      /* Save the arguments away.  */
-	      TREE_VALUE (attribute) = arguments;
 	    }
 
 	  if (arguments != error_mark_node)
 	    {
+	      /* Save the arguments away.  */
+	      TREE_VALUE (attribute) = arguments;
 	      /* Add this attribute to the list.  */
 	      TREE_CHAIN (attribute) = attribute_list;
 	      attribute_list = attribute;
