]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Incorrect type equivalence [PR 99496]
authorNathan Sidwell <nathan@acm.org>
Mon, 15 Mar 2021 18:25:46 +0000 (11:25 -0700)
committerNathan Sidwell <nathan@acm.org>
Tue, 16 Mar 2021 11:37:33 +0000 (04:37 -0700)
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.

gcc/cp/module.cc
gcc/testsuite/g++.dg/modules/pr99496_a.H [new file with mode: 0644]
gcc/testsuite/g++.dg/modules/pr99496_b.C [new file with mode: 0644]

index 19bdfc7cb218c095eec3d53e0ed65eb0348da39a..6dbdc926cb4e434844f20eebf266f9c3cb691782 100644 (file)
@@ -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 a/gcc/testsuite/g++.dg/modules/pr99496_a.H b/gcc/testsuite/g++.dg/modules/pr99496_a.H
new file mode 100644 (file)
index 0000000..71b77fb
--- /dev/null
@@ -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 a/gcc/testsuite/g++.dg/modules/pr99496_b.C b/gcc/testsuite/g++.dg/modules/pr99496_b.C
new file mode 100644 (file)
index 0000000..57b71d1
--- /dev/null
@@ -0,0 +1,3 @@
+// { dg-additional-options {-fmodules-ts -fno-module-lazy} }
+
+import "pr99496_a.H";