public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [pushed] c++: redeclared hidden friend take 2 [PR105852]
@ 2022-06-08 20:38 Jason Merrill
  2022-06-08 20:38 ` [pushed] c++: non-templated friends [PR105852] Jason Merrill
  0 siblings, 1 reply; 2+ messages in thread
From: Jason Merrill @ 2022-06-08 20:38 UTC (permalink / raw)
  To: gcc-patches

My previous patch for 105761 avoided copying DECL_TEMPLATE_INFO from a
friend to a later definition, but in this testcase we have first a
non-friend declaration and then a definition, and we need to avoid copying
in that case as well.  But we do still want to set new_template_info to
avoid GC trouble.

With this change, the modules dump correctly identifies ::foo as a
non-template function in tpl-friend-2_a.C.

Along the way I noticed that the duplicate_decls handling of
DECL_UNIQUE_FRIEND_P was backwards for templates, where we don't clobber
DECL_LANG_SPECIFIC (olddecl) with DECL_LANG_SPECIFIC (newdecl) like we do
for non-templates.

Tested x86_64-pc-linux-gnu, applying to trunk.

	PR c++/105852
	PR c++/105761

gcc/cp/ChangeLog:

	* decl.cc (duplicate_decls): Avoid copying template info
	from non-templated friend even if newdecl isn't a definition.
	Correct handling of DECL_UNIQUE_FRIEND_P on templates.
	* pt.cc (non_templated_friend_p): New.
	* cp-tree.h (non_templated_friend_p): Declare it.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/tpl-friend-2_a.C: Adjust expected dump.
	* g++.dg/template/friend74.C: New test.
---
 gcc/cp/cp-tree.h                              |  1 +
 gcc/cp/decl.cc                                | 16 ++++------
 gcc/cp/pt.cc                                  | 29 ++++++++++++++++++-
 gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C |  2 +-
 gcc/testsuite/g++.dg/template/friend74.C      |  8 +++++
 5 files changed, 44 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/friend74.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index cc13809f38a..3d8a08b8dd7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7395,6 +7395,7 @@ extern bool push_tinst_level_loc                (tree, location_t);
 extern bool push_tinst_level_loc                (tree, tree, location_t);
 extern void pop_tinst_level                     (void);
 extern struct tinst_level *outermost_tinst_level(void);
+extern bool non_templated_friend_p		(tree);
 extern void init_template_processing		(void);
 extern void print_template_statistics		(void);
 bool template_template_parameter_p		(const_tree);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 7add82aa39e..3e869954ccb 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2294,8 +2294,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 	      merge_default_template_args (new_parms, old_parms,
 					   /*class_p=*/false);
 	    }
-	  if (!DECL_UNIQUE_FRIEND_P (old_result))
-	    DECL_UNIQUE_FRIEND_P (new_result) = false;
+	  if (!DECL_UNIQUE_FRIEND_P (new_result))
+	    DECL_UNIQUE_FRIEND_P (old_result) = false;
 
 	  check_default_args (newdecl);
 
@@ -2654,13 +2654,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
       if (LANG_DECL_HAS_MIN (newdecl))
 	{
 	  DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
-	  if (new_defines_function
-	      && DECL_TEMPLATE_INFO (olddecl)
-	      && DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT
-				       (DECL_TI_TEMPLATE (olddecl))))
-	    /* Don't copy template info from a non-template friend declaration
-	       in a class template (PR105761).  */;
-	  else if (DECL_TEMPLATE_INFO (newdecl))
+	  if (DECL_TEMPLATE_INFO (newdecl))
 	    {
 	      new_template_info = DECL_TEMPLATE_INFO (newdecl);
 	      if (DECL_TEMPLATE_INSTANTIATION (olddecl)
@@ -2668,8 +2662,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 		/* Remember the presence of explicit specialization args.  */
 		TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl))
 		  = TINFO_USED_TEMPLATE_ID (new_template_info);
-	      DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
 	    }
+
+	  if (non_templated_friend_p (olddecl))
+	    /* Don't copy tinfo from a non-templated friend (PR105761).  */;
 	  else
 	    DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
 	}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index dcacba56a1c..9c1b026857e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11165,6 +11165,33 @@ outermost_tinst_level (void)
   return level;
 }
 
+/* True iff T is a friend function declaration that is not itself a template
+   and is not defined in a class template.  */
+
+bool
+non_templated_friend_p (tree t)
+{
+  if (t && TREE_CODE (t) == FUNCTION_DECL
+      && DECL_UNIQUE_FRIEND_P (t))
+    {
+      tree ti = DECL_TEMPLATE_INFO (t);
+      if (!ti)
+	return true;
+      /* DECL_FRIEND_CONTEXT is set for a friend defined in class.  */
+      if (DECL_FRIEND_CONTEXT (t))
+	return false;
+      /* Non-templated friends in a class template are still represented with a
+	 TEMPLATE_DECL; check that its primary template is the befriending
+	 class.  Note that DECL_PRIMARY_TEMPLATE is null for
+	 template <class T> friend A<T>::f(); */
+      tree tmpl = TI_TEMPLATE (ti);
+      tree primary = DECL_PRIMARY_TEMPLATE (tmpl);
+      return (primary && primary != tmpl);
+    }
+  else
+    return false;
+}
+
 /* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL.  ARGS is the
    vector of template arguments, as for tsubst.
 
@@ -14094,7 +14121,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
       /* This special case arises when we have something like this:
 
 	 template <class T> struct S {
-	 friend void f<int>(int, double);
+	   friend void f<int>(int, double);
 	 };
 
 	 Here, the DECL_TI_TEMPLATE for the friend declaration
diff --git a/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C b/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C
index 3acacf8ee34..c12857fbf69 100644
--- a/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C
+++ b/gcc/testsuite/g++.dg/modules/tpl-friend-2_a.C
@@ -16,5 +16,5 @@ template class TPL<int>;  // instantiate
 void foo (int, void *);
 
 // { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl definition '::template TPL'\n(  \[.\]=[^\n]*'\n)*  \[.\]=decl declaration '::template foo'\n(  \[.\]=[^\n]*'\n)*  \[.\]=binding '::TPL'} module } }
-// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::foo<int>'\n  \[.\]=binding '::foo'} module } }
+// { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=decl declaration '::foo'\n  \[.\]=binding '::foo'} module } }
 // { dg-final { scan-lang-dump {Cluster members:\n  \[0\]=specialization definition '::TPL<int>'} module } }
diff --git a/gcc/testsuite/g++.dg/template/friend74.C b/gcc/testsuite/g++.dg/template/friend74.C
new file mode 100644
index 00000000000..51708334d81
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend74.C
@@ -0,0 +1,8 @@
+// PR c++/105852
+// { dg-additional-options -w }
+
+template <class> struct Local { friend Local False(int *); };
+Local<int> loc;
+Local<int> False(int *);
+void New() { False; }
+Local<int> False(int *) { return Local<int>(); }

base-commit: b6e1373bd34aebbb512a03ea9a4e3c7acd955382
-- 
2.27.0


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

* [pushed] c++: non-templated friends [PR105852]
  2022-06-08 20:38 [pushed] c++: redeclared hidden friend take 2 [PR105852] Jason Merrill
@ 2022-06-08 20:38 ` Jason Merrill
  0 siblings, 0 replies; 2+ messages in thread
From: Jason Merrill @ 2022-06-08 20:38 UTC (permalink / raw)
  To: gcc-patches

The previous patch for 105852 avoids copying DECL_TEMPLATE_INFO from a
non-templated friend, but it really shouldn't have it in the first place.

Tested x86_64-pc-linux-gnu, applying to trunk.

	PR c++/105852

gcc/cp/ChangeLog:

	* decl.cc (duplicate_decls): Change non-templated friend
	check to an assert.
	* pt.cc	(tsubst_function_decl): Don't set DECL_TEMPLATE_INFO
	on non-templated friends.
	(tsubst_friend_function): Adjust.
---
 gcc/cp/decl.cc |  9 +++++----
 gcc/cp/pt.cc   | 14 ++++++++++----
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 3e869954ccb..7f3b3c3c588 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2664,10 +2664,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
 		  = TINFO_USED_TEMPLATE_ID (new_template_info);
 	    }
 
-	  if (non_templated_friend_p (olddecl))
-	    /* Don't copy tinfo from a non-templated friend (PR105761).  */;
-	  else
-	    DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
+	  /* We don't want to copy template info from a non-templated friend
+	     (PR105761), but these shouldn't have DECL_TEMPLATE_INFO now.  */
+	  gcc_checking_assert (!DECL_TEMPLATE_INFO (olddecl)
+			       || !non_templated_friend_p (olddecl));
+	  DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
 	}
 
       if (DECL_DECLARES_FUNCTION_P (newdecl))
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 9c1b026857e..3154186ac20 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -11298,9 +11298,10 @@ tsubst_friend_function (tree decl, tree args)
       tree new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
       tree new_friend_result_template_info = NULL_TREE;
       bool new_friend_is_defn =
-	(DECL_INITIAL (DECL_TEMPLATE_RESULT
-		       (template_for_substitution (new_friend)))
-	 != NULL_TREE);
+	(new_friend_template_info
+	 && (DECL_INITIAL (DECL_TEMPLATE_RESULT
+			   (template_for_substitution (new_friend)))
+	     != NULL_TREE));
       tree not_tmpl = new_friend;
 
       if (TREE_CODE (new_friend) == TEMPLATE_DECL)
@@ -14084,6 +14085,10 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
 	  && !LAMBDA_FUNCTION_P (t))
 	return t;
 
+      /* A non-templated friend doesn't get DECL_TEMPLATE_INFO.  */
+      if (non_templated_friend_p (t))
+	goto friend_case;
+
       /* Calculate the most general template of which R is a
 	 specialization.  */
       gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
@@ -14129,6 +14134,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
 	 tsubst_friend_function, and we want only to create a
 	 new decl (R) with appropriate types so that we can call
 	 determine_specialization.  */
+    friend_case:
       gen_tmpl = NULL_TREE;
       argvec = NULL_TREE;
     }
@@ -14324,7 +14330,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
       /* If this is an instantiation of a member template, clone it.
 	 If it isn't, that'll be handled by
 	 clone_constructors_and_destructors.  */
-      if (PRIMARY_TEMPLATE_P (gen_tmpl))
+      if (gen_tmpl && PRIMARY_TEMPLATE_P (gen_tmpl))
 	clone_cdtor (r, /*update_methods=*/false);
     }
   else if ((complain & tf_error) != 0

base-commit: 7d87790a871482e9c5142a8e885b4a5f76d197c8
-- 
2.27.0


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

end of thread, other threads:[~2022-06-08 20:38 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 20:38 [pushed] c++: redeclared hidden friend take 2 [PR105852] Jason Merrill
2022-06-08 20:38 ` [pushed] c++: non-templated friends [PR105852] 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).