diff mbox series

[v3] c++: Fix parsing of invalid enum specifiers [PR90995]

Message ID 20200317082819.GU2156@tucnak
State New
Headers show
Series [v3] c++: Fix parsing of invalid enum specifiers [PR90995] | expand

Commit Message

Li, Pan2 via Gcc-patches March 17, 2020, 8:28 a.m. UTC
On Mon, Mar 16, 2020 at 06:01:25PM -0400, Jason Merrill wrote:
> > -	      type = NULL_TREE;
> > -	      goto out;
> > +	      error_at (cp_lexer_peek_token (parser->lexer)->location,
> > +			"expected %<;%> or %<{%>");
> > +	      return NULL_TREE;
> 
> Hmm, what happens if we commit_to_tentative_parse before the cp_parser_error
> if has_underlying_type?  That would also get us a diagnostic in this case
> even in enclosing tentative context.
> 
> And yes, I think returning error_mark_node seems appropriate; this is an
> enum-specifier, just an ill-formed one.

Seems to work too.  Bootstrapped/regtested on x86_64-linux and i686-linux,
ok for trunk?

2020-03-17  Jakub Jelinek  <jakub@redhat.com>

	PR c++/90995
	* parser.c (cp_parser_enum_specifier): Use temp_override for
	parser->colon_corrects_to_scope_p, replace goto out with return.
	If scoped enum or enum with underlying type is not followed by
	{ or ;, call cp_parser_commit_to_tentative_parse before calling
	cp_parser_error and make sure to return error_mark_node instead of
	NULL_TREE.  Formatting fixes.

	* g++.dg/cpp0x/enum40.C: New test.



	Jakub

Comments

Li, Pan2 via Gcc-patches March 17, 2020, 7:56 p.m. UTC | #1
On 3/17/20 4:28 AM, Jakub Jelinek wrote:
> On Mon, Mar 16, 2020 at 06:01:25PM -0400, Jason Merrill wrote:
>>> -	      type = NULL_TREE;
>>> -	      goto out;
>>> +	      error_at (cp_lexer_peek_token (parser->lexer)->location,
>>> +			"expected %<;%> or %<{%>");
>>> +	      return NULL_TREE;
>>
>> Hmm, what happens if we commit_to_tentative_parse before the cp_parser_error
>> if has_underlying_type?  That would also get us a diagnostic in this case
>> even in enclosing tentative context.
>>
>> And yes, I think returning error_mark_node seems appropriate; this is an
>> enum-specifier, just an ill-formed one.
> 
> Seems to work too.  Bootstrapped/regtested on x86_64-linux and i686-linux,
> ok for trunk?

OK, thanks.

> 2020-03-17  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/90995
> 	* parser.c (cp_parser_enum_specifier): Use temp_override for
> 	parser->colon_corrects_to_scope_p, replace goto out with return.
> 	If scoped enum or enum with underlying type is not followed by
> 	{ or ;, call cp_parser_commit_to_tentative_parse before calling
> 	cp_parser_error and make sure to return error_mark_node instead of
> 	NULL_TREE.  Formatting fixes.
> 
> 	* g++.dg/cpp0x/enum40.C: New test.
> 
> --- gcc/cp/parser.c.jj	2020-03-14 08:14:47.125740994 +0100
> +++ gcc/cp/parser.c	2020-03-17 07:57:19.195642249 +0100
> @@ -19001,9 +19001,7 @@ cp_parser_enum_specifier (cp_parser* par
>     bool is_unnamed = false;
>     tree underlying_type = NULL_TREE;
>     cp_token *type_start_token = NULL;
> -  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
> -
> -  parser->colon_corrects_to_scope_p = false;
> +  temp_override<bool> cleanup (parser->colon_corrects_to_scope_p, false);
>   
>     /* Parse tentatively so that we can back up if we don't find a
>        enum-specifier.  */
> @@ -19043,24 +19041,24 @@ cp_parser_enum_specifier (cp_parser* par
>   
>     push_deferring_access_checks (dk_no_check);
>     nested_name_specifier
> -      = cp_parser_nested_name_specifier_opt (parser,
> -					     /*typename_keyword_p=*/true,
> -					     /*check_dependency_p=*/false,
> -					     /*type_p=*/false,
> -					     /*is_declaration=*/false);
> +    = cp_parser_nested_name_specifier_opt (parser,
> +					   /*typename_keyword_p=*/true,
> +					   /*check_dependency_p=*/false,
> +					   /*type_p=*/false,
> +					   /*is_declaration=*/false);
>   
>     if (nested_name_specifier)
>       {
>         tree name;
>   
>         identifier = cp_parser_identifier (parser);
> -      name =  cp_parser_lookup_name (parser, identifier,
> -				     enum_type,
> -				     /*is_template=*/false,
> -				     /*is_namespace=*/false,
> -				     /*check_dependency=*/true,
> -				     /*ambiguous_decls=*/NULL,
> -				     input_location);
> +      name = cp_parser_lookup_name (parser, identifier,
> +				    enum_type,
> +				    /*is_template=*/false,
> +				    /*is_namespace=*/false,
> +				    /*check_dependency=*/true,
> +				    /*ambiguous_decls=*/NULL,
> +				    input_location);
>         if (name && name != error_mark_node)
>   	{
>   	  type = TREE_TYPE (name);
> @@ -19140,23 +19138,21 @@ cp_parser_enum_specifier (cp_parser* par
>       {
>         if (cxx_dialect < cxx11 || (!scoped_enum_p && !underlying_type))
>   	{
> +	  if (has_underlying_type)
> +	    cp_parser_commit_to_tentative_parse (parser);
>   	  cp_parser_error (parser, "expected %<{%>");
>   	  if (has_underlying_type)
> -	    {
> -	      type = NULL_TREE;
> -	      goto out;
> -	    }
> +	    return error_mark_node;
>   	}
>         /* An opaque-enum-specifier must have a ';' here.  */
>         if ((scoped_enum_p || underlying_type)
>   	  && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
>   	{
> +	  if (has_underlying_type)
> +	    cp_parser_commit_to_tentative_parse (parser);
>   	  cp_parser_error (parser, "expected %<;%> or %<{%>");
>   	  if (has_underlying_type)
> -	    {
> -	      type = NULL_TREE;
> -	      goto out;
> -	    }
> +	    return error_mark_node;
>   	}
>       }
>   
> @@ -19172,9 +19168,7 @@ cp_parser_enum_specifier (cp_parser* par
>   	  push_scope (nested_name_specifier);
>   	}
>         else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
> -	{
> -	  push_nested_namespace (nested_name_specifier);
> -	}
> +	push_nested_namespace (nested_name_specifier);
>       }
>   
>     /* Issue an error message if type-definitions are forbidden here.  */
> @@ -19334,12 +19328,8 @@ cp_parser_enum_specifier (cp_parser* par
>   	  pop_scope (nested_name_specifier);
>   	}
>         else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
> -	{
> -	  pop_nested_namespace (nested_name_specifier);
> -	}
> +	pop_nested_namespace (nested_name_specifier);
>       }
> - out:
> -  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
>     return type;
>   }
>   
> --- gcc/testsuite/g++.dg/cpp0x/enum40.C.jj	2020-03-15 22:35:43.413297557 +0100
> +++ gcc/testsuite/g++.dg/cpp0x/enum40.C	2020-03-15 22:35:43.413297557 +0100
> @@ -0,0 +1,26 @@
> +// PR c++/90995
> +// { dg-do compile { target c++11 } }
> +
> +void
> +foo ()
> +{
> +  enum : int a alignas;		// { dg-error "expected" }
> +}
> +
> +void
> +bar ()
> +{
> +  enum : int a;			// { dg-error "expected" }
> +}
> +
> +void
> +baz ()
> +{
> +  enum class a : int b alignas;	// { dg-error "expected" }
> +}
> +
> +void
> +qux ()
> +{
> +  enum class a : int b;		// { dg-error "expected" }
> +}
> 
> 
> 	Jakub
>
diff mbox series

Patch

--- gcc/cp/parser.c.jj	2020-03-14 08:14:47.125740994 +0100
+++ gcc/cp/parser.c	2020-03-17 07:57:19.195642249 +0100
@@ -19001,9 +19001,7 @@  cp_parser_enum_specifier (cp_parser* par
   bool is_unnamed = false;
   tree underlying_type = NULL_TREE;
   cp_token *type_start_token = NULL;
-  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
-
-  parser->colon_corrects_to_scope_p = false;
+  temp_override<bool> cleanup (parser->colon_corrects_to_scope_p, false);
 
   /* Parse tentatively so that we can back up if we don't find a
      enum-specifier.  */
@@ -19043,24 +19041,24 @@  cp_parser_enum_specifier (cp_parser* par
 
   push_deferring_access_checks (dk_no_check);
   nested_name_specifier
-      = cp_parser_nested_name_specifier_opt (parser,
-					     /*typename_keyword_p=*/true,
-					     /*check_dependency_p=*/false,
-					     /*type_p=*/false,
-					     /*is_declaration=*/false);
+    = cp_parser_nested_name_specifier_opt (parser,
+					   /*typename_keyword_p=*/true,
+					   /*check_dependency_p=*/false,
+					   /*type_p=*/false,
+					   /*is_declaration=*/false);
 
   if (nested_name_specifier)
     {
       tree name;
 
       identifier = cp_parser_identifier (parser);
-      name =  cp_parser_lookup_name (parser, identifier,
-				     enum_type,
-				     /*is_template=*/false,
-				     /*is_namespace=*/false,
-				     /*check_dependency=*/true,
-				     /*ambiguous_decls=*/NULL,
-				     input_location);
+      name = cp_parser_lookup_name (parser, identifier,
+				    enum_type,
+				    /*is_template=*/false,
+				    /*is_namespace=*/false,
+				    /*check_dependency=*/true,
+				    /*ambiguous_decls=*/NULL,
+				    input_location);
       if (name && name != error_mark_node)
 	{
 	  type = TREE_TYPE (name);
@@ -19140,23 +19138,21 @@  cp_parser_enum_specifier (cp_parser* par
     {
       if (cxx_dialect < cxx11 || (!scoped_enum_p && !underlying_type))
 	{
+	  if (has_underlying_type)
+	    cp_parser_commit_to_tentative_parse (parser);
 	  cp_parser_error (parser, "expected %<{%>");
 	  if (has_underlying_type)
-	    {
-	      type = NULL_TREE;
-	      goto out;
-	    }
+	    return error_mark_node;
 	}
       /* An opaque-enum-specifier must have a ';' here.  */
       if ((scoped_enum_p || underlying_type)
 	  && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
 	{
+	  if (has_underlying_type)
+	    cp_parser_commit_to_tentative_parse (parser);
 	  cp_parser_error (parser, "expected %<;%> or %<{%>");
 	  if (has_underlying_type)
-	    {
-	      type = NULL_TREE;
-	      goto out;
-	    }
+	    return error_mark_node;
 	}
     }
 
@@ -19172,9 +19168,7 @@  cp_parser_enum_specifier (cp_parser* par
 	  push_scope (nested_name_specifier);
 	}
       else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
-	{
-	  push_nested_namespace (nested_name_specifier);
-	}
+	push_nested_namespace (nested_name_specifier);
     }
 
   /* Issue an error message if type-definitions are forbidden here.  */
@@ -19334,12 +19328,8 @@  cp_parser_enum_specifier (cp_parser* par
 	  pop_scope (nested_name_specifier);
 	}
       else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
-	{
-	  pop_nested_namespace (nested_name_specifier);
-	}
+	pop_nested_namespace (nested_name_specifier);
     }
- out:
-  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
   return type;
 }
 
--- gcc/testsuite/g++.dg/cpp0x/enum40.C.jj	2020-03-15 22:35:43.413297557 +0100
+++ gcc/testsuite/g++.dg/cpp0x/enum40.C	2020-03-15 22:35:43.413297557 +0100
@@ -0,0 +1,26 @@ 
+// PR c++/90995
+// { dg-do compile { target c++11 } }
+
+void
+foo ()
+{
+  enum : int a alignas;		// { dg-error "expected" }
+}
+
+void
+bar ()
+{
+  enum : int a;			// { dg-error "expected" }
+}
+
+void
+baz ()
+{
+  enum class a : int b alignas;	// { dg-error "expected" }
+}
+
+void
+qux ()
+{
+  enum class a : int b;		// { dg-error "expected" }
+}