diff mbox

C++ PATCH for c++/56095 (ICE on invalid function pointer template argument)

Message ID 5102E2C1.507@redhat.com
State New
Headers show

Commit Message

Jason Merrill Jan. 25, 2013, 7:53 p.m. UTC
We were assuming well-formed code.

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

Patch

commit dc80cbbc639c39dd8728aa14d6188bcd9061bfd0
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 25 06:15:26 2013 -0500

    	PR c++/56095
    	* pt.c (convert_nontype_argument_function): Handle invalid input.
    	(convert_nontype_argument): Likewise.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 01d4295..7430289 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5113,6 +5113,17 @@  convert_nontype_argument_function (tree type, tree expr)
      [...]
      -- the address of an object or function with external [C++11: or
         internal] linkage.  */
+
+  if (TREE_CODE (fn_no_ptr) != FUNCTION_DECL)
+    {
+      error ("%qE is not a valid template argument for type %qT", expr, type);
+      if (TREE_CODE (type) == POINTER_TYPE)
+	error ("it must be the address of a function with external linkage");
+      else
+	error ("it must be the name of a function with external linkage");
+      return NULL_TREE;
+    }
+
   linkage = decl_linkage (fn_no_ptr);
   if (cxx_dialect >= cxx0x ? linkage == lk_none : linkage != lk_external)
     {
@@ -5511,15 +5522,16 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	     could actually change the type to something more cv-qualified,
 	     and this is not folded by convert_from_reference.  */
 	  tree addr = TREE_OPERAND (probe, 0);
-	  gcc_assert (TREE_CODE (probe_type) == REFERENCE_TYPE);
-	  gcc_assert (TREE_CODE (addr) == ADDR_EXPR);
-	  gcc_assert (TREE_CODE (TREE_TYPE (addr)) == POINTER_TYPE);
-	  gcc_assert (same_type_ignoring_top_level_qualifiers_p
-		      (TREE_TYPE (probe_type),
-		       TREE_TYPE (TREE_TYPE (addr))));
-
-	  expr = TREE_OPERAND (addr, 0);
-	  expr_type = TREE_TYPE (expr);
+	  if (TREE_CODE (probe_type) == REFERENCE_TYPE
+	      && TREE_CODE (addr) == ADDR_EXPR
+	      && TREE_CODE (TREE_TYPE (addr)) == POINTER_TYPE
+	      && (same_type_ignoring_top_level_qualifiers_p
+		  (TREE_TYPE (probe_type),
+		   TREE_TYPE (TREE_TYPE (addr)))))
+	    {
+	      expr = TREE_OPERAND (addr, 0);
+	      expr_type = TREE_TYPE (expr);
+	    }
 	}
     }
 
@@ -5745,13 +5757,6 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       expr = convert_nontype_argument_function (type, expr);
       if (!expr || expr == error_mark_node)
 	return expr;
-
-      if (TREE_CODE (expr) != ADDR_EXPR)
-	{
-	  error ("%qE is not a valid template argument for type %qT", expr, type);
-	  error ("it must be the address of a function with external linkage");
-	  return NULL_TREE;
-	}
     }
   /* [temp.arg.nontype]/5, bullet 5
 
diff --git a/gcc/testsuite/g++.dg/template/fn-ptr2.C b/gcc/testsuite/g++.dg/template/fn-ptr2.C
new file mode 100644
index 0000000..742135a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fn-ptr2.C
@@ -0,0 +1,14 @@ 
+// PR c++/56095
+
+int *a(void) { return 0; }
+typedef void voidfn(void);
+template <voidfn* b> void z1(void) {}
+template <voidfn& b> void z2(void) {}
+
+int main()
+{
+  z1<(voidfn*)a>();		      // { dg-error "" }
+  z1<reinterpret_cast<voidfn*>(a)>(); // { dg-error "" }
+  z2<(voidfn&)a>();		      // { dg-error "" }
+  z2<reinterpret_cast<voidfn&>(a)>(); // { dg-error "" }
+}