diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3d304917b3c..1b640ff3309 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2013-01-25 Jason Merrill + 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. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 01d42959754..743028942ed 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 00000000000..742135a1e38 --- /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 void z1(void) {} +template void z2(void) {} + +int main() +{ + z1<(voidfn*)a>(); // { dg-error "" } + z1(a)>(); // { dg-error "" } + z2<(voidfn&)a>(); // { dg-error "" } + z2(a)>(); // { dg-error "" } +}