Ping for https://gcc.gnu.org/pipermail/gcc-patches/2023-November/638089.html.
On Fri, Nov 24, 2023 at 10:32:13PM +1100, Nathaniel Shead wrote: > On Thu, Nov 23, 2023 at 12:11:58PM -0500, Nathan Sidwell wrote: > > On 11/14/23 01:24, Nathaniel Shead wrote: > > > I'll also note that the comments above the parsing functions here no > > > longer exactly match with the grammar in the standard, should they be > > > updated as well? > > > > please. > > > > As I was attempting to rewrite the comments I ended up splitting up the > work that was being done by cp_parser_module_name a lot to better match > the grammar, and also caught a few other segfaults that were occurring > along the way. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk? > > -- >8 -- > > 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 <nathanielosh...@gmail.com> > --- > gcc/cp/parser.cc | 100 ++++++++++++------- > gcc/testsuite/g++.dg/modules/mod-invalid-1.C | 7 ++ > gcc/testsuite/g++.dg/modules/part-8_a.C | 6 ++ > gcc/testsuite/g++.dg/modules/part-8_b.C | 6 ++ > gcc/testsuite/g++.dg/modules/part-8_c.C | 8 ++ > gcc/testsuite/g++.dg/modules/part-hdr-1_c.C | 2 +- > gcc/testsuite/g++.dg/modules/part-mac-1_c.C | 2 +- > 7 files changed, 95 insertions(+), 36 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/modules/mod-invalid-1.C > create mode 100644 gcc/testsuite/g++.dg/modules/part-8_a.C > create mode 100644 gcc/testsuite/g++.dg/modules/part-8_b.C > create mode 100644 gcc/testsuite/g++.dg/modules/part-8_c.C > > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc > index f6d088bc73f..20bd8d45a08 100644 > --- a/gcc/cp/parser.cc > +++ b/gcc/cp/parser.cc > @@ -14853,58 +14853,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 > @@ -14962,9 +14968,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; > > @@ -14976,7 +14985,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, > @@ -15004,7 +15016,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)) > diff --git a/gcc/testsuite/g++.dg/modules/mod-invalid-1.C > b/gcc/testsuite/g++.dg/modules/mod-invalid-1.C > new file mode 100644 > index 00000000000..fadaba0b560 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/mod-invalid-1.C > @@ -0,0 +1,7 @@ > +// { dg-additional-options "-fmodules-ts" } > + > +module; > + > +module :foo; // { dg-error "expected module-name" } > + > +import :foo; // { dg-error "import specifying a module-partition must > appear after a named module-declaration" } > diff --git a/gcc/testsuite/g++.dg/modules/part-8_a.C > b/gcc/testsuite/g++.dg/modules/part-8_a.C > new file mode 100644 > index 00000000000..09f956ff36f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/part-8_a.C > @@ -0,0 +1,6 @@ > +// PR c++/110808 > +// { dg-additional-options "-fmodules-ts" } > +// { dg-module-cmi group:tres } > + > +export module group:tres; > +int mul() { return 0; } > diff --git a/gcc/testsuite/g++.dg/modules/part-8_b.C > b/gcc/testsuite/g++.dg/modules/part-8_b.C > new file mode 100644 > index 00000000000..1ade029495c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/part-8_b.C > @@ -0,0 +1,6 @@ > +// PR c++/110808 > +// { dg-additional-options "-fmodules-ts" } > +// { dg-module-cmi group } > + > +export module group; > +export import :tres; > diff --git a/gcc/testsuite/g++.dg/modules/part-8_c.C > b/gcc/testsuite/g++.dg/modules/part-8_c.C > new file mode 100644 > index 00000000000..2351f28f909 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/part-8_c.C > @@ -0,0 +1,8 @@ > +// PR c++/110808 > +// { dg-additional-options "-fmodules-ts" } > + > +import group:tres; // { dg-error "expected .;." } > + > +int main() { > + return mul(); // { dg-error "not declared" } > +} > diff --git a/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C > b/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C > index 78a53d2fda3..db57adcef44 100644 > --- a/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C > +++ b/gcc/testsuite/g++.dg/modules/part-hdr-1_c.C > @@ -2,4 +2,4 @@ > // { dg-module-cmi {mod} } > > export module mod; > -import mod:impl; > +import :impl; > diff --git a/gcc/testsuite/g++.dg/modules/part-mac-1_c.C > b/gcc/testsuite/g++.dg/modules/part-mac-1_c.C > index 78a53d2fda3..db57adcef44 100644 > --- a/gcc/testsuite/g++.dg/modules/part-mac-1_c.C > +++ b/gcc/testsuite/g++.dg/modules/part-mac-1_c.C > @@ -2,4 +2,4 @@ > // { dg-module-cmi {mod} } > > export module mod; > -import mod:impl; > +import :impl; > -- > 2.42.0 >