From 71aebb36174c194231da5f9c7c23f81dbb082ca4 Mon Sep 17 00:00:00 2001
From: Nathaniel Shead <nathanieloshead@gmail.com>
Date: Thu, 8 Aug 2024 17:52:03 +1000
Subject: [PATCH] c++: Propagate TREE_ADDRESSABLE in fixup_type_variants
 [PR115062]

This has caused issues with modules when an import fills in the
definition of a type already created with a typedef.

	PR c++/115062

gcc/cp/ChangeLog:

	* class.cc (fixup_type_variants): Propagate TREE_ADDRESSABLE.
	(finish_struct_bits): Cleanup now that TREE_ADDRESSABLE is
	propagated by fixup_type_variants.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/pr115062_a.H: New test.
	* g++.dg/modules/pr115062_b.H: New test.
	* g++.dg/modules/pr115062_c.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/class.cc                           | 31 ++++++++++-------------
 gcc/testsuite/g++.dg/modules/pr115062_a.H |  6 +++++
 gcc/testsuite/g++.dg/modules/pr115062_b.H | 14 ++++++++++
 gcc/testsuite/g++.dg/modules/pr115062_c.C |  9 +++++++
 4 files changed, 43 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/pr115062_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/pr115062_b.H
 create mode 100644 gcc/testsuite/g++.dg/modules/pr115062_c.C

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 718601756ddc..fb6c33709500 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -2312,6 +2312,7 @@ fixup_type_variants (tree type)
       TYPE_PRECISION (variant) = TYPE_PRECISION (type);
       TYPE_MODE_RAW (variant) = TYPE_MODE_RAW (type);
       TYPE_EMPTY_P (variant) = TYPE_EMPTY_P (type);
+      TREE_ADDRESSABLE (variant) = TREE_ADDRESSABLE (type);
     }
 }
 
@@ -2378,8 +2379,17 @@ fixup_attribute_variants (tree t)
 static void
 finish_struct_bits (tree t)
 {
-  /* Fix up variants (if any).  */
-  fixup_type_variants (t);
+  /* If this type has a copy constructor or a destructor, force its
+     mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
+     nonzero.  This will cause it to be passed by invisible reference
+     and prevent it from being returned in a register.  */
+  if (type_has_nontrivial_copy_init (t)
+      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+    {
+      SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
+      SET_TYPE_MODE (t, BLKmode);
+      TREE_ADDRESSABLE (t) = 1;
+    }
 
   if (BINFO_N_BASE_BINFOS (TYPE_BINFO (t)) && TYPE_POLYMORPHIC_P (t))
     /* For a class w/o baseclasses, 'finish_struct' has set
@@ -2392,21 +2402,8 @@ finish_struct_bits (tree t)
        looking in the vtables).  */
     get_pure_virtuals (t);
 
-  /* If this type has a copy constructor or a destructor, force its
-     mode to be BLKmode, and force its TREE_ADDRESSABLE bit to be
-     nonzero.  This will cause it to be passed by invisible reference
-     and prevent it from being returned in a register.  */
-  if (type_has_nontrivial_copy_init (t)
-      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
-    {
-      tree variants;
-      SET_DECL_MODE (TYPE_MAIN_DECL (t), BLKmode);
-      for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
-	{
-	  SET_TYPE_MODE (variants, BLKmode);
-	  TREE_ADDRESSABLE (variants) = 1;
-	}
-    }
+  /* Fix up variants (if any).  */
+  fixup_type_variants (t);
 }
 
 /* Issue warnings about T having private constructors, but no friends,
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_a.H b/gcc/testsuite/g++.dg/modules/pr115062_a.H
new file mode 100644
index 000000000000..3c9daac317e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_a.H
@@ -0,0 +1,6 @@
+// PR c++/115062
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template <typename T> class S;
+typedef S<char> X;
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_b.H b/gcc/testsuite/g++.dg/modules/pr115062_b.H
new file mode 100644
index 000000000000..d8da59591ec5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_b.H
@@ -0,0 +1,14 @@
+// PR c++/115062
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+
+template <typename>
+struct S {
+  int a;
+  long b;
+  union {};
+  ~S();
+  void foo();
+};
+extern template void S<char>::foo();
+S<char> operator+(S<char>, const char *);
diff --git a/gcc/testsuite/g++.dg/modules/pr115062_c.C b/gcc/testsuite/g++.dg/modules/pr115062_c.C
new file mode 100644
index 000000000000..5255b9ffca7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr115062_c.C
@@ -0,0 +1,9 @@
+// PR c++/115062
+// { dg-additional-options "-fmodules-ts" }
+
+import "pr115062_a.H";
+import "pr115062_b.H";
+
+int main() {
+  X x = X() + "";
+}
-- 
GitLab