We were assuming well-formed code. Tested x86_64-pc-linux-gnu, applying to trunk.
commit dc80cbbc639c39dd8728aa14d6188bcd9061bfd0 Author: Jason Merrill <ja...@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 "" } +}