[PATCH] c++: Fix up parsing of attributes for using-directive

Jason Merrill jason@redhat.com
Wed Aug 11 20:20:17 GMT 2021


On 8/4/21 6:05 AM, Jakub Jelinek wrote:
> Hi!
> 
> As I've said earlier and added xfails in gen-attrs-76.C test,
> https://eel.is/c++draft/namespace.udir#nt:using-directive
> has attribute-specifier-seq[opt] at the start, not at the end before ;
> as gcc is expecting.
> IMHO we should continue parsing at the end the GNU attributes
> because using namespace N __attribute__((strong));, while not supported
> anymore, used to be supported in the past, but my code searches for
> using namespace N [[gnu::strong]]; didn't reveal anything at all.

> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> 2021-08-04  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* parser.c (cp_parser_block_declaration): Call
> 	cp_parser_using_directive for C++11 attributes followed by
> 	using namespace tokens.
> 	(cp_parser_using_directive): Parse C++11 attributes at the start
> 	of the directive rather than at the end, only parse GNU attributes
> 	at the end.
> 
> 	* g++.dg/lookup/strong-using.C: Add test using [[gnu::strong]]
> 	as well.
> 	* g++.dg/lookup/strong-using2.C: Likewise.
> 	* g++.dg/cpp0x/gen-attrs-58.C: Move alignas(int) before
> 	using namespace.
> 	* g++.dg/cpp0x/gen-attrs-59.C: Move alignas(X) before
> 	using namespace, add tests for alignas before semicolon.
> 	* g++.dg/cpp0x/gen-attrs-76.C: Remove xfails.  Add test for
> 	C++11 attributes on using directive before semicolon.
> 
> --- gcc/cp/parser.c.jj	2021-08-03 00:44:32.890492433 +0200
> +++ gcc/cp/parser.c	2021-08-03 17:38:07.541725977 +0200
> @@ -14655,6 +14655,7 @@ cp_parser_block_declaration (cp_parser *
>     /* Peek at the next token to figure out which kind of declaration is
>        present.  */
>     cp_token *token1 = cp_lexer_peek_token (parser->lexer);
> +  size_t attr_idx;
>   
>     /* If the next keyword is `asm', we have an asm-definition.  */
>     if (token1->keyword == RID_ASM)
> @@ -14708,6 +14709,18 @@ cp_parser_block_declaration (cp_parser *
>     /* If the next token is `static_assert' we have a static assertion.  */
>     else if (token1->keyword == RID_STATIC_ASSERT)
>       cp_parser_static_assert (parser, /*member_p=*/false);
> +  /* If the next tokens after attributes is `using namespace', then we have
> +     a using-directive.  */
> +  else if ((attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1)) != 1
> +	   && cp_lexer_peek_nth_token (parser->lexer,
> +				       attr_idx)->keyword == RID_USING
> +	   && cp_lexer_peek_nth_token (parser->lexer,
> +				       attr_idx + 1)->keyword == RID_NAMESPACE)

Let's use cp_lexer_nth_token_is_keyword here.  OK with that change.

> +    {
> +      if (statement_p)
> +	cp_parser_commit_to_tentative_parse (parser);
> +      cp_parser_using_directive (parser);
> +    }
>     /* Anything else must be a simple-declaration.  */
>     else
>       cp_parser_simple_declaration (parser, !statement_p,
> @@ -21394,14 +21407,21 @@ cp_parser_alias_declaration (cp_parser*
>   /* Parse a using-directive.
>   
>      using-directive:
> -     using namespace :: [opt] nested-name-specifier [opt]
> -       namespace-name ;  */
> +     attribute-specifier-seq [opt] using namespace :: [opt]
> +       nested-name-specifier [opt] namespace-name ;  */
>   
>   static void
>   cp_parser_using_directive (cp_parser* parser)
>   {
>     tree namespace_decl;
> -  tree attribs;
> +  tree attribs = cp_parser_std_attribute_spec_seq (parser);
> +  if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
> +    {
> +      /* Error during attribute parsing that resulted in skipping
> +	 to next semicolon.  */
> +      cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
> +      return;
> +    }
>   
>     /* Look for the `using' keyword.  */
>     cp_parser_require_keyword (parser, RID_USING, RT_USING);
> @@ -21418,8 +21438,9 @@ cp_parser_using_directive (cp_parser* pa
>     /* Get the namespace being used.  */
>     namespace_decl = cp_parser_namespace_name (parser);
>     cp_warn_deprecated_use_scopes (namespace_decl);
> -  /* And any specified attributes.  */
> -  attribs = cp_parser_attributes_opt (parser);
> +  /* And any specified GNU attributes.  */
> +  if (cp_next_tokens_can_be_gnu_attribute_p (parser))
> +    attribs = chainon (attribs, cp_parser_gnu_attributes_opt (parser));
>   
>     /* Update the symbol table.  */
>     finish_using_directive (namespace_decl, attribs);
> --- gcc/testsuite/g++.dg/lookup/strong-using.C.jj	2020-01-12 11:54:37.197401580 +0100
> +++ gcc/testsuite/g++.dg/lookup/strong-using.C	2021-08-03 17:12:05.872281490 +0200
> @@ -8,3 +8,12 @@ namespace A
>   
>     using namespace B __attribute__ ((strong)); // { dg-warning "no longer supported" "" }
>   }
> +
> +namespace C
> +{
> +  namespace D // { dg-message "inline namespace" }
> +  {
> +  }
> +
> +  [[gnu::strong]] using namespace D; // { dg-warning "no longer supported" "" }
> +}
> --- gcc/testsuite/g++.dg/lookup/strong-using2.C.jj	2020-01-12 11:54:37.197401580 +0100
> +++ gcc/testsuite/g++.dg/lookup/strong-using2.C	2021-08-03 17:12:31.968921065 +0200
> @@ -9,3 +9,12 @@ namespace A
>   
>     using namespace B __attribute__ ((strong)); // { dg-bogus "no longer supported" }
>   }
> +
> +namespace C
> +{
> +  namespace D // { dg-bogus "inline namespace" }
> +  {
> +  }
> +
> +  [[gnu::strong]] using namespace D; // { dg-bogus "no longer supported" }
> +}
> --- gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C.jj	2020-01-12 11:54:37.072403466 +0100
> +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C	2021-08-03 17:19:06.218477375 +0200
> @@ -2,4 +2,4 @@
>   // { dg-do compile { target c++11 } }
>   
>   namespace N { int i; }
> -using namespace N alignas(int); // { dg-warning "ignored" }
> +alignas(int) using namespace N; // { dg-warning "ignored" }
> --- gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C.jj	2020-01-12 11:54:37.072403466 +0100
> +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C	2021-08-03 17:43:54.722937966 +0200
> @@ -2,4 +2,11 @@
>   // { dg-do compile { target c++11 } }
>   
>   namespace N {}
> -using namespace N alignas(X); // { dg-error "declared" }
> +alignas(X) using namespace N; // { dg-error "declared" }
> +namespace O {}
> +using namespace O alignas(X); // { dg-error "expected" }
> +// { dg-error "declared" "" { target *-*-* } .-1 }
> +// { dg-warning "attribute ignored" "" { target *-*-* } .-2 }
> +namespace P {}
> +using namespace P alignas(int); // { dg-error "expected" }
> +// { dg-warning "attribute ignored" "" { target *-*-* } .-1 }
> --- gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C.jj	2021-07-31 09:17:09.288342624 +0200
> +++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C	2021-08-03 17:10:47.187368210 +0200
> @@ -3,6 +3,7 @@
>   
>   namespace N {}
>   namespace O { typedef int T; };
> +namespace P {}
>   
>   void
>   foo ()
> @@ -11,7 +12,8 @@ foo ()
>     [[]] __extension__ asm ("");			// { dg-error "expected" }
>     __extension__ [[]] asm ("");			// { dg-error "expected" }
>     [[]] namespace M = ::N;			// { dg-error "expected" }
> -  [[]] using namespace N;			// { dg-bogus "expected" "" { xfail *-*-* } }
> +  [[]] using namespace N;			// { dg-bogus "expected" }
> +  using namespace P [[]];			// { dg-error "expected" }
>     [[]] using O::T;				// { dg-error "expected" }
>     [[]] __label__ foo;				// { dg-error "expected" }
>     [[]] static_assert (true, "");		// { dg-error "expected" }
> @@ -24,7 +26,8 @@ bar ()
>     [[gnu::unused]] __extension__ asm ("");	// { dg-error "expected" }
>     __extension__ [[gnu::unused]] asm ("");	// { dg-error "expected" }
>     [[gnu::unused]] namespace M = ::N;		// { dg-error "expected" }
> -  [[gnu::unused]] using namespace N;		// { dg-bogus "expected" "" { xfail *-*-* } }
> +  [[gnu::unused]] using namespace N;		// { dg-bogus "expected" }
> +  using namespace P [[gnu::unused]];		// { dg-error "expected" }
>     [[gnu::unused]] using O::T;			// { dg-error "expected" }
>     [[gnu::unused]] __label__ foo;		// { dg-error "expected" }
>     [[gnu::unused]] static_assert (true, "");	// { dg-error "expected" }
> 
> 	Jakub
> 



More information about the Gcc-patches mailing list