c++: Fix up parsing of attributes for using-directive
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. 2021-08-12 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.
This commit is contained in:
parent
2bdf17de1d
commit
3890c28ac5
|
@ -14853,6 +14853,7 @@ cp_parser_block_declaration (cp_parser *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)
|
||||
|
@ -14906,6 +14907,18 @@ cp_parser_block_declaration (cp_parser *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_nth_token_is_keyword (parser->lexer, attr_idx,
|
||||
RID_USING)
|
||||
&& cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx + 1,
|
||||
RID_NAMESPACE))
|
||||
{
|
||||
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,
|
||||
|
@ -21609,14 +21622,21 @@ cp_parser_alias_declaration (cp_parser* 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);
|
||||
|
@ -21633,8 +21653,9 @@ cp_parser_using_directive (cp_parser* parser)
|
|||
/* 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);
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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" "" }
|
||||
}
|
||||
|
|
|
@ -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" }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue