[v23,03/33] c++: Accept the use of built-in trait identifiers

Message ID 20231020135748.1846670-4-kmatsui@gcc.gnu.org
State Accepted
Headers
Series Optimize type traits performance |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Ken Matsui Oct. 20, 2023, 1:53 p.m. UTC
  This patch accepts the use of built-in trait identifiers when they are
actually not used as traits.  Specifically, we check if the subsequent token
is '(' for ordinary built-in traits or is '<' only for the special
__type_pack_element built-in trait.  If those identifiers are used
differently, the parser treats them as normal identifiers.  This allows
us to accept code like: struct __is_pointer {};.

gcc/cp/ChangeLog:

	* parser.cc (cp_lexer_lookup_trait): Rename to ...
	(cp_lexer_peek_trait): ... this.  Handle a subsequent token for
	the corresponding built-in trait.
	(cp_lexer_lookup_trait_expr): Rename to ...
	(cp_lexer_peek_trait_expr): ... this.
	(cp_lexer_lookup_trait_type): Rename to ...
	(cp_lexer_peek_trait_type): ... this.
	(cp_lexer_next_token_is_decl_specifier_keyword): Call
	cp_lexer_peek_trait_type.
	(cp_parser_simple_type_specifier): Likewise.
	(cp_parser_primary_expression): Call cp_lexer_peek_trait_expr.

Signed-off-by: Ken Matsui <kmatsui@gcc.gnu.org>
---
 gcc/cp/parser.cc | 47 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 30 insertions(+), 17 deletions(-)
  

Comments

Jason Merrill Oct. 23, 2023, 8:36 p.m. UTC | #1
On 10/20/23 09:53, Ken Matsui wrote:
> This patch accepts the use of built-in trait identifiers when they are
> actually not used as traits.  Specifically, we check if the subsequent token
> is '(' for ordinary built-in traits or is '<' only for the special
> __type_pack_element built-in trait.  If those identifiers are used
> differently, the parser treats them as normal identifiers.  This allows
> us to accept code like: struct __is_pointer {};.
> 
> +/* Peeks the corresponding built-in trait if a given token is
>      a built-in trait.  Otherwise, returns nullptr.  */
>   
>   static const cp_trait *
> +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)

Passing in both the lexer and the peeked token seems awkward, let's just 
pass in the lexer.  Looking up the peeked token again is fast.

>   {
> +  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
> +    {
> +      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
> +      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
> +
> +      /* Check if the subsequent token is a `<' token to
> +         __type_pack_element or is a `(' token to everything else.  */

git complains about indentation with spaces instead of a tab on this line.

Jason
  
Ken Matsui Oct. 23, 2023, 9:08 p.m. UTC | #2
On Mon, Oct 23, 2023 at 1:36 PM Jason Merrill <jason@redhat.com> wrote:
>
> On 10/20/23 09:53, Ken Matsui wrote:
> > This patch accepts the use of built-in trait identifiers when they are
> > actually not used as traits.  Specifically, we check if the subsequent token
> > is '(' for ordinary built-in traits or is '<' only for the special
> > __type_pack_element built-in trait.  If those identifiers are used
> > differently, the parser treats them as normal identifiers.  This allows
> > us to accept code like: struct __is_pointer {};.
> >
> > +/* Peeks the corresponding built-in trait if a given token is
> >      a built-in trait.  Otherwise, returns nullptr.  */
> >
> >   static const cp_trait *
> > +cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
>
> Passing in both the lexer and the peeked token seems awkward, let's just
> pass in the lexer.  Looking up the peeked token again is fast.
>
> >   {
> > +  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
> > +    {
> > +      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
> > +      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
> > +
> > +      /* Check if the subsequent token is a `<' token to
> > +         __type_pack_element or is a `(' token to everything else.  */
>
> git complains about indentation with spaces instead of a tab on this line.
>

Thank you!

> Jason
>
  

Patch

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f87d4c0a855..8b6c01e52c2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -246,12 +246,12 @@  static void cp_lexer_start_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
 static void cp_lexer_stop_debugging
   (cp_lexer *) ATTRIBUTE_UNUSED;
-static const cp_trait *cp_lexer_lookup_trait
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_expr
-  (const cp_token *);
-static const cp_trait *cp_lexer_lookup_trait_type
-  (const cp_token *);
+static const cp_trait *cp_lexer_peek_trait
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_expr
+  (cp_lexer *lexer, const cp_token *);
+static const cp_trait *cp_lexer_peek_trait_type
+  (cp_lexer *lexer, const cp_token *);
 
 static cp_token_cache *cp_token_cache_new
   (cp_token *, cp_token *);
@@ -1182,15 +1182,27 @@  cp_keyword_starts_decl_specifier_p (enum rid keyword)
     }
 }
 
-/* Look ups the corresponding built-in trait if a given token is
+/* Peeks the corresponding built-in trait if a given token is
    a built-in trait.  Otherwise, returns nullptr.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait (const cp_token *token)
+cp_lexer_peek_trait (cp_lexer *lexer, const cp_token *token1)
 {
-  if (token->type == CPP_NAME && IDENTIFIER_TRAIT_P (token->u.value))
-    return &cp_traits[IDENTIFIER_CP_INDEX (token->u.value)];
+  if (token1->type == CPP_NAME && IDENTIFIER_TRAIT_P (token1->u.value))
+    {
+      const cp_trait &trait = cp_traits[IDENTIFIER_CP_INDEX (token1->u.value)];
+      const bool is_pack_element = (trait.kind == CPTK_TYPE_PACK_ELEMENT);
+
+      /* Check if the subsequent token is a `<' token to
+         __type_pack_element or is a `(' token to everything else.  */
+      const cp_token *token2 = cp_lexer_peek_nth_token (lexer, 2);
+      if (is_pack_element && token2->type != CPP_LESS)
+	return nullptr;
+      if (!is_pack_element && token2->type != CPP_OPEN_PAREN)
+	return nullptr;
 
+      return &trait;
+    }
   return nullptr;
 }
 
@@ -1198,9 +1210,9 @@  cp_lexer_lookup_trait (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_expr (const cp_token *token)
+cp_lexer_peek_trait_expr (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && !trait->type)
     return trait;
 
@@ -1211,9 +1223,9 @@  cp_lexer_lookup_trait_expr (const cp_token *token)
    built-in trait.  */
 
 static const cp_trait *
-cp_lexer_lookup_trait_type (const cp_token *token)
+cp_lexer_peek_trait_type (cp_lexer *lexer, const cp_token *token1)
 {
-  const cp_trait *trait = cp_lexer_lookup_trait (token);
+  const cp_trait *trait = cp_lexer_peek_trait (lexer, token1);
   if (trait && trait->type)
     return trait;
 
@@ -1228,7 +1240,7 @@  cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
   cp_token *token;
 
   token = cp_lexer_peek_token (lexer);
-  if (cp_lexer_lookup_trait_type (token))
+  if (cp_lexer_peek_trait_type (lexer, token))
     return true;
   return cp_keyword_starts_decl_specifier_p (token->keyword);
 }
@@ -6107,7 +6119,8 @@  cp_parser_primary_expression (cp_parser *parser,
 	 `::' as the beginning of a qualified-id, or the "operator"
 	 keyword.  */
     case CPP_NAME:
-      if (const cp_trait* trait = cp_lexer_lookup_trait_expr (token))
+      if (const cp_trait* trait
+	  = cp_lexer_peek_trait_expr (parser->lexer, token))
 	return cp_parser_trait (parser, trait);
       /* FALLTHRU */
     case CPP_SCOPE:
@@ -20116,7 +20129,7 @@  cp_parser_simple_type_specifier (cp_parser* parser,
     }
 
   /* If token is a type-yielding built-in traits, parse it.  */
-  const cp_trait* trait = cp_lexer_lookup_trait_type (token);
+  const cp_trait* trait = cp_lexer_peek_trait_type (parser->lexer, token);
   if (trait)
     {
       type = cp_parser_trait (parser, trait);