diff mbox series

c++: header unit template alias merging [PR 98770]

Message ID 7e0e26b4-aac6-9928-ef02-0802c743a53b@acm.org
State New
Headers show
Series c++: header unit template alias merging [PR 98770] | expand

Commit Message

Nathan Sidwell Jan. 28, 2021, 12:54 p.m. UTC
Typedefs are streamed by streaming the underlying type, and then
recreating the typedef.  But this breaks checking a duplicate is the
same as the original when it is a template alias -- we end up checking
a template alias (eg __void_t) against the underlying type (void).
And those are not the same template alias.  This stops pretendig that
the underlying type is the typedef for that checking and tells
is_matching_decl 'you have a typedef', so it knows what to do.  (We do
not want to recreate the typedef of the duplicate, because that whole
set of nodes is going to go away.)

         PR c++/98770
         gcc/cp/
         gcc/testsuite/
         * g++.dg/modules/pr98770_a.C: New.
         * g++.dg/modules/pr98770_b.C: New.

Comments

Nathan Sidwell Jan. 28, 2021, 12:58 p.m. UTC | #1
On 1/28/21 7:54 AM, Nathan Sidwell wrote:
> 
> Typedefs are streamed by streaming the underlying type, and then
> recreating the typedef.  But this breaks checking a duplicate is the
> same as the original when it is a template alias -- we end up checking
> a template alias (eg __void_t) against the underlying type (void).
> And those are not the same template alias.  This stops pretendig that
> the underlying type is the typedef for that checking and tells
> is_matching_decl 'you have a typedef', so it knows what to do.  (We do
> not want to recreate the typedef of the duplicate, because that whole
> set of nodes is going to go away.)

d'oh!
         PR c++/98770
         gcc/cp/
         * module.cc (trees_out::decl_value): Swap is_typedef & TYPE_NAME
         check order.
         (trees_in::decl_value): Do typedef frobbing only when installing
         a new typedef, adjust is_matching_decl call.  Swap is_typedef
         & TYPE_NAME check.
         (trees_in::is_matching_decl): Add is_typedef parm. Adjust variable
         names and deal with typedef checking.
         gcc/testsuite/
         * g++.dg/modules/pr98770_a.C: New.
         * g++.dg/modules/pr98770_b.C: New.
diff mbox series

Patch

diff --git c/gcc/cp/module.cc w/gcc/cp/module.cc
index 18f5de8724b..daf75b16007 100644
--- c/gcc/cp/module.cc
+++ w/gcc/cp/module.cc
@@ -3029,7 +3029,7 @@  public:
   bool read_definition (tree decl);
   
 private:
-  bool is_matching_decl (tree existing, tree decl);
+  bool is_matching_decl (tree existing, tree decl, bool is_typedef);
   static bool install_implicit_member (tree decl);
   bool read_function_def (tree decl, tree maybe_template);
   bool read_var_def (tree decl, tree maybe_template);
@@ -7864,8 +7864,8 @@  trees_out::decl_value (tree decl, depset *dep)
 			 || !dep == (VAR_OR_FUNCTION_DECL_P (inner)
 				     && DECL_LOCAL_DECL_P (inner)));
   else if ((TREE_CODE (inner) == TYPE_DECL
-	    && TYPE_NAME (TREE_TYPE (inner)) == inner
-	    && !is_typedef)
+	    && !is_typedef
+	    && TYPE_NAME (TREE_TYPE (inner)) == inner)
 	   || TREE_CODE (inner) == FUNCTION_DECL)
     {
       bool write_defn = !dep && has_definition (decl);
@@ -8088,12 +8088,6 @@  trees_in::decl_value ()
 		     && TREE_CODE (inner) == TYPE_DECL
 		     && DECL_ORIGINAL_TYPE (inner)
 		     && !TREE_TYPE (inner));
-  if (is_typedef)
-    {
-      /* Frob it to be ready for cloning.  */
-      TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner);
-      DECL_ORIGINAL_TYPE (inner) = NULL_TREE;
-    }
 
   existing = back_refs[~tag];
   bool installed = install_entity (existing);
@@ -8156,7 +8150,12 @@  trees_in::decl_value ()
 	}
 
       if (is_typedef)
-	set_underlying_type (inner);
+	{
+	  /* Frob it to be ready for cloning.  */
+	  TREE_TYPE (inner) = DECL_ORIGINAL_TYPE (inner);
+	  DECL_ORIGINAL_TYPE (inner) = NULL_TREE;
+	  set_underlying_type (inner);
+	}
 
       if (inner_tag)
 	/* Set the TEMPLATE_DECL's type.  */
@@ -8218,7 +8217,7 @@  trees_in::decl_value ()
 	/* Set the TEMPLATE_DECL's type.  */
 	TREE_TYPE (decl) = TREE_TYPE (inner);
 
-      if (!is_matching_decl (existing, decl))
+      if (!is_matching_decl (existing, decl, is_typedef))
 	unmatched_duplicate (existing);
 
       /* And our result is the existing node.  */
@@ -8257,8 +8256,8 @@  trees_in::decl_value ()
   if (inner
       && !NAMESPACE_SCOPE_P (inner)
       && ((TREE_CODE (inner) == TYPE_DECL
-	   && TYPE_NAME (TREE_TYPE (inner)) == inner
-	   && !is_typedef)
+	   && !is_typedef
+	   && TYPE_NAME (TREE_TYPE (inner)) == inner)
 	  || TREE_CODE (inner) == FUNCTION_DECL)
       && u ())
     read_definition (decl);
@@ -11088,7 +11087,7 @@  trees_in::binfo_mergeable (tree *type)
    decls_match because it can cause instantiations of constraints.  */
 
 bool
-trees_in::is_matching_decl (tree existing, tree decl)
+trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
 {
   // FIXME: We should probably do some duplicate decl-like stuff here
   // (beware, default parms should be the same?)  Can we just call
@@ -11099,35 +11098,36 @@  trees_in::is_matching_decl (tree existing, tree decl)
   // can elide some of the checking
   gcc_checking_assert (TREE_CODE (existing) == TREE_CODE (decl));
 
-  tree inner = decl;
+  tree d_inner = decl;
+  tree e_inner = existing;
   if (TREE_CODE (decl) == TEMPLATE_DECL)
     {
-      inner = DECL_TEMPLATE_RESULT (decl);
-      gcc_checking_assert (TREE_CODE (DECL_TEMPLATE_RESULT (existing))
-			   == TREE_CODE (inner));
+      d_inner = DECL_TEMPLATE_RESULT (d_inner);
+      e_inner = DECL_TEMPLATE_RESULT (e_inner);
+      gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner));
     }
 
   gcc_checking_assert (!map_context_from);
   /* This mapping requres the new decl on the lhs and the existing
      entity on the rhs of the comparitors below.  */
-  map_context_from = inner;
-  map_context_to = STRIP_TEMPLATE (existing);
+  map_context_from = d_inner;
+  map_context_to = e_inner;
 
-  if (TREE_CODE (inner) == FUNCTION_DECL)
+  if (TREE_CODE (d_inner) == FUNCTION_DECL)
     {
       tree e_ret = fndecl_declared_return_type (existing);
       tree d_ret = fndecl_declared_return_type (decl);
 
-      if (decl != inner && DECL_NAME (inner) == fun_identifier
-	  && LAMBDA_TYPE_P (DECL_CONTEXT (inner)))
+      if (decl != d_inner && DECL_NAME (d_inner) == fun_identifier
+	  && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner)))
 	/* This has a recursive type that will compare different.  */;
       else if (!same_type_p (d_ret, e_ret))
 	goto mismatch;
 
-      tree e_type = TREE_TYPE (existing);
-      tree d_type = TREE_TYPE (decl);
+      tree e_type = TREE_TYPE (e_inner);
+      tree d_type = TREE_TYPE (d_inner);
 
-      if (DECL_EXTERN_C_P (decl) != DECL_EXTERN_C_P (existing))
+      if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner))
 	goto mismatch;
 
       for (tree e_args = TYPE_ARG_TYPES (e_type),
@@ -11176,6 +11176,13 @@  trees_in::is_matching_decl (tree existing, tree decl)
 	       && !comp_except_specs (d_spec, e_spec, ce_type))
 	goto mismatch;
     }
+  else if (is_typedef)
+    {
+      if (!DECL_ORIGINAL_TYPE (e_inner)
+	  || !same_type_p (DECL_ORIGINAL_TYPE (d_inner),
+			   DECL_ORIGINAL_TYPE (e_inner)))
+	goto mismatch;
+    }
   /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs
      here. I suspect the entities that directly do that are things
      that shouldn't go to duplicate_decls (FIELD_DECLs etc).   */
@@ -11255,12 +11262,10 @@  trees_in::is_matching_decl (tree existing, tree decl)
     /* Don't instantiate again!  */
     DECL_TEMPLATE_INSTANTIATED (existing) = true;
 
-  tree e_inner = inner == decl ? existing : DECL_TEMPLATE_RESULT (existing);
-
-  if (TREE_CODE (inner) == FUNCTION_DECL
-      && DECL_DECLARED_INLINE_P (inner))
+  if (TREE_CODE (d_inner) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (d_inner))
     DECL_DECLARED_INLINE_P (e_inner) = true;
-  if (!DECL_EXTERNAL (inner))
+  if (!DECL_EXTERNAL (d_inner))
     DECL_EXTERNAL (e_inner) = false;
 
   // FIXME: Check default tmpl and fn parms here
diff --git c/gcc/testsuite/g++.dg/modules/pr98770_a.C w/gcc/testsuite/g++.dg/modules/pr98770_a.C
new file mode 100644
index 00000000000..668ff2891ca
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98770_a.C
@@ -0,0 +1,10 @@ 
+// PR 98770 confused about duplicate template type aliases
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module ;
+# 6 __FILE__ 1
+template<typename> using __void_t = void;
+# 8 "" 2
+export module Foo;
+
+export using B = __void_t<int>;
diff --git c/gcc/testsuite/g++.dg/modules/pr98770_b.C w/gcc/testsuite/g++.dg/modules/pr98770_b.C
new file mode 100644
index 00000000000..a4ab2376815
--- /dev/null
+++ w/gcc/testsuite/g++.dg/modules/pr98770_b.C
@@ -0,0 +1,12 @@ 
+// PR 98770 confused about duplicate template type aliases
+// { dg-additional-options "-fmodules-ts -Wno-pedantic" }
+
+module ;
+# 6 __FILE__ 1
+template<typename> using __void_t = void;
+# 8 "" 2
+export module Bar;
+
+import Foo;
+
+export B *b;