From ccb05613cfd1d37ce6473244e28c56e75d1d0e66 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Thu, 8 Oct 2009 12:09:22 -0400
Subject: [PATCH] re PR c++/37177 ([c++0x] ICE on
 decltype(rel_ops::operator><int>);)

	PR c++/37177
	* pt.c (resolve_nondeduced_context): New.
	* cvt.c (convert_to_void): Call it.
	* semantics.c (finish_decltype_type): Likewise.
	* typeck.c (decay_conversion): Here too.
	* pt.c (tsubst_decl): Don't clobber input_location.
	Don't register a bad specialization.

From-SVN: r152564
---
 gcc/cp/ChangeLog                              |  10 ++
 gcc/cp/cp-tree.h                              |   4 +-
 gcc/cp/cvt.c                                  |   1 +
 gcc/cp/pt.c                                   | 144 +++++++++++++++---
 gcc/cp/semantics.c                            |   7 +-
 gcc/cp/typeck.c                               |   1 +
 gcc/testsuite/ChangeLog                       |   8 +
 gcc/testsuite/g++.dg/cpp0x/variadic-throw.C   |   4 +-
 .../g++.dg/template/explicit-args2.C          |  38 +++++
 .../g++.dg/template/explicit-args3.C          |  12 ++
 gcc/testsuite/g++.old-deja/g++.pt/crash58.C   |  12 +-
 11 files changed, 214 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/explicit-args2.C
 create mode 100644 gcc/testsuite/g++.dg/template/explicit-args3.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5cf2373b1b23..5f672041fffa 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+2009-10-08  Jason Merrill  <jason@redhat.com>
+
+	PR c++/37177
+	* pt.c (resolve_nondeduced_context): New.
+	* cvt.c (convert_to_void): Call it.
+	* semantics.c (finish_decltype_type): Likewise.
+	* typeck.c (decay_conversion): Here too.
+	* pt.c (tsubst_decl): Don't clobber input_location.
+	Don't register a bad specialization.
+
 2009-10-07  Gabriel Dos Reis  <gdr@cs.tamu.edu>
 
 	* cp-tree.h: Fix location of documentation for DECL_LANG_FLAG_7.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 208bbe2b106c..3d826b9ad922 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4845,7 +4845,9 @@ bool template_template_parameter_p		(const_tree);
 extern tree get_primary_template_innermost_parameters	(const_tree);
 extern tree get_template_innermost_arguments	(const_tree);
 extern tree get_template_argument_pack_elems	(const_tree);
-extern tree get_function_template_decl (const_tree);
+extern tree get_function_template_decl		(const_tree);
+extern tree resolve_nondeduced_context		(tree);
+
 /* in repo.c */
 extern void init_repo				(void);
 extern int repo_emit_p				(tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index aff002dc6666..8c5b001dd15c 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -956,6 +956,7 @@ convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain)
 
     default:;
     }
+  expr = resolve_nondeduced_context (expr);
   {
     tree probe = expr;
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9ef3f79a599a..19d8c9a87df2 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8461,6 +8461,7 @@ tsubst_default_arguments (tree fn)
 static tree
 tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 {
+#define RETURN(EXP) do { r = (EXP); goto out; } while(0)
   location_t saved_loc;
   tree r = NULL_TREE;
   tree in_decl = t;
@@ -8486,7 +8487,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    /* Template template parameter is treated here.  */
 	    tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	    if (new_type == error_mark_node)
-	      return error_mark_node;
+	      RETURN (error_mark_node);
 
 	    r = copy_decl (t);
 	    TREE_CHAIN (r) = NULL_TREE;
@@ -8517,12 +8518,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 					  complain, in_decl);
 	--processing_template_decl;
 	if (full_args == error_mark_node)
-	  return error_mark_node;
+	  RETURN (error_mark_node);
 
 	/* If this is a default template template argument,
 	   tsubst might not have changed anything.  */
 	if (full_args == tmpl_args)
-	  return t;
+	  RETURN (t);
 
 	hash = hash_tmpl_and_args (t, full_args);
 	spec = retrieve_specialization (t, full_args, hash);
@@ -8550,7 +8551,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	    --processing_template_decl;
 	    if (new_type == error_mark_node)
-	      return error_mark_node;
+	      RETURN (error_mark_node);
 
 	    TREE_TYPE (r) = new_type;
 	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
@@ -8565,7 +8566,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    new_decl = tsubst (decl, args, complain, in_decl);
 	    --processing_template_decl;
 	    if (new_decl == error_mark_node)
-	      return error_mark_node;
+	      RETURN (error_mark_node);
 
 	    DECL_TEMPLATE_RESULT (r) = new_decl;
 	    DECL_TI_TEMPLATE (new_decl) = r;
@@ -8623,7 +8624,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    dependent_p = value_dependent_expression_p (t);
 	    --processing_template_decl;
 	    if (!dependent_p)
-	      return t;
+	      RETURN (t);
 
 	    /* Calculate the most general template of which R is a
 	       specialization, and the complete set of arguments used to
@@ -8714,7 +8715,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	  }
 	type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	if (type == error_mark_node)
-	  return error_mark_node;
+	  RETURN (error_mark_node);
 
 	/* We do NOT check for matching decls pushed separately at this
 	   point, as they may not represent instantiations of this
@@ -8757,6 +8758,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	/* We'll re-clone as appropriate in instantiate_template.  */
 	DECL_CLONED_FUNCTION (r) = NULL_TREE;
 
+	/* If we aren't complaining now, return on error before we register
+	   the specialization so that we'll complain eventually.  */
+	if ((complain & tf_error) == 0
+	    && IDENTIFIER_OPNAME_P (DECL_NAME (r))
+	    && !grok_op_properties (r, /*complain=*/false))
+	  RETURN (error_mark_node);
+
 	/* Set up the DECL_TEMPLATE_INFO for R.  There's no need to do
 	   this in the special friend case mentioned above where
 	   GEN_TMPL is NULL.  */
@@ -8808,9 +8816,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    if (PRIMARY_TEMPLATE_P (gen_tmpl))
 	      clone_function_decl (r, /*update_method_vec_p=*/0);
 	  }
-	else if (IDENTIFIER_OPNAME_P (DECL_NAME (r))
-		 && !grok_op_properties (r, (complain & tf_error) != 0))
-	  return error_mark_node;
+	else if ((complain & tf_error) != 0
+		 && IDENTIFIER_OPNAME_P (DECL_NAME (r))
+		 && !grok_op_properties (r, /*complain=*/true))
+	  RETURN (error_mark_node);
 
 	if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
 	  SET_DECL_FRIEND_CONTEXT (r,
@@ -8851,7 +8860,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
             if (spec 
                 && TREE_CODE (spec) == PARM_DECL
                 && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION)
-              return spec;
+              RETURN (spec);
 
             /* Expand the TYPE_PACK_EXPANSION that provides the types for
                the parameters in this function parameter pack.  */
@@ -8864,8 +8873,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
                 /* Zero-length parameter packs are boring. Just substitute
                    into the chain.  */
                 if (len == 0)
-                  return tsubst (TREE_CHAIN (t), args, complain, 
-                                 TREE_CHAIN (t));
+                  RETURN (tsubst (TREE_CHAIN (t), args, complain,
+				  TREE_CHAIN (t)));
               }
             else
               {
@@ -8955,7 +8964,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	r = copy_decl (t);
 	type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	if (type == error_mark_node)
-	  return error_mark_node;
+	  RETURN (error_mark_node);
 	TREE_TYPE (r) = type;
 	cp_apply_type_quals_to_decl (cp_type_quals (type), r);
 
@@ -9018,7 +9027,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	       we've copied the type for a typedef.  */
 	    type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	    if (type == error_mark_node)
-	      return error_mark_node;
+	      RETURN (error_mark_node);
 	    r = TYPE_NAME (type);
 	    break;
 	  }
@@ -9091,7 +9100,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    DECL_INITIALIZED_P (r) = 0;
 	    DECL_TEMPLATE_INSTANTIATED (r) = 0;
 	    if (type == error_mark_node)
-	      return error_mark_node;
+	      RETURN (error_mark_node);
 	    if (TREE_CODE (type) == FUNCTION_TYPE)
 	      {
 		/* It may seem that this case cannot occur, since:
@@ -9111,7 +9120,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 		       /* R is not yet sufficiently initialized, so we
 			  just use its name.  */
 		       DECL_NAME (r));
-		return error_mark_node;
+		RETURN (error_mark_node);
 	      }
 	    type = complete_type (type);
 	    DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r)
@@ -9207,7 +9216,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
     default:
       gcc_unreachable ();
     }
+#undef RETURN
 
+ out:
   /* Restore the file and line information.  */
   input_location = saved_loc;
 
@@ -13307,6 +13318,105 @@ resolve_overloaded_unification (tree tparms,
   return false;
 }
 
+/* Core DR 115: In contexts where deduction is done and fails, or in
+   contexts where deduction is not done, if a template argument list is
+   specified and it, along with any default template arguments, identifies
+   a single function template specialization, then the template-id is an
+   lvalue for the function template specialization.  */
+
+tree
+resolve_nondeduced_context (tree orig_expr)
+{
+  tree expr, offset, baselink;
+  bool addr;
+
+  if (!type_unknown_p (orig_expr))
+    return orig_expr;
+
+  expr = orig_expr;
+  addr = false;
+  offset = NULL_TREE;
+  baselink = NULL_TREE;
+
+  if (TREE_CODE (expr) == ADDR_EXPR)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      addr = true;
+    }
+  if (TREE_CODE (expr) == OFFSET_REF)
+    {
+      offset = expr;
+      expr = TREE_OPERAND (expr, 1);
+    }
+  if (TREE_CODE (expr) == BASELINK)
+    {
+      baselink = expr;
+      expr = BASELINK_FUNCTIONS (expr);
+    }
+
+  if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+    {
+      int good = 0;
+      tree goodfn = NULL_TREE;
+
+      /* If we got some explicit template args, we need to plug them into
+	 the affected templates before we try to unify, in case the
+	 explicit args will completely resolve the templates in question.  */
+
+      tree expl_subargs = TREE_OPERAND (expr, 1);
+      tree arg = TREE_OPERAND (expr, 0);
+      tree badfn = NULL_TREE;
+      tree badargs = NULL_TREE;
+
+      for (; arg; arg = OVL_NEXT (arg))
+	{
+	  tree fn = OVL_CURRENT (arg);
+	  tree subargs, elem;
+
+	  if (TREE_CODE (fn) != TEMPLATE_DECL)
+	    continue;
+
+	  ++processing_template_decl;
+	  subargs = get_bindings (fn, DECL_TEMPLATE_RESULT (fn),
+				  expl_subargs, /*check_ret=*/false);
+	  if (subargs && !any_dependent_template_arguments_p (subargs))
+	    {
+	      elem = instantiate_template (fn, subargs, tf_none);
+	      if (elem == error_mark_node)
+		{
+		  badfn = fn;
+		  badargs = subargs;
+		}
+	      else if (elem && (!goodfn || !decls_match (goodfn, elem)))
+		{
+		  goodfn = elem;
+		  ++good;
+		}
+	    }
+	  --processing_template_decl;
+	}
+      if (good == 1)
+	{
+	  expr = goodfn;
+	  if (baselink)
+	    expr = build_baselink (BASELINK_BINFO (baselink),
+				   BASELINK_ACCESS_BINFO (baselink),
+				   expr, BASELINK_OPTYPE (baselink));
+	  if (offset)
+	    expr = build2 (OFFSET_REF, TREE_TYPE (expr),
+			   TREE_OPERAND (offset, 0), expr);
+	  if (addr)
+	    expr = build_address (expr);
+	  return expr;
+	}
+      else if (good == 0 && badargs)
+	/* There were no good options and at least one bad one, so let the
+	   user know what the problem is.  */
+	instantiate_template (badfn, badargs, tf_warning_or_error);
+    }
+  return orig_expr;
+}
+
 /* Subroutine of resolve_overloaded_unification; does deduction for a single
    overload.  Fills TARGS with any deduced arguments, or error_mark_node if
    different overloads deduce different arguments for a given parm.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 391228b02a63..6cf22204a5e0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4741,6 +4741,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
 
   /* The type denoted by decltype(e) is defined as follows:  */
 
+  expr = resolve_nondeduced_context (expr);
   if (id_expression_or_member_access_p)
     {
       /* If e is an id-expression or a class member access (5.2.5
@@ -4766,9 +4767,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
         /* See through BASELINK nodes to the underlying functions.  */
         expr = BASELINK_FUNCTIONS (expr);
 
+      if (TREE_CODE (expr) == TEMPLATE_ID_EXPR)
+	expr = TREE_OPERAND (expr, 0);
+
       if (TREE_CODE (expr) == OVERLOAD)
         {
-          if (OVL_CHAIN (expr))
+          if (OVL_CHAIN (expr)
+	      || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL)
             {
               error ("%qE refers to a set of overloaded functions", orig_expr);
               return error_mark_node;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 79b0201b77ad..526e7066a60c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1613,6 +1613,7 @@ decay_conversion (tree exp)
   if (type == error_mark_node)
     return error_mark_node;
 
+  exp = resolve_nondeduced_context (exp);
   if (type_unknown_p (exp))
     {
       cxx_incomplete_type_error (exp, TREE_TYPE (exp));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bf7e5ba08f4d..edfbe1df6739 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2009-10-08  Jason Merrill  <jason@redhat.com>
+
+	PR c++/37177
+	* g++.dg/cpp0x/variadic-throw.C: Adjust errors.
+	* g++.dg/template/explicit-args2.C: New.
+	* g++.dg/template/explicit-args3.C: New.
+	* g++.old-deja/g++.pt/crash58.C: Remove some errors.
+
 2009-10-08  Michael Matz  <matz@suse.de>
 
 	PR middle-end/41573
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C b/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C
index f2ff652d8a0f..ee85bf2a5692 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-throw.C
@@ -8,7 +8,7 @@ template<int M, int N> struct pair
 
 template<int... M> struct S
 {
-  template<int... N> static int foo() throw (pair <M, N>...) // { dg-error "mismatched|no matching" }
+  template<int... N> static int foo() throw (pair <M, N>...) // { dg-error "mismatched" }
   {
     return 1;
   }
@@ -21,5 +21,5 @@ int bar ()
 
 int wibble()
 {
-  return S<0, 1, 2>::foo<0, 1> ();
+  return S<0, 1, 2>::foo<0, 1> (); // { dg-error "no matching" }
 }
diff --git a/gcc/testsuite/g++.dg/template/explicit-args2.C b/gcc/testsuite/g++.dg/template/explicit-args2.C
new file mode 100644
index 000000000000..cd53b456dcc7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit-args2.C
@@ -0,0 +1,38 @@
+// PR c++/37177
+// { dg-options -std=c++0x }
+
+namespace N1
+{
+  template<class T> bool foo();
+}
+
+struct S
+{
+  template <class T>
+  static bool foo();
+
+  template <class T>
+  bool bar();
+};
+
+template<class T> bool foo();
+
+int main()
+{
+  (void)(&S::bar<int>);
+  decltype(&S::bar<int>) a;
+
+  (void*)(&S::foo<int>);
+  (void)(&S::foo<int>);
+  decltype(&S::foo<int>) b;
+
+  (void*)(&N1::foo<int>);
+  (void)(&N1::foo<int>);
+  decltype(&N1::foo<int>) c;
+
+  (void*)(&foo<int>);
+  (void)(&foo<int>);
+  decltype(&foo<int>) d;
+
+  &foo<int> == 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/explicit-args3.C b/gcc/testsuite/g++.dg/template/explicit-args3.C
new file mode 100644
index 000000000000..c095e6688fdc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/explicit-args3.C
@@ -0,0 +1,12 @@
+// PR c++/37177
+
+template <class T>
+struct A { };
+
+template <class T>
+void operator+(T, T);		// { dg-error "class or enum" }
+
+int main()
+{
+  operator+<int>;		// { dg-error "cannot resolve" }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash58.C b/gcc/testsuite/g++.old-deja/g++.pt/crash58.C
index 315f3e02896b..0ce3d81723d5 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash58.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash58.C
@@ -15,16 +15,16 @@ struct MatrixC
 {
   void foo () {
     EManip::do_assign<T> (0);
-    &EManip::do_assign<T>;	// { dg-error "" } unresolved
-    &do_assign<T>;		// { dg-error "" } unresolved
-    EManip::do_assign<T>;       // { dg-error "" } unresolved
-    do_assign<T>;               // { dg-error "" } unresolved
+    &EManip::do_assign<T>;	// { dg-bogus "" } unresolved
+    &do_assign<T>;		// { dg-bogus "" } unresolved
+    EManip::do_assign<T>;       // { dg-bogus "" } unresolved
+    do_assign<T>;               // { dg-bogus "" } unresolved
   }
 };
 void foo(MatrixC <double> *ptr)
 {
-  EManip::do_assign<double>;    // { dg-error "" } unresolved
-  &EManip::do_assign<double>;	// { dg-error "" } unresolved
+  EManip::do_assign<double>;    // { dg-bogus "" } unresolved
+  &EManip::do_assign<double>;	// { dg-bogus "" } unresolved
   ptr->foo ();
   void (*p1) (int *) = &do_assign<double>;       // { dg-error "" } cannot convert
   void (*p2) (int *) = &EManip::do_assign<double>; // { dg-error "" } cannot convert
-- 
GitLab