C++ PATCH for c++/85356, C++17 ICE with pointer to member function in template

Message ID CADzB+2mJ7_2dyhnYqqP8WxD=2dt4SsV996LUXei_go5rcXRV7A@mail.gmail.com
State New
Headers show
Series
  • C++ PATCH for c++/85356, C++17 ICE with pointer to member function in template
Related show

Commit Message

Jason Merrill April 12, 2018, 8:02 p.m.
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.

Patch

commit e68e003bf7c837312bab52de2195ef4707150a3a
Author: Jason Merrill <jason@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=);
+}