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