c++: Accept C++11 attribute-definition [PR101582]

As the following testcase shows, we don't parse properly
C++11 attribute-declaration:
https://eel.is/c++draft/dcl.dcl#nt:attribute-declaration

cp_parser_toplevel_declaration just handles empty-declaration parsing
(with diagnostics for C++98) and otherwise calls cp_parser_declaration
which on it calls cp_parser_simple_declaration and rejects it with
"does not declare anything" permerror.

The following patch moves the handling of empty-declaration from
cp_parser_toplevel_declaration to cp_parser_declaration and
handles attribute-declaration in cp_parser_declaration
by parsing the attributes (standard ones only, we've never supported
__attribute__((...)); at namespace scope, so I'm not sure we need to
introduce that), which for C++98 emits the needed diagnostics, and then
warning if there are any attributes that we throw away on the floor.

I'll need this later for OpenMP directives at namespace scope, e.g.
[[omp::directive (requires, atomic_default_mem_order(seq_cst))]];
should be valid at namespace scope (and many other directives).

2021-07-30  Jakub Jelinek  <jakub@redhat.com>

	PR c++/101582
	* parser.c (cp_parser_skip_std_attribute_spec_seq): Add a forward
	declaration.
	(cp_parser_declaration): Parse empty-declaration and
	attribute-declaration.
	(cp_parser_toplevel_declaration): Don't parse empty-declaration here.

	* g++.dg/cpp0x/gen-attrs-45.C: Expect a warning about ignored
	attributes instead of error.
	* g++.dg/cpp0x/gen-attrs-75.C: New test.
	* g++.dg/modules/pr101582-1.C: New test.
This commit is contained in:
Jakub Jelinek 2021-07-30 10:30:16 +02:00
parent 291416d378
commit 77ab4e3be2
4 changed files with 71 additions and 9 deletions

View File

@ -2507,6 +2507,8 @@ static tree cp_parser_std_attribute_spec
(cp_parser *);
static tree cp_parser_std_attribute_spec_seq
(cp_parser *);
static size_t cp_parser_skip_std_attribute_spec_seq
(cp_parser *, size_t);
static size_t cp_parser_skip_attributes_opt
(cp_parser *, size_t);
static bool cp_parser_extension_opt
@ -14405,6 +14407,30 @@ cp_parser_declaration (cp_parser* parser, tree prefix_attrs)
cp_token *token2 = (token1->type == CPP_EOF
? token1 : cp_lexer_peek_nth_token (parser->lexer, 2));
if (token1->type == CPP_SEMICOLON)
{
cp_lexer_consume_token (parser->lexer);
/* A declaration consisting of a single semicolon is invalid
* before C++11. Allow it unless we're being pedantic. */
if (cxx_dialect < cxx11)
pedwarn (input_location, OPT_Wpedantic, "extra %<;%>");
return;
}
else if (cp_lexer_nth_token_is (parser->lexer,
cp_parser_skip_std_attribute_spec_seq (parser,
1),
CPP_SEMICOLON))
{
location_t attrs_loc = token1->location;
tree std_attrs = cp_parser_std_attribute_spec_seq (parser);
if (std_attrs != NULL_TREE)
warning_at (make_location (attrs_loc, attrs_loc, parser->lexer),
OPT_Wattributes, "attribute ignored");
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
return;
}
/* Get the high-water mark for the DECLARATOR_OBSTACK. */
void *p = obstack_alloc (&declarator_obstack, 0);
@ -14555,14 +14581,6 @@ cp_parser_toplevel_declaration (cp_parser* parser)
cp_parser_declaration. (A #pragma at block scope is
handled in cp_parser_statement.) */
cp_parser_pragma (parser, pragma_external, NULL);
else if (token->type == CPP_SEMICOLON)
{
cp_lexer_consume_token (parser->lexer);
/* A declaration consisting of a single semicolon is invalid
* before C++11. Allow it unless we're being pedantic. */
if (cxx_dialect < cxx11)
pedwarn (input_location, OPT_Wpedantic, "extra %<;%>");
}
else
/* Parse the declaration itself. */
cp_parser_declaration (parser, NULL_TREE);

View File

@ -1,4 +1,4 @@
// PR c++/52906
// { dg-do compile { target c++11 } }
[[gnu::deprecated]]; // { dg-error "does not declare anything" }
[[gnu::deprecated]]; // { dg-warning "attribute ignored" }

View File

@ -0,0 +1,35 @@
// PR c++/101582
// { dg-do compile }
// { dg-options "" }
;
[[]] [[]] [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
[[foobar]]; // { dg-warning "attribute ignored" }
// { dg-warning "attributes only available with" "" { target c++98_only } .-1 }
extern "C" ;
extern "C" [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
extern "C" extern "C" ;
extern "C" extern "C" [[]][[]][[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
__extension__ ;
__extension__ [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
__extension__ __extension__ ;
__extension__ __extension__ [[]][[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
namespace N {
;
[[]] [[]] [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
[[foobar]]; // { dg-warning "attribute ignored" }
// { dg-warning "attributes only available with" "" { target c++98_only } .-1 }
extern "C" ;
extern "C" [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
extern "C" extern "C" ;
extern "C" extern "C" [[]][[]][[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
__extension__ ;
__extension__ [[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
__extension__ __extension__ ;
__extension__ __extension__ [[]][[]]; // { dg-warning "attributes only available with" "" { target c++98_only } }
}

View File

@ -0,0 +1,9 @@
// PR c++/101582
// { dg-additional-options "-fmodules-ts" }
export module pr101582;
// { dg-module-cmi "pr101582" }
export ; // { dg-error "export declaration does not declare anything" "" { xfail *-*-* } }
export [[]]; // { dg-error "export declaration does not declare anything" "" { xfail *-*-* } }
export // { dg-error "export declaration does not declare anything" "" { xfail *-*-* } }
{
}