diff mbox series

c++: Incorrect type equivalence [PR 99496]

Message ID ec0cee1c-2f08-f9eb-0053-2b2e1eb5a35c@acm.org
State New
Headers show
Series c++: Incorrect type equivalence [PR 99496] | expand

Commit Message

Nathan Sidwell March 15, 2021, 6:29 p.m. UTC
This bug was caused by not marking dependent template aliases
correctly -- these things look like typedefs, but are not
(necessarily) equivalent to the	canonical type.	 We need to record that.

         PR c++/99496
         gcc/cp/
         * module.cc (trees_out::decl_value): Adjust typedef streaming,
         indicate whether it is a dependent alias.
         (trees_in::decl_value):	Likewise.  Set as dependent alias, if it
         is one.
         gcc/testsuite/
         * g++.dg/modules/pr99496_a.H: New.
         * g++.dg/modules/pr99496_b.C: New.
diff mbox series

Patch

diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index 19bdfc7cb21..6dbdc926cb4 100644
--- c/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -7719,18 +7719,35 @@  trees_out::decl_value (tree decl, depset *dep)
 	}
     }
 
-  bool is_typedef = (!type && inner
-		     && TREE_CODE (inner) == TYPE_DECL
-		     && DECL_ORIGINAL_TYPE (inner)
-		     && TYPE_NAME (TREE_TYPE (inner)) == inner);
-  if (is_typedef)
+  bool is_typedef = false;
+  if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
     {
-      /* A typedef type.  */
-      int type_tag = insert (TREE_TYPE (inner));
+      tree t = TREE_TYPE (inner);
+      unsigned tdef_flags = 0;
+      if (DECL_ORIGINAL_TYPE (inner)
+	  && TYPE_NAME (TREE_TYPE (inner)) == inner)
+	{
+	  tdef_flags |= 1;
+	  if (TYPE_STRUCTURAL_EQUALITY_P (t)
+	      && TYPE_DEPENDENT_P_VALID (t)
+	      && TYPE_DEPENDENT_P (t))
+	    tdef_flags |= 2;
+	}
       if (streaming_p ())
-	dump (dumper::TREE)
-	  && dump ("Cloned:%d typedef %C:%N", type_tag,
-		   TREE_CODE (TREE_TYPE (inner)), TREE_TYPE (inner));
+	u (tdef_flags);
+
+      if (tdef_flags & 1)
+	{
+	  /* A typedef type.  */
+	  int type_tag = insert (t);
+	  if (streaming_p ())
+	    dump (dumper::TREE)
+	      && dump ("Cloned:%d %s %C:%N", type_tag,
+		       tdef_flags & 2 ? "depalias" : "typedef",
+		       TREE_CODE (t), t);
+
+	  is_typedef = true;
+	}
     }
 
   if (streaming_p () && DECL_MAYBE_IN_CHARGE_CDTOR_P (decl))
@@ -7993,12 +8010,6 @@  trees_in::decl_value ()
 
   dump (dumper::TREE) && dump ("Read:%d %C:%N", tag, TREE_CODE (decl), decl);
 
-  /* Regular typedefs will have a NULL TREE_TYPE at this point.  */
-  bool is_typedef = (!type && inner
-		     && TREE_CODE (inner) == TYPE_DECL
-		     && DECL_ORIGINAL_TYPE (inner)
-		     && !TREE_TYPE (inner));
-
   existing = back_refs[~tag];
   bool installed = install_entity (existing);
   bool is_new = existing == decl;
@@ -8030,6 +8041,16 @@  trees_in::decl_value ()
 	}
     }
 
+  /* Regular typedefs will have a NULL TREE_TYPE at this point.  */
+  unsigned tdef_flags = 0;
+  bool is_typedef = false;
+  if (!type && inner && TREE_CODE (inner) == TYPE_DECL)
+    {
+      tdef_flags = u ();
+      if (tdef_flags & 1)
+	is_typedef = true;
+    }
+
   if (is_new)
     {
       /* A newly discovered node.  */
@@ -8076,6 +8097,14 @@  trees_in::decl_value ()
 	  TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner);
 	  DECL_ORIGINAL_TYPE (inner) = NULL_TREE;
 	  set_underlying_type (inner);
+	  if (tdef_flags & 2)
+	    {
+	      /* Match instantiate_alias_template's handling.  */
+	      tree type = TREE_TYPE (inner);
+	      TYPE_DEPENDENT_P (type) = true;
+	      TYPE_DEPENDENT_P_VALID (type) = true;
+	      SET_TYPE_STRUCTURAL_EQUALITY (type);
+	    }
 	}
 
       if (inner_tag)
@@ -10661,6 +10690,9 @@  trees_in::key_mergeable (int tag, merge_kind mk, tree decl, tree inner,
       spec.tmpl = tree_node ();
       spec.args = tree_node ();
 
+      if (get_overrun ())
+	return error_mark_node;
+
       DECL_NAME (decl) = DECL_NAME (spec.tmpl);
       DECL_CONTEXT (decl) = DECL_CONTEXT (spec.tmpl);
       DECL_NAME (inner) = DECL_NAME (decl);
diff --git c/gcc/testsuite/g++.dg/modules/pr99496_a.H w/gcc/testsuite/g++.dg/modules/pr99496_a.H
new file mode 100644
index 00000000000..71b77fbb49c
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99496_a.H
@@ -0,0 +1,17 @@ 
+// PR 99496 different types with same canonical
+// (requires spec hasher to be a constant, so we get collisions)
+// { dg-additional-options -fmodule-header }
+// { dg-module-cmi {} }
+
+template<typename...> using __void_t = void;
+
+template<typename _Tp, typename = void>
+struct __is_referenceable
+{ };
+
+template<typename _Tp>
+struct __is_referenceable<_Tp, __void_t<_Tp&>>
+{ };
+
+template<typename _Tp, bool = __is_referenceable<_Tp>::value>
+struct __is_copy_constructible_impl;
diff --git c/gcc/testsuite/g++.dg/modules/pr99496_b.C w/gcc/testsuite/g++.dg/modules/pr99496_b.C
new file mode 100644
index 00000000000..57b71d13f54
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr99496_b.C
@@ -0,0 +1,3 @@ 
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+
+import "pr99496_a.H";