PR c++/89612 - ICE with member friend template with noexcept.
authorMarek Polacek <polacek@redhat.com>
Thu, 28 Mar 2019 20:24:48 +0000 (20:24 +0000)
committerMarek Polacek <mpolacek@gcc.gnu.org>
Thu, 28 Mar 2019 20:24:48 +0000 (20:24 +0000)
* pt.c (maybe_instantiate_noexcept): For function templates, use their
template result (function decl).  Don't set up local specializations.
Temporarily turn on processing_template_decl.  Update the template type
too.

* g++.dg/cpp0x/noexcept38.C: New test.
* g++.dg/cpp0x/noexcept39.C: New test.
* g++.dg/cpp1z/noexcept-type21.C: New test.

From-SVN: r270005

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/noexcept38.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/noexcept39.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C [new file with mode: 0644]

index 075e977b70b3c59059a3fc2636d26e96f4816008..eb35f9ec798ff530782354fc05faf42e4468510a 100644 (file)
@@ -1,5 +1,11 @@
 2019-03-28  Marek Polacek  <polacek@redhat.com>
 
+       PR c++/89612 - ICE with member friend template with noexcept.
+       * pt.c (maybe_instantiate_noexcept): For function templates, use their
+       template result (function decl).  Don't set up local specializations.
+       Temporarily turn on processing_template_decl.  Update the template type
+       too.
+
        PR c++/89836 - bool constant expression and explicit conversions.
        * call.c (build_converted_constant_expr_internal): New function,
        renamed from...
index 229b34a197e4ca9be4290ddfba89c1ec488ea746..91c341589be5dddd6a953ccfc76066e55980bf65 100644 (file)
@@ -24193,6 +24193,17 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
 
   if (DECL_CLONED_FUNCTION_P (fn))
     fn = DECL_CLONED_FUNCTION (fn);
+
+  tree orig_fn = NULL_TREE;
+  /* For a member friend template we can get a TEMPLATE_DECL.  Let's use
+     its FUNCTION_DECL for the rest of this function -- push_access_scope
+     doesn't accept TEMPLATE_DECLs.  */
+  if (DECL_FUNCTION_TEMPLATE_P (fn))
+    {
+      orig_fn = fn;
+      fn = DECL_TEMPLATE_RESULT (fn);
+    }
+
   fntype = TREE_TYPE (fn);
   spec = TYPE_RAISES_EXCEPTIONS (fntype);
 
@@ -24229,37 +24240,41 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
          push_deferring_access_checks (dk_no_deferred);
          input_location = DECL_SOURCE_LOCATION (fn);
 
-         /* A new stack interferes with pop_access_scope.  */
-         {
-           /* Set up the list of local specializations.  */
-           local_specialization_stack lss (lss_copy);
-
-           tree save_ccp = current_class_ptr;
-           tree save_ccr = current_class_ref;
-           /* If needed, set current_class_ptr for the benefit of
-              tsubst_copy/PARM_DECL.  */
-           tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
-           if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
-             {
-               tree this_parm = DECL_ARGUMENTS (tdecl);
-               current_class_ptr = NULL_TREE;
-               current_class_ref = cp_build_fold_indirect_ref (this_parm);
-               current_class_ptr = this_parm;
-             }
+         tree save_ccp = current_class_ptr;
+         tree save_ccr = current_class_ref;
+         /* If needed, set current_class_ptr for the benefit of
+            tsubst_copy/PARM_DECL.  */
+         tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
+         if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
+           {
+             tree this_parm = DECL_ARGUMENTS (tdecl);
+             current_class_ptr = NULL_TREE;
+             current_class_ref = cp_build_fold_indirect_ref (this_parm);
+             current_class_ptr = this_parm;
+           }
 
-           /* Create substitution entries for the parameters.  */
-           register_parameter_specializations (tdecl, fn);
+         /* If this function is represented by a TEMPLATE_DECL, then
+            the deferred noexcept-specification might still contain
+            dependent types, even after substitution.  And we need the
+            dependency check functions to work in build_noexcept_spec.  */
+         if (orig_fn)
+           ++processing_template_decl;
 
-           /* Do deferred instantiation of the noexcept-specifier.  */
-           noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
-                                         DEFERRED_NOEXCEPT_ARGS (noex),
-                                         tf_warning_or_error, fn,
-                                         /*function_p=*/false,
-                                         /*i_c_e_p=*/true);
-           current_class_ptr = save_ccp;
-           current_class_ref = save_ccr;
-           spec = build_noexcept_spec (noex, tf_warning_or_error);
-         }
+         /* Do deferred instantiation of the noexcept-specifier.  */
+         noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
+                                       DEFERRED_NOEXCEPT_ARGS (noex),
+                                       tf_warning_or_error, fn,
+                                       /*function_p=*/false,
+                                       /*i_c_e_p=*/true);
+
+         current_class_ptr = save_ccp;
+         current_class_ref = save_ccr;
+
+         /* Build up the noexcept-specification.  */
+         spec = build_noexcept_spec (noex, tf_warning_or_error);
+
+         if (orig_fn)
+           --processing_template_decl;
 
          pop_deferring_access_checks ();
          pop_access_scope (fn);
@@ -24279,6 +24294,8 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
        }
 
       TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+      if (orig_fn)
+       TREE_TYPE (orig_fn) = TREE_TYPE (fn);
     }
 
   FOR_EACH_CLONE (clone, fn)
index cf9ed5cda8f46d840acfaf52b2a1a59dc7d26455..9a496ec58f4a8abd906c99ded74ef2f575c7c425 100644 (file)
@@ -1,3 +1,10 @@
+2019-03-28  Marek Polacek  <polacek@redhat.com>
+
+       PR c++/89612 - ICE with member friend template with noexcept.
+       * g++.dg/cpp0x/noexcept38.C: New test.
+       * g++.dg/cpp0x/noexcept39.C: New test.
+       * g++.dg/cpp1z/noexcept-type21.C: New test.
+
 2019-03-28  Uroš Bizjak  <ubizjak@gmail.com>
 
        PR target/89848
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept38.C b/gcc/testsuite/g++.dg/cpp0x/noexcept38.C
new file mode 100644 (file)
index 0000000..ecab59d
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/89612
+// { dg-do compile { target c++11 } }
+
+template <typename> 
+struct C {
+  template <int N>
+  friend int foo() noexcept(N);
+
+  template <int N>
+  friend int foo2() noexcept(N); // { dg-error "different exception" }
+};
+
+template <int N>
+int foo() noexcept(N);
+
+template <int N>
+int foo2() noexcept(N + 1);
+
+C<int> c;
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept39.C b/gcc/testsuite/g++.dg/cpp0x/noexcept39.C
new file mode 100644 (file)
index 0000000..fbebbed
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/89612
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+struct C {
+  template <int N>
+  friend void foo(T t) noexcept(sizeof(decltype(t)) > 1);
+
+  template <int N>
+  friend void foo2(T t) noexcept(sizeof(decltype(t)) < 1); // { dg-error "different exception" }
+};
+
+template <int N>
+void foo(int i) noexcept { }
+
+template <int N>
+void foo2(int i) noexcept { }
+
+C<int> c;
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C
new file mode 100644 (file)
index 0000000..d0a61d9
--- /dev/null
@@ -0,0 +1,16 @@
+// PR c++/89612
+// { dg-do compile { target c++17 } }
+
+template <typename a> using b = typename a ::c;
+template <typename> bool d;
+template <typename, typename> struct e {
+  template <typename f, typename g> e(f, g) {}
+  template <typename h, typename i, typename j>
+  friend auto k(h &&, const j &, i &&) noexcept(d<b<h>, h> &&d<b<i>, i>);
+};
+template <typename l, typename m> e(l, m)->e<l, m>;
+template <typename l, typename m, typename j>
+auto k(l &&, const j &, m &&) noexcept(d<b<l>, l> &&d<b<m>, m>);
+int main() {
+  e(0, [] {});
+}