diff options
author | Nathaniel Shead <nathanieloshead@gmail.com> | 2023-11-24 16:26:43 +1100 |
---|---|---|
committer | Nathaniel Shead <nathanieloshead@gmail.com> | 2024-01-07 21:04:17 +1100 |
commit | 7f24446a3cf67d1346c78b4667fba74b73a23302 (patch) | |
tree | 0b0b81f427592ab946fb6f9619bb511948563900 /gcc/cp | |
parent | e74c37aab51d2350a3417f442c3a7d119b755378 (diff) | |
download | gcc-7f24446a3cf67d1346c78b4667fba74b73a23302.zip gcc-7f24446a3cf67d1346c78b4667fba74b73a23302.tar.gz gcc-7f24446a3cf67d1346c78b4667fba74b73a23302.tar.bz2 |
c++: Follow module grammar more closely [PR110808]
This patch cleans up the parsing of module-declarations and
import-declarations to more closely follow the grammar defined by the
standard.
For instance, currently we allow declarations like 'import A:B', even
from an unrelated source file (not part of module A), which causes
errors in merging declarations. However, the syntax in [module.import]
doesn't even allow this form of import, so this patch prevents this from
parsing at all and avoids the error that way.
Additionally, we sometimes allow statements like 'import :X' or
'module :X' even when not in a named module, and this causes segfaults,
so we disallow this too.
PR c++/110808
gcc/cp/ChangeLog:
* parser.cc (cp_parser_module_name): Rewrite to handle
module-names and module-partitions independently.
(cp_parser_module_partition): New function.
(cp_parser_module_declaration): Parse module partitions
explicitly. Don't change state if parsing module decl failed.
(cp_parser_import_declaration): Handle different kinds of
import-declarations locally.
gcc/testsuite/ChangeLog:
* g++.dg/modules/part-hdr-1_c.C: Fix syntax.
* g++.dg/modules/part-mac-1_c.C: Likewise.
* g++.dg/modules/mod-invalid-1.C: New test.
* g++.dg/modules/part-8_a.C: New test.
* g++.dg/modules/part-8_b.C: New test.
* g++.dg/modules/part-8_c.C: New test.
Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/parser.cc | 100 |
1 files changed, 66 insertions, 34 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 37536fa..bc1683b 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -14894,58 +14894,64 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p, /* Modules */ -/* Parse a module-name, - identifier - module-name . identifier - header-name +/* Parse a module-name or module-partition. - Returns a pointer to module object, NULL. */ + module-name: + module-name-qualifier [opt] identifier -static module_state * -cp_parser_module_name (cp_parser *parser) -{ - cp_token *token = cp_lexer_peek_token (parser->lexer); - if (token->type == CPP_HEADER_NAME) - { - cp_lexer_consume_token (parser->lexer); + module-partition: + : module-name-qualifier [opt] identifier - return get_module (token->u.value); - } + module-name-qualifier: + identifier . + module-name-qualifier identifier . - module_state *parent = NULL; - bool partitioned = false; - if (token->type == CPP_COLON && named_module_p ()) - { - partitioned = true; - cp_lexer_consume_token (parser->lexer); - } + Returns a pointer to the module object, or NULL on failure. + For PARTITION_P, PARENT is the module this is a partition of. */ + +static module_state * +cp_parser_module_name (cp_parser *parser, bool partition_p = false, + module_state *parent = NULL) +{ + if (partition_p + && cp_lexer_consume_token (parser->lexer)->type != CPP_COLON) + return NULL; for (;;) { if (cp_lexer_peek_token (parser->lexer)->type != CPP_NAME) { - cp_parser_error (parser, "expected module-name"); - break; + if (partition_p) + cp_parser_error (parser, "expected module-partition"); + else + cp_parser_error (parser, "expected module-name"); + return NULL; } tree name = cp_lexer_consume_token (parser->lexer)->u.value; - parent = get_module (name, parent, partitioned); - token = cp_lexer_peek_token (parser->lexer); - if (!partitioned && token->type == CPP_COLON) - partitioned = true; - else if (token->type != CPP_DOT) + parent = get_module (name, parent, partition_p); + if (cp_lexer_peek_token (parser->lexer)->type != CPP_DOT) break; cp_lexer_consume_token (parser->lexer); - } + } return parent; } +/* Parse a module-partition. Defers to cp_parser_module_name. */ + +static module_state * +cp_parser_module_partition (cp_parser *parser, module_state *parent = NULL) +{ + return cp_parser_module_name (parser, /*partition_p=*/true, parent); +} + /* Named module-declaration __module ; PRAGMA_EOL - __module private ; PRAGMA_EOL (unimplemented) - [__export] __module module-name attr-spec-seq-opt ; PRAGMA_EOL + __module : private ; PRAGMA_EOL (unimplemented) + [__export] __module module-name module-partition [opt] + attr-spec-seq-opt ; PRAGMA_EOL */ static module_parse @@ -15003,9 +15009,12 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, else { module_state *mod = cp_parser_module_name (parser); + if (mod && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON) + mod = cp_parser_module_partition (parser, mod); tree attrs = cp_parser_attributes_opt (parser); - mp_state = MP_PURVIEW_IMPORTS; + if (mod) + mp_state = MP_PURVIEW_IMPORTS; if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) goto skip_eol; @@ -15017,7 +15026,10 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state, } /* Import-declaration - [__export] __import module-name attr-spec-seq-opt ; PRAGMA_EOL */ + __import module-name attr-spec-seq-opt ; PRAGMA_EOL + __import module-partition attr-spec-seq-opt ; PRAGMA_EOL + __import header-name attr-spec-seq-opt ; PRAGMA_EOL +*/ static void cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, @@ -15045,7 +15057,27 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state, } else { - module_state *mod = cp_parser_module_name (parser); + module_state *mod = NULL; + cp_token *next = cp_lexer_peek_token (parser->lexer); + if (next->type == CPP_HEADER_NAME) + { + cp_lexer_consume_token (parser->lexer); + mod = get_module (next->u.value); + } + else if (next->type == CPP_COLON) + { + /* An import specifying a module-partition shall only appear after the + module-declaration in a module unit: [module.import]/4. */ + if (named_module_p () + && (mp_state == MP_PURVIEW_IMPORTS + || mp_state == MP_PRIVATE_IMPORTS)) + mod = cp_parser_module_partition (parser); + else + error_at (next->location, "import specifying a module-partition" + " must appear after a named module-declaration"); + } + else + mod = cp_parser_module_name (parser); tree attrs = cp_parser_attributes_opt (parser); if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON)) |