public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7134] c++: memfn lookup consistency and using-decls [PR104432]
@ 2022-02-09 16:33 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2022-02-09 16:33 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:ee50b4383a0dca88172c3a821418344bd7391956

commit r12-7134-gee50b4383a0dca88172c3a821418344bd7391956
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Feb 9 11:33:04 2022 -0500

    c++: memfn lookup consistency and using-decls [PR104432]
    
    In filter_memfn_lookup, we weren't correctly recognizing and matching up
    member functions introduced via a non-dependent using-decl.  This caused
    us to crash in the below testcases in which we correctly pruned the
    overload set for the non-dependent call ahead of time, but then at
    instantiation time filter_memfn_lookup failed to match the selected
    function (introduced in each case by a non-dependent using-decl) to the
    corresponding function from the new lookup set.  Such member functions
    need special handling in filter_memfn_lookup because they look exactly
    the same in the old and new lookup sets, whereas ordinary member
    functions that're defined in the (dependent) current class become more
    specialized in the new lookup set.
    
    This patch reworks the matching logic in filter_memfn_lookup so that it
    handles (member functions introduced by) non-dependent using-decls
    correctly, and is hopefully simpler overall.
    
            PR c++/104432
    
    gcc/cp/ChangeLog:
    
            * call.cc (build_new_method_call): When a non-dependent call
            resolves to a specialization of a member template, always build
            the pruned overload set using the member template, not the
            specialization.
            * pt.cc (filter_memfn_lookup): New parameter newtype.  Simplify
            and correct how members from the new lookup set are matched to
            those from the old one.
            (tsubst_baselink): Pass binfo_type as newtype to
            filter_memfn_lookup.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/template/non-dependent19.C: New test.
            * g++.dg/template/non-dependent19a.C: New test.
            * g++.dg/template/non-dependent20.C: New test.

Diff:
---
 gcc/cp/call.cc                                   |  9 ++---
 gcc/cp/pt.cc                                     | 49 +++++++++++-------------
 gcc/testsuite/g++.dg/template/non-dependent19.C  | 14 +++++++
 gcc/testsuite/g++.dg/template/non-dependent19a.C | 16 ++++++++
 gcc/testsuite/g++.dg/template/non-dependent20.C  | 16 ++++++++
 5 files changed, 73 insertions(+), 31 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index b2e89c5d783..d6eed5ed835 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -11189,12 +11189,11 @@ build_new_method_call (tree instance, tree fns, vec<tree, va_gc> **args,
       if (really_overloaded_fn (fns))
 	{
 	  if (DECL_TEMPLATE_INFO (fn)
-	      && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn))
-	      && dependent_type_p (DECL_CONTEXT (fn)))
+	      && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
 	    {
-	      /* FIXME: We're not prepared to fully instantiate "inside-out"
-		 partial instantiations such as A<T>::f<int>().  So instead
-		 use the selected template, not the specialization.  */
+	      /* Use the selected template, not the specialization, so that
+		 this looks like an actual lookup result for sake of
+		 filter_memfn_lookup.  */
 
 	      if (OVL_SINGLE_P (fns))
 		/* If the original overload set consists of a single function
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 5c995da62c6..86b6ddc634f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -16317,12 +16317,12 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 }
 
 /* OLDFNS is a lookup set of member functions from some class template, and
-   NEWFNS is a lookup set of member functions from a specialization of that
-   class template.  Return the subset of NEWFNS which are specializations of
-   a function from OLDFNS.  */
+   NEWFNS is a lookup set of member functions from NEWTYPE, a specialization
+   of that class template.  Return the subset of NEWFNS which are
+   specializations of a function from OLDFNS.  */
 
 static tree
-filter_memfn_lookup (tree oldfns, tree newfns)
+filter_memfn_lookup (tree oldfns, tree newfns, tree newtype)
 {
   /* Record all member functions from the old lookup set OLDFNS into
      VISIBLE_SET.  */
@@ -16332,38 +16332,34 @@ filter_memfn_lookup (tree oldfns, tree newfns)
       if (TREE_CODE (fn) == USING_DECL)
 	{
 	  /* FIXME: Punt on (dependent) USING_DECL for now; mapping
-	     a dependent USING_DECL to its instantiation seems
-	     tricky.  */
+	     a dependent USING_DECL to the member functions it introduces
+	     seems tricky.  */
 	  gcc_checking_assert (DECL_DEPENDENT_P (fn));
 	  return newfns;
 	}
-      else if (TREE_CODE (fn) == TEMPLATE_DECL)
-	/* A member function template.  */
-	visible_set.add (fn);
-      else if (TREE_CODE (fn) == FUNCTION_DECL)
-	{
-	  if (DECL_TEMPLATE_INFO (fn))
-	    /* A non-template member function.  */
-	    visible_set.add (DECL_TI_TEMPLATE (fn));
-	  else
-	    /* A non-template member function from a non-template base,
-	       injected via a using-decl.  */
-	    visible_set.add (fn);
-	}
       else
-	gcc_unreachable ();
+	visible_set.add (fn);
     }
 
   /* Returns true iff (a less specialized version of) FN appeared in
      the old lookup set OLDFNS.  */
-  auto visible_p = [&visible_set] (tree fn) {
-    if (TREE_CODE (fn) == FUNCTION_DECL
-	&& !DECL_TEMPLATE_INFO (fn))
+  auto visible_p = [newtype, &visible_set] (tree fn) {
+    if (DECL_CONTEXT (fn) != newtype)
+      /* FN is a member function from a base class, introduced via a
+	 non-dependent using-decl; look in the old lookup set for
+	 FN exactly.  */
       return visible_set.contains (fn);
-    else if (DECL_TEMPLATE_INFO (fn))
+    else if (TREE_CODE (fn) == TEMPLATE_DECL)
+      /* FN is a member function template from the current class;
+	 look in the old lookup set for the TEMPLATE_DECL from which
+	 it was specialized.  */
       return visible_set.contains (DECL_TI_TEMPLATE (fn));
     else
-      gcc_unreachable ();
+      /* FN is a non-template member function from the current class;
+	 look in the old lookup set for the FUNCTION_DECL from which
+	 it was specialized.  */
+      return visible_set.contains (DECL_TEMPLATE_RESULT
+				   (DECL_TI_TEMPLATE (fn)));
   };
 
   bool lookup_changed_p = false;
@@ -16455,7 +16451,8 @@ tsubst_baselink (tree baselink, tree object_type,
 	     performed in an incomplete-class context, within which
 	     later-declared members ought to remain invisible.  */
 	  BASELINK_FUNCTIONS (baselink)
-	    = filter_memfn_lookup (fns, BASELINK_FUNCTIONS (baselink));
+	    = filter_memfn_lookup (fns, BASELINK_FUNCTIONS (baselink),
+				   binfo_type);
 	  BASELINK_FUNCTIONS_MAYBE_INCOMPLETE_P (baselink) = true;
 	}
 
diff --git a/gcc/testsuite/g++.dg/template/non-dependent19.C b/gcc/testsuite/g++.dg/template/non-dependent19.C
new file mode 100644
index 00000000000..d690e80f2eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent19.C
@@ -0,0 +1,14 @@
+// PR c++/104432
+// { dg-do compile { target c++11 } }
+
+struct A {
+  template<class=int> void f();
+  void f(int);
+};
+
+template<class> struct B : A {
+  using A::f;
+  void g() { f(); }
+};
+
+template struct B<int>;
diff --git a/gcc/testsuite/g++.dg/template/non-dependent19a.C b/gcc/testsuite/g++.dg/template/non-dependent19a.C
new file mode 100644
index 00000000000..2f523c81988
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent19a.C
@@ -0,0 +1,16 @@
+// PR c++/104432
+// { dg-do compile { target c++11 } }
+// A variant of non-dependent19.C where A is a template.
+
+template<class>
+struct A {
+  template<class=int> void f();
+  void f(int);
+};
+
+template<class> struct B : A<int> {
+  using A<int>::f;
+  void g() { f(); }
+};
+
+template struct B<int>;
diff --git a/gcc/testsuite/g++.dg/template/non-dependent20.C b/gcc/testsuite/g++.dg/template/non-dependent20.C
new file mode 100644
index 00000000000..ebf7d7f40fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent20.C
@@ -0,0 +1,16 @@
+// PR c++/104432
+// { dg-do compile { target c++11 } }
+
+template<class T>
+struct A {
+  template<class=int> static void f(T);
+  static void f();
+};
+
+template<class> struct B : A<int>, A<int&> {
+  using A<int>::f;
+  using A<int&>::f;
+  void g() { f(0); }
+};
+
+template struct B<int>;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-02-09 16:33 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-09 16:33 [gcc r12-7134] c++: memfn lookup consistency and using-decls [PR104432] Patrick Palka

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).