From ac24fa46e449fbff0ff571951cfcc78b8488f6e7 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Thu, 8 Apr 2021 01:03:28 -0400
Subject: [PATCH] c++: improve specialization mismatch diagnostic [PR94529]

We were telling users they needed more template<> to specialize a member
template in a testcase with no member templates.  Only produce that message
if we actually see a member template, and also always print the candidates.

gcc/cp/ChangeLog:

	PR c++/94529
	* pt.c (determine_specialization): Improve diagnostic.

gcc/testsuite/ChangeLog:

	PR c++/94529
	* g++.dg/template/mem-spec2.C: New test.
---
 gcc/cp/pt.c                               | 11 +++++++----
 gcc/testsuite/g++.dg/template/mem-spec2.C | 11 +++++++++++
 2 files changed, 18 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/mem-spec2.C

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index dee802121e5d..46b237f2ec0a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2201,6 +2201,7 @@ determine_specialization (tree template_id,
     ++header_count;
 
   tree orig_fns = fns;
+  bool header_mismatch = false;
 
   if (variable_template_p (fns))
     {
@@ -2248,7 +2249,10 @@ determine_specialization (tree template_id,
 	     specialization but rather a template instantiation, so there
 	     is no check we can perform here.  */
 	  if (header_count && header_count != template_count + 1)
-	    continue;
+	    {
+	      header_mismatch = true;
+	      continue;
+	    }
 
 	  /* Check that the number of template arguments at the
 	     innermost level for DECL is the same as for FN.  */
@@ -2482,13 +2486,12 @@ determine_specialization (tree template_id,
     {
       error ("template-id %qD for %q+D does not match any template "
 	     "declaration", template_id, decl);
-      if (header_count && header_count != template_count + 1)
+      if (header_mismatch)
 	inform (DECL_SOURCE_LOCATION (decl),
 		"saw %d %<template<>%>, need %d for "
 		"specializing a member function template",
 		header_count, template_count + 1);
-      else
-	print_candidates (orig_fns);
+      print_candidates (orig_fns);
       return error_mark_node;
     }
   else if ((templates && TREE_CHAIN (templates))
diff --git a/gcc/testsuite/g++.dg/template/mem-spec2.C b/gcc/testsuite/g++.dg/template/mem-spec2.C
new file mode 100644
index 000000000000..bc96159522c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/mem-spec2.C
@@ -0,0 +1,11 @@
+// PR c++/94529
+
+template <class T>
+struct foo {
+    // the issue is const here
+    void bar(T& foobar) const { foobar = 0; } // { dg-message "candidate" }
+};
+
+template <> void
+foo<int>::bar(int& foobar) { foobar = 9; } // { dg-error "does not match" }
+// { dg-bogus "member function template" "" { target *-*-* } .-1 }
-- 
GitLab