public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++/modules: Prevent emission of really-extern vtables in importers [PR114229]
@ 2024-03-06  3:06 Nathaniel Shead
  2024-03-06 13:59 ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Nathaniel Shead @ 2024-03-06  3:06 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill, Nathan Sidwell, Patrick Palka

Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >8 --

Currently, reading a variable definition always marks that decl as
DECL_NOT_REALLY_EXTERN, with anything else imported still being
considered external. This is not sufficient for vtables, however; for an
extern template, a vtable may be generated (and its definition emitted)
but nonetheless the vtable should only be emitted in the TU where that
template is actually instantiated.

While playing around with various settings of DECL_EXTERNAL I also
noticed that we mark variables not declared 'inline' as external, which
makes sense (there's a definition in another TU, while for vague linkage
variables we'll be importing the definition too), but we also do so for
'static constexpr' members that aren't directly marked 'inline'. This
fixes that for consistency, if nothing else (I wasn't able to cause an
actual issue exploiting this currently), but may become relevant with
https://github.com/itanium-cxx-abi/cxx-abi/issues/170.

	PR c++/114229

gcc/cp/ChangeLog:

	* module.cc (trees_out::core_bools): Count 'static constexpr'
	vars also as inline.
	(trees_out::write_var_def): Stream DECL_NOT_REALLY_EXTERN for
	vtables.
	(trees_in::read_var_def): Read it.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/virt-2_c.C:
	* g++.dg/modules/virt-3_a.C: New test.
	* g++.dg/modules/virt-3_b.C: New test.
	* g++.dg/modules/virt-3_c.C: New test.
	* g++.dg/modules/virt-3_d.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                        | 15 +++++++++++++--
 gcc/testsuite/g++.dg/modules/virt-2_c.C | 14 +++++++++-----
 gcc/testsuite/g++.dg/modules/virt-3_a.C |  9 +++++++++
 gcc/testsuite/g++.dg/modules/virt-3_b.C |  6 ++++++
 gcc/testsuite/g++.dg/modules/virt-3_c.C |  3 +++
 gcc/testsuite/g++.dg/modules/virt-3_d.C |  7 +++++++
 6 files changed, 47 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_c.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_d.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 67f132d28d7..771e56245dc 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5418,7 +5418,7 @@ trees_out::core_bools (tree t)
 		  && !(TREE_STATIC (t)
 		       && DECL_FUNCTION_SCOPE_P (t)
 		       && DECL_DECLARED_INLINE_P (DECL_CONTEXT (t)))
-		  && !DECL_VAR_DECLARED_INLINE_P (t))
+		  && !DECL_INLINE_VAR_P (t))
 		is_external = true;
 	      break;
 
@@ -11799,6 +11799,12 @@ trees_out::write_var_def (tree decl)
 	}
       tree_node (dyn_init);
     }
+
+  /* For vtables we need to know if they're actually extern or not,
+     even if we get a definition; for other kinds of variables we
+     can assume that if we have a definition they can be emitted.  */
+  if (streaming_p () && VAR_P (decl) && DECL_VTABLE_OR_VTT_P (decl))
+    u (DECL_NOT_REALLY_EXTERN (decl));
 }
 
 void
@@ -11816,6 +11822,11 @@ trees_in::read_var_def (tree decl, tree maybe_template)
   tree dyn_init = init ? NULL_TREE : tree_node ();
   unused -= vtable;
 
+  /* Assume for most vars that if we have a definition it's not extern.  */
+  bool not_really_extern = true;
+  if (vtable)
+    not_really_extern = u ();
+
   if (get_overrun ())
     return false;
 
@@ -11826,7 +11837,7 @@ trees_in::read_var_def (tree decl, tree maybe_template)
   if (installing)
     {
       if (DECL_EXTERNAL (decl))
-	DECL_NOT_REALLY_EXTERN (decl) = true;
+	DECL_NOT_REALLY_EXTERN (decl) = not_really_extern;
       if (VAR_P (decl))
 	{
 	  DECL_INITIALIZED_P (decl) = true;
diff --git a/gcc/testsuite/g++.dg/modules/virt-2_c.C b/gcc/testsuite/g++.dg/modules/virt-2_c.C
index 7b3eeebe508..8969cb04911 100644
--- a/gcc/testsuite/g++.dg/modules/virt-2_c.C
+++ b/gcc/testsuite/g++.dg/modules/virt-2_c.C
@@ -9,8 +9,12 @@ int Foo ()
   return !(Visit (&v) == 0);
 }
 
-// We do emit Visitor vtable
-// andl also we do emit rtti here
-// { dg-final { scan-assembler {_ZTVW3foo7Visitor:} } }
-// { dg-final { scan-assembler {_ZTIW3foo7Visitor:} } }
-// { dg-final { scan-assembler {_ZTSW3foo7Visitor:} } }
+// Again, we do not emit Visitor vtable
+// but we do emit rtti here
+
+// but see https://github.com/itanium-cxx-abi/cxx-abi/issues/170:
+// we should only emit RTTI in virt-2_a.C, alongside the vtable
+
+// { dg-final { scan-assembler-not {_ZTVW3foo7Visitor:} } }
+// { dg-final { scan-assembler-not {_ZTIW3foo7Visitor:} { xfail *-*-* } } }
+// { dg-final { scan-assembler-not {_ZTSW3foo7Visitor:} { xfail *-*-* } } }
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_a.C b/gcc/testsuite/g++.dg/modules/virt-3_a.C
new file mode 100644
index 00000000000..a7eae7f9d35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_a.C
@@ -0,0 +1,9 @@
+// PR c++/114229
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi modA }
+
+module;
+template<class> struct basic_streambuf { virtual void overflow() { } };
+extern template struct basic_streambuf<long>;
+export module modA;
+export basic_streambuf<long> *p;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_b.C b/gcc/testsuite/g++.dg/modules/virt-3_b.C
new file mode 100644
index 00000000000..4d87b965bbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_b.C
@@ -0,0 +1,6 @@
+// PR c++/114229
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+// { dg-module-cmi modB }
+
+export module modB;
+import modA;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_c.C b/gcc/testsuite/g++.dg/modules/virt-3_c.C
new file mode 100644
index 00000000000..224bb4aed49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_c.C
@@ -0,0 +1,3 @@
+// PR c++/114229
+template<class> struct basic_streambuf { virtual void overflow() { } };
+template struct basic_streambuf<long>;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_d.C b/gcc/testsuite/g++.dg/modules/virt-3_d.C
new file mode 100644
index 00000000000..b3a0aad7abe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_d.C
@@ -0,0 +1,7 @@
+// PR c++/114229
+// { dg-module-do link }
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import modA;
+import modB;
+int main() { }
-- 
2.43.2


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

* Re: [PATCH] c++/modules: Prevent emission of really-extern vtables in importers [PR114229]
  2024-03-06  3:06 [PATCH] c++/modules: Prevent emission of really-extern vtables in importers [PR114229] Nathaniel Shead
@ 2024-03-06 13:59 ` Jason Merrill
  2024-03-07 12:49   ` [PATCH v2] c++: Redetermine whether to write vtables on stream-in [PR114229] Nathaniel Shead
  0 siblings, 1 reply; 4+ messages in thread
From: Jason Merrill @ 2024-03-06 13:59 UTC (permalink / raw)
  To: Nathaniel Shead, gcc-patches; +Cc: Nathan Sidwell, Patrick Palka

On 3/5/24 22:06, Nathaniel Shead wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> 
> -- >8 --
> 
> Currently, reading a variable definition always marks that decl as
> DECL_NOT_REALLY_EXTERN, with anything else imported still being
> considered external. This is not sufficient for vtables, however; for an
> extern template, a vtable may be generated (and its definition emitted)
> but nonetheless the vtable should only be emitted in the TU where that
> template is actually instantiated.

Does the vtable go through import_export_decl?  I've been thinking that 
that function (and import_export_class) need to be more module-aware. 
Would it make sense to do that rather than stream DECL_NOT_REALLY_EXTERN?

Jason


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

* [PATCH v2] c++: Redetermine whether to write vtables on stream-in [PR114229]
  2024-03-06 13:59 ` Jason Merrill
@ 2024-03-07 12:49   ` Nathaniel Shead
  2024-03-07 20:24     ` Jason Merrill
  0 siblings, 1 reply; 4+ messages in thread
From: Nathaniel Shead @ 2024-03-07 12:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, Nathan Sidwell, Patrick Palka

On Wed, Mar 06, 2024 at 08:59:16AM -0500, Jason Merrill wrote:
> On 3/5/24 22:06, Nathaniel Shead wrote:
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > 
> > -- >8 --
> > 
> > Currently, reading a variable definition always marks that decl as
> > DECL_NOT_REALLY_EXTERN, with anything else imported still being
> > considered external. This is not sufficient for vtables, however; for an
> > extern template, a vtable may be generated (and its definition emitted)
> > but nonetheless the vtable should only be emitted in the TU where that
> > template is actually instantiated.
> 
> Does the vtable go through import_export_decl?  I've been thinking that that
> function (and import_export_class) need to be more module-aware. Would it
> make sense to do that rather than stream DECL_NOT_REALLY_EXTERN?
> 
> Jason
> 

Right. It doesn't go through 'import_export_decl' because when it's
imported, DECL_INTERFACE_KNOWN is already set. So it seems an obvious
fix here is to just ensure that we clear that flag on stream-in for
vtables (we can't do it generally as it seems to be needed to be kept on
various other kinds of declarations).

Linaro complained about the last version of this patch too on ARM;
hopefully this version is friendlier.

I might also spend some time messing around to see if I can implement
https://github.com/itanium-cxx-abi/cxx-abi/issues/170 later, but that
will probably have to be a GCC 15 change.

Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk if
Linaro doesn't complain about this patch?

-- >8 --

We currently always stream DECL_INTERFACE_KNOWN, which is needed since
many kinds of declarations already have their interface determined at
parse time.  But for vtables and type-info declarations we need to
re-evaluate on stream-in, as whether they need to be emitted or not
changes in each TU, so this patch clears DECL_INTERFACE_KNOWN on these
kinds of declarations so that they can go through 'import_export_decl'
again.

Note that the precise details of the virt-2 tests will need to change
when we implement the resolution of [1]; for now I just updated the test
to not fail with the new (current) semantics.

[1]: https://github.com/itanium-cxx-abi/cxx-abi/pull/171

	PR c++/114229

gcc/cp/ChangeLog:

	* module.cc (trees_out::core_bools): Redetermine
	DECL_INTERFACE_KNOWN on stream-in for vtables and tinfo.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/virt-2_b.C: Update test to acknowledge that we
	now emit vtables here too.
	* g++.dg/modules/virt-3_a.C: New test.
	* g++.dg/modules/virt-3_b.C: New test.
	* g++.dg/modules/virt-3_c.C: New test.
	* g++.dg/modules/virt-3_d.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/module.cc                        | 12 +++++++++++-
 gcc/testsuite/g++.dg/modules/virt-2_b.C |  5 ++---
 gcc/testsuite/g++.dg/modules/virt-3_a.C |  9 +++++++++
 gcc/testsuite/g++.dg/modules/virt-3_b.C |  6 ++++++
 gcc/testsuite/g++.dg/modules/virt-3_c.C |  3 +++
 gcc/testsuite/g++.dg/modules/virt-3_d.C |  7 +++++++
 6 files changed, 38 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_b.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_c.C
 create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_d.C

diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index f7e8b357fc2..d77286328f5 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5390,7 +5390,17 @@ trees_out::core_bools (tree t)
       WB (t->decl_common.lang_flag_2);
       WB (t->decl_common.lang_flag_3);
       WB (t->decl_common.lang_flag_4);
-      WB (t->decl_common.lang_flag_5);
+
+      {
+	/* This is DECL_INTERFACE_KNOWN: We should redetermine whether
+	   we need to import or export any vtables or typeinfo objects
+	   on stream-in.  */
+	bool interface_known = t->decl_common.lang_flag_5;
+	if (VAR_P (t) && (DECL_VTABLE_OR_VTT_P (t) || DECL_TINFO_P (t)))
+	  interface_known = false;
+	WB (interface_known);
+      }
+
       WB (t->decl_common.lang_flag_6);
       WB (t->decl_common.lang_flag_7);
       WB (t->decl_common.lang_flag_8);
diff --git a/gcc/testsuite/g++.dg/modules/virt-2_b.C b/gcc/testsuite/g++.dg/modules/virt-2_b.C
index e041f0721f9..2bc5eced013 100644
--- a/gcc/testsuite/g++.dg/modules/virt-2_b.C
+++ b/gcc/testsuite/g++.dg/modules/virt-2_b.C
@@ -21,8 +21,7 @@ int main ()
   return !(Visit (&me) == 1);
 }
 
-// We do not emit Visitor vtable
-// but we do emit rtti here
-// { dg-final { scan-assembler-not {_ZTVW3foo7Visitor:} } }
+// Again, we emit Visitor vtable and rtti here
+// { dg-final { scan-assembler {_ZTVW3foo7Visitor:} } }
 // { dg-final { scan-assembler {_ZTIW3foo7Visitor:} } }
 // { dg-final { scan-assembler {_ZTSW3foo7Visitor:} } }
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_a.C b/gcc/testsuite/g++.dg/modules/virt-3_a.C
new file mode 100644
index 00000000000..a7eae7f9d35
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_a.C
@@ -0,0 +1,9 @@
+// PR c++/114229
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi modA }
+
+module;
+template<class> struct basic_streambuf { virtual void overflow() { } };
+extern template struct basic_streambuf<long>;
+export module modA;
+export basic_streambuf<long> *p;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_b.C b/gcc/testsuite/g++.dg/modules/virt-3_b.C
new file mode 100644
index 00000000000..4d87b965bbf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_b.C
@@ -0,0 +1,6 @@
+// PR c++/114229
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+// { dg-module-cmi modB }
+
+export module modB;
+import modA;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_c.C b/gcc/testsuite/g++.dg/modules/virt-3_c.C
new file mode 100644
index 00000000000..224bb4aed49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_c.C
@@ -0,0 +1,3 @@
+// PR c++/114229
+template<class> struct basic_streambuf { virtual void overflow() { } };
+template struct basic_streambuf<long>;
diff --git a/gcc/testsuite/g++.dg/modules/virt-3_d.C b/gcc/testsuite/g++.dg/modules/virt-3_d.C
new file mode 100644
index 00000000000..b3a0aad7abe
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/virt-3_d.C
@@ -0,0 +1,7 @@
+// PR c++/114229
+// { dg-module-do link }
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import modA;
+import modB;
+int main() { }
-- 
2.43.2


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

* Re: [PATCH v2] c++: Redetermine whether to write vtables on stream-in [PR114229]
  2024-03-07 12:49   ` [PATCH v2] c++: Redetermine whether to write vtables on stream-in [PR114229] Nathaniel Shead
@ 2024-03-07 20:24     ` Jason Merrill
  0 siblings, 0 replies; 4+ messages in thread
From: Jason Merrill @ 2024-03-07 20:24 UTC (permalink / raw)
  To: Nathaniel Shead; +Cc: gcc-patches, Nathan Sidwell, Patrick Palka

On 3/7/24 07:49, Nathaniel Shead wrote:
> On Wed, Mar 06, 2024 at 08:59:16AM -0500, Jason Merrill wrote:
>> On 3/5/24 22:06, Nathaniel Shead wrote:
>>> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
>>>
>>> -- >8 --
>>>
>>> Currently, reading a variable definition always marks that decl as
>>> DECL_NOT_REALLY_EXTERN, with anything else imported still being
>>> considered external. This is not sufficient for vtables, however; for an
>>> extern template, a vtable may be generated (and its definition emitted)
>>> but nonetheless the vtable should only be emitted in the TU where that
>>> template is actually instantiated.
>>
>> Does the vtable go through import_export_decl?  I've been thinking that that
>> function (and import_export_class) need to be more module-aware. Would it
>> make sense to do that rather than stream DECL_NOT_REALLY_EXTERN?
>>
>> Jason
>>
> 
> Right. It doesn't go through 'import_export_decl' because when it's
> imported, DECL_INTERFACE_KNOWN is already set. So it seems an obvious
> fix here is to just ensure that we clear that flag on stream-in for
> vtables (we can't do it generally as it seems to be needed to be kept on
> various other kinds of declarations).
> 
> Linaro complained about the last version of this patch too on ARM;
> hopefully this version is friendlier.
> 
> I might also spend some time messing around to see if I can implement
> https://github.com/itanium-cxx-abi/cxx-abi/issues/170 later, but that
> will probably have to be a GCC 15 change.

That's OK, but please add a FIXME in this change until then.

OK with that adjustment.

> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk if
> Linaro doesn't complain about this patch?
> 
> -- >8 --
> 
> We currently always stream DECL_INTERFACE_KNOWN, which is needed since
> many kinds of declarations already have their interface determined at
> parse time.  But for vtables and type-info declarations we need to
> re-evaluate on stream-in, as whether they need to be emitted or not
> changes in each TU, so this patch clears DECL_INTERFACE_KNOWN on these
> kinds of declarations so that they can go through 'import_export_decl'
> again.
> 
> Note that the precise details of the virt-2 tests will need to change
> when we implement the resolution of [1]; for now I just updated the test
> to not fail with the new (current) semantics.
> 
> [1]: https://github.com/itanium-cxx-abi/cxx-abi/pull/171
> 
> 	PR c++/114229
> 
> gcc/cp/ChangeLog:
> 
> 	* module.cc (trees_out::core_bools): Redetermine
> 	DECL_INTERFACE_KNOWN on stream-in for vtables and tinfo.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/virt-2_b.C: Update test to acknowledge that we
> 	now emit vtables here too.
> 	* g++.dg/modules/virt-3_a.C: New test.
> 	* g++.dg/modules/virt-3_b.C: New test.
> 	* g++.dg/modules/virt-3_c.C: New test.
> 	* g++.dg/modules/virt-3_d.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/module.cc                        | 12 +++++++++++-
>   gcc/testsuite/g++.dg/modules/virt-2_b.C |  5 ++---
>   gcc/testsuite/g++.dg/modules/virt-3_a.C |  9 +++++++++
>   gcc/testsuite/g++.dg/modules/virt-3_b.C |  6 ++++++
>   gcc/testsuite/g++.dg/modules/virt-3_c.C |  3 +++
>   gcc/testsuite/g++.dg/modules/virt-3_d.C |  7 +++++++
>   6 files changed, 38 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_a.C
>   create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_b.C
>   create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_c.C
>   create mode 100644 gcc/testsuite/g++.dg/modules/virt-3_d.C
> 
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index f7e8b357fc2..d77286328f5 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -5390,7 +5390,17 @@ trees_out::core_bools (tree t)
>         WB (t->decl_common.lang_flag_2);
>         WB (t->decl_common.lang_flag_3);
>         WB (t->decl_common.lang_flag_4);
> -      WB (t->decl_common.lang_flag_5);
> +
> +      {
> +	/* This is DECL_INTERFACE_KNOWN: We should redetermine whether
> +	   we need to import or export any vtables or typeinfo objects
> +	   on stream-in.  */
> +	bool interface_known = t->decl_common.lang_flag_5;
> +	if (VAR_P (t) && (DECL_VTABLE_OR_VTT_P (t) || DECL_TINFO_P (t)))
> +	  interface_known = false;
> +	WB (interface_known);
> +      }
> +
>         WB (t->decl_common.lang_flag_6);
>         WB (t->decl_common.lang_flag_7);
>         WB (t->decl_common.lang_flag_8);
> diff --git a/gcc/testsuite/g++.dg/modules/virt-2_b.C b/gcc/testsuite/g++.dg/modules/virt-2_b.C
> index e041f0721f9..2bc5eced013 100644
> --- a/gcc/testsuite/g++.dg/modules/virt-2_b.C
> +++ b/gcc/testsuite/g++.dg/modules/virt-2_b.C
> @@ -21,8 +21,7 @@ int main ()
>     return !(Visit (&me) == 1);
>   }
>   
> -// We do not emit Visitor vtable
> -// but we do emit rtti here
> -// { dg-final { scan-assembler-not {_ZTVW3foo7Visitor:} } }
> +// Again, we emit Visitor vtable and rtti here
> +// { dg-final { scan-assembler {_ZTVW3foo7Visitor:} } }
>   // { dg-final { scan-assembler {_ZTIW3foo7Visitor:} } }
>   // { dg-final { scan-assembler {_ZTSW3foo7Visitor:} } }
> diff --git a/gcc/testsuite/g++.dg/modules/virt-3_a.C b/gcc/testsuite/g++.dg/modules/virt-3_a.C
> new file mode 100644
> index 00000000000..a7eae7f9d35
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/virt-3_a.C
> @@ -0,0 +1,9 @@
> +// PR c++/114229
> +// { dg-additional-options "-fmodules-ts -Wno-global-module" }
> +// { dg-module-cmi modA }
> +
> +module;
> +template<class> struct basic_streambuf { virtual void overflow() { } };
> +extern template struct basic_streambuf<long>;
> +export module modA;
> +export basic_streambuf<long> *p;
> diff --git a/gcc/testsuite/g++.dg/modules/virt-3_b.C b/gcc/testsuite/g++.dg/modules/virt-3_b.C
> new file mode 100644
> index 00000000000..4d87b965bbf
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/virt-3_b.C
> @@ -0,0 +1,6 @@
> +// PR c++/114229
> +// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
> +// { dg-module-cmi modB }
> +
> +export module modB;
> +import modA;
> diff --git a/gcc/testsuite/g++.dg/modules/virt-3_c.C b/gcc/testsuite/g++.dg/modules/virt-3_c.C
> new file mode 100644
> index 00000000000..224bb4aed49
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/virt-3_c.C
> @@ -0,0 +1,3 @@
> +// PR c++/114229
> +template<class> struct basic_streambuf { virtual void overflow() { } };
> +template struct basic_streambuf<long>;
> diff --git a/gcc/testsuite/g++.dg/modules/virt-3_d.C b/gcc/testsuite/g++.dg/modules/virt-3_d.C
> new file mode 100644
> index 00000000000..b3a0aad7abe
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/virt-3_d.C
> @@ -0,0 +1,7 @@
> +// PR c++/114229
> +// { dg-module-do link }
> +// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
> +
> +import modA;
> +import modB;
> +int main() { }


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

end of thread, other threads:[~2024-03-07 20:24 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-06  3:06 [PATCH] c++/modules: Prevent emission of really-extern vtables in importers [PR114229] Nathaniel Shead
2024-03-06 13:59 ` Jason Merrill
2024-03-07 12:49   ` [PATCH v2] c++: Redetermine whether to write vtables on stream-in [PR114229] Nathaniel Shead
2024-03-07 20:24     ` Jason Merrill

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).