public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++/modules: Restrict partitions when parsing import declarations [PR110808]
@ 2023-11-14  6:24 Nathaniel Shead
  2023-11-23 17:11 ` Nathan Sidwell
  0 siblings, 1 reply; 6+ messages in thread
From: Nathaniel Shead @ 2023-11-14  6:24 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Nathan Sidwell

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?

Bootstrapped and regtested on x86_64-pc-linux-gnu. I don't have write
access.

-- >8 --

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.

	PR c++/110808

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_module_name): Add param import_p.
	Disallow partitions after module-name for import decls.
	(cp_parser_module_declaration): Pass import_p = false.
	(cp_parser_import_declaration): Pass import_p = true.

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/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>
---
 gcc/cp/parser.cc                            | 11 ++++++-----
 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 +-
 6 files changed, 28 insertions(+), 7 deletions(-)
 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 5116bcb78f6..72a5c52313d 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -14858,10 +14858,11 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p,
    module-name . identifier
    header-name
 
-   Returns a pointer to module object, NULL.   */
+   Returns a pointer to module object, or NULL.  Also parses an optional
+   module-partition after the module-name unless IMPORT_P is true.  */
 
 static module_state *
-cp_parser_module_name (cp_parser *parser)
+cp_parser_module_name (cp_parser *parser, bool import_p)
 {
   cp_token *token = cp_lexer_peek_token (parser->lexer);
   if (token->type == CPP_HEADER_NAME)
@@ -14890,7 +14891,7 @@ cp_parser_module_name (cp_parser *parser)
       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)
+      if (!partitioned && !import_p && token->type == CPP_COLON)
 	partitioned = true;
       else if (token->type != CPP_DOT)
 	break;
@@ -14961,7 +14962,7 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state,
     }
   else
     {
-      module_state *mod = cp_parser_module_name (parser);
+      module_state *mod = cp_parser_module_name (parser, /*import_p=*/false);
       tree attrs = cp_parser_attributes_opt (parser);
 
       mp_state = MP_PURVIEW_IMPORTS;
@@ -15004,7 +15005,7 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state,
     }
   else
     {
-      module_state *mod = cp_parser_module_name (parser);
+      module_state *mod = cp_parser_module_name (parser, /*import_p=*/true);
       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/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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] c++/modules: Restrict partitions when parsing import declarations [PR110808]
  2023-11-14  6:24 [PATCH] c++/modules: Restrict partitions when parsing import declarations [PR110808] Nathaniel Shead
@ 2023-11-23 17:11 ` Nathan Sidwell
  2023-11-24 11:32   ` [PATCH v2] c++: Follow module grammar more closely [PR110808] Nathaniel Shead
  0 siblings, 1 reply; 6+ messages in thread
From: Nathan Sidwell @ 2023-11-23 17:11 UTC (permalink / raw)
  To: Nathaniel Shead, gcc-patches; +Cc: Jason Merrill

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.

> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu. I don't have write
> access.
> 
> -- >8 --
> 
> 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.

ok, I messed that one right up :)
> 
> 	PR c++/110808
> 
> gcc/cp/ChangeLog:
> 
> 	* parser.cc (cp_parser_module_name): Add param import_p.
> 	Disallow partitions after module-name for import decls.
> 	(cp_parser_module_declaration): Pass import_p = false.
> 	(cp_parser_import_declaration): Pass import_p = true.
> 
> 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/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>
> ---
>   gcc/cp/parser.cc                            | 11 ++++++-----
>   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 +-
>   6 files changed, 28 insertions(+), 7 deletions(-)
>   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 5116bcb78f6..72a5c52313d 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -14858,10 +14858,11 @@ cp_parser_already_scoped_statement (cp_parser* parser, bool *if_p,
>      module-name . identifier
>      header-name
>   
> -   Returns a pointer to module object, NULL.   */
> +   Returns a pointer to module object, or NULL.  Also parses an optional
> +   module-partition after the module-name unless IMPORT_P is true.  */
>   
>   static module_state *
> -cp_parser_module_name (cp_parser *parser)
> +cp_parser_module_name (cp_parser *parser, bool import_p)
>   {
>     cp_token *token = cp_lexer_peek_token (parser->lexer);
>     if (token->type == CPP_HEADER_NAME)
> @@ -14890,7 +14891,7 @@ cp_parser_module_name (cp_parser *parser)
>         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)
> +      if (!partitioned && !import_p && token->type == CPP_COLON)
>   	partitioned = true;
>         else if (token->type != CPP_DOT)
>   	break;
> @@ -14961,7 +14962,7 @@ cp_parser_module_declaration (cp_parser *parser, module_parse mp_state,
>       }
>     else
>       {
> -      module_state *mod = cp_parser_module_name (parser);
> +      module_state *mod = cp_parser_module_name (parser, /*import_p=*/false);
>         tree attrs = cp_parser_attributes_opt (parser);
>   
>         mp_state = MP_PURVIEW_IMPORTS;
> @@ -15004,7 +15005,7 @@ cp_parser_import_declaration (cp_parser *parser, module_parse mp_state,
>       }
>     else
>       {
> -      module_state *mod = cp_parser_module_name (parser);
> +      module_state *mod = cp_parser_module_name (parser, /*import_p=*/true);
>         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/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;

-- 
Nathan Sidwell


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2] c++: Follow module grammar more closely [PR110808]
  2023-11-23 17:11 ` Nathan Sidwell
@ 2023-11-24 11:32   ` Nathaniel Shead
  2023-12-16 11:03     ` Nathaniel Shead
  2024-01-02 22:50     ` Nathaniel Shead
  0 siblings, 2 replies; 6+ messages in thread
From: Nathaniel Shead @ 2023-11-24 11:32 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches, Jason Merrill

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 <nathanieloshead@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


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2] c++: Follow module grammar more closely [PR110808]
  2023-11-24 11:32   ` [PATCH v2] c++: Follow module grammar more closely [PR110808] Nathaniel Shead
@ 2023-12-16 11:03     ` Nathaniel Shead
  2024-01-06 22:23       ` Nathan Sidwell
  2024-01-02 22:50     ` Nathaniel Shead
  1 sibling, 1 reply; 6+ messages in thread
From: Nathaniel Shead @ 2023-12-16 11:03 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches, Jason Merrill

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 <nathanieloshead@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
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] c++: Follow module grammar more closely [PR110808]
  2023-11-24 11:32   ` [PATCH v2] c++: Follow module grammar more closely [PR110808] Nathaniel Shead
  2023-12-16 11:03     ` Nathaniel Shead
@ 2024-01-02 22:50     ` Nathaniel Shead
  1 sibling, 0 replies; 6+ messages in thread
From: Nathaniel Shead @ 2024-01-02 22:50 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches, Jason Merrill

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 <nathanieloshead@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
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] c++: Follow module grammar more closely [PR110808]
  2023-12-16 11:03     ` Nathaniel Shead
@ 2024-01-06 22:23       ` Nathan Sidwell
  0 siblings, 0 replies; 6+ messages in thread
From: Nathan Sidwell @ 2024-01-06 22:23 UTC (permalink / raw)
  To: Nathaniel Shead; +Cc: gcc-patches, Jason Merrill

This is ok -- sorry, I thought I'd already acked this


On 12/16/23 06:03, Nathaniel Shead wrote:
> 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 <nathanieloshead@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
>>

-- 
Nathan Sidwell


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-01-06 22:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-14  6:24 [PATCH] c++/modules: Restrict partitions when parsing import declarations [PR110808] Nathaniel Shead
2023-11-23 17:11 ` Nathan Sidwell
2023-11-24 11:32   ` [PATCH v2] c++: Follow module grammar more closely [PR110808] Nathaniel Shead
2023-12-16 11:03     ` Nathaniel Shead
2024-01-06 22:23       ` Nathan Sidwell
2024-01-02 22:50     ` Nathaniel Shead

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).