re PR c++/56095 (Crash casting function pointer as non-type template argument)
authorJason Merrill <jason@redhat.com>
Fri, 25 Jan 2013 20:01:29 +0000 (15:01 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 25 Jan 2013 20:01:29 +0000 (15:01 -0500)
PR c++/56095
* pt.c (convert_nontype_argument_function): Handle invalid input.
(convert_nontype_argument): Likewise.

From-SVN: r195474

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/template/fn-ptr2.C [new file with mode: 0644]

index 3d30491..1b640ff 100644 (file)
@@ -1,5 +1,9 @@
 2013-01-25  Jason Merrill  <jason@redhat.com>
 
+       PR c++/56095
+       * pt.c (convert_nontype_argument_function): Handle invalid input.
+       (convert_nontype_argument): Likewise.
+
        PR c++/56104
        * typeck.c (get_member_function_from_ptrfunc): Optimize if the
        dynamic type has no virtual functions.
index 01d4295..7430289 100644 (file)
@@ -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 (file)
index 0000000..742135a
--- /dev/null
@@ -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 "" }
+}