We weren't instantiating exception-specifications when a template referred to them, but that won't fly in the C++17 world where they're part of the type, so we need to resolve them to do overload resolution for non-dependent expressions.
The change to check_redeclaration_exception_specification is necessary because type_dependent_expression_p (fn) will fail for a dependent new_decl, beacuse it doesn't have DECL_TEMPLATE_INFO yet. Tested x86_64-pc-linux-gnu, applying to trunk.
commit e68e003bf7c837312bab52de2195ef4707150a3a Author: Jason Merrill <ja...@redhat.com> Date: Thu Apr 12 07:45:03 2018 -0400 PR c++/85356 - ICE with pointer to member function. * pt.c (maybe_instantiate_noexcept): Do instantiate in templates if flag_noexcept_type. Build the new spec within the function context. * except.c (build_noexcept_spec): Do get constant value in templates if flag_noexcept_type. * decl.c (check_redeclaration_exception_specification): Don't instantiate noexcept on a dependent declaration. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 44a152bd195..9f1a171ead7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1232,8 +1232,11 @@ check_redeclaration_exception_specification (tree new_decl, && UNEVALUATED_NOEXCEPT_SPEC_P (old_exceptions)) return; - maybe_instantiate_noexcept (new_decl); - maybe_instantiate_noexcept (old_decl); + if (!type_dependent_expression_p (old_decl)) + { + maybe_instantiate_noexcept (new_decl); + maybe_instantiate_noexcept (old_decl); + } new_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (new_decl)); old_exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old_decl)); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 0b46698b974..6dab6d6bd96 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1194,11 +1194,14 @@ build_noexcept_spec (tree expr, int complain) { /* This isn't part of the signature, so don't bother trying to evaluate it until instantiation. */ - if (!processing_template_decl && TREE_CODE (expr) != DEFERRED_NOEXCEPT) + if (TREE_CODE (expr) != DEFERRED_NOEXCEPT + && (!processing_template_decl + || (flag_noexcept_type && !value_dependent_expression_p (expr)))) { expr = perform_implicit_conversion_flags (boolean_type_node, expr, complain, LOOKUP_NORMAL); + expr = instantiate_non_dependent_expr (expr); expr = cxx_constant_value (expr); } if (TREE_CODE (expr) == INTEGER_CST) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 76e546cdeaa..da8a5264d33 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -23234,7 +23234,8 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) tree fntype, spec, noex, clone; /* Don't instantiate a noexcept-specification from template context. */ - if (processing_template_decl) + if (processing_template_decl + && (!flag_noexcept_type || type_dependent_expression_p (fn))) return true; if (DECL_CLONED_FUNCTION_P (fn)) @@ -23273,10 +23274,10 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) tf_warning_or_error, fn, /*function_p=*/false, /*integral_constant_expression_p=*/true); + spec = build_noexcept_spec (noex, tf_warning_or_error); pop_deferring_access_checks (); pop_access_scope (fn); pop_tinst_level (); - spec = build_noexcept_spec (noex, tf_warning_or_error); if (spec == error_mark_node) spec = noexcept_false_spec; } diff --git a/gcc/testsuite/g++.dg/template/mem_func_ptr2.C b/gcc/testsuite/g++.dg/template/mem_func_ptr2.C new file mode 100644 index 00000000000..9ceabd3642b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/mem_func_ptr2.C @@ -0,0 +1,13 @@ +// PR c++/85356 + +struct A +{ + A& operator=(int); +}; + +void foo(A&(A::*)(int)); + +template<int> void bar() +{ + foo(&A::operator=); +}