On 3/28/19 2:59 PM, Marek Polacek wrote:
On Thu, Mar 21, 2019 at 04:00:41PM -0400, Jason Merrill wrote:
On 3/19/19 11:45 AM, Marek Polacek wrote:
On Thu, Mar 14, 2019 at 04:22:41PM -0400, Jason Merrill wrote:
On 3/7/19 4:52 PM, Marek Polacek wrote:
This was one of those PRs where the more you poke, the more ICEs turn up.
This patch fixes the ones I could find.  The original problem was that
maybe_instantiate_noexcept got a TEMPLATE_DECL created for the member
friend template in do_friend.  Its noexcept-specification was deferred,
so we went to the block with push_access_scope, but that crashes on a
TEMPLATE_DECL.  One approach could be to somehow not defer noexcept-specs
for friend templates, I guess, but I didn't want to do that.

How does it make sense to instantiate the noexcept-specifier of a template?
We should only get there for fully-instantiated function decls.

Hmm, but duplicate_decls calls check_redeclaration_exception_specification even
for DECL_FUNCTION_TEMPLATE_Ps.
...
Note the crash happens in tsubst_friend_function.  I wouldn't know when to
check the noexcept-specifier of such a TEMPLATE_DECL for a template friend
if not there.

Hmm, true, I guess we do need to do a partial instantiation of the
noexcept-specifier in order to compare it.

*nod*

That broke in register_parameter_specializations but we don't need this
code anyway, so let's do away with it -- the current_class_{ref,ptr}
code is enough to fix the PR that register_parameter_specializations was
introduced for.

What about uses of non-'this' parameters in the noexcept-specification?

template <typename T>
struct C {
   template <int N>
   friend void foo(T t) noexcept(sizeof(decltype(t)) > 1);
};

template <int N>
void foo(int i) noexcept { }

C<int> c;

Still works.  I extended the test to see if we detect the scenario when the
noexcept-specifiers don't match, and we do.  It's noexcept39.C.

Lastly, I found an invalid testcase that was breaking because a template code
leaked to constexpr functions.  This I fixed similarly to the recent explicit
PR fix (r269131).

This spot should probably also use build_converted_constant_expr.

Ok, I'll address this.

I'm finding this repeated pattern awkward.  Earlier you changed
check_narrowing to use maybe_constant_value instead of
fold_non_dependent_expr, but perhaps whatever that fixed should have been
fixed instead with a processing_template_decl_sentinel in the enclosing code
that already instantiated the expression.  That ought to avoid any need to
change this spot or r269131.

So this also came up in the other patch.  Why don't I drop this part (and the
noexcept1.C test) and open a new PR for this issue, so that we don't conflate
two problems?  The following patch fixes the original issue.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

OK.

Jason


2019-03-28  Marek Polacek  <pola...@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.

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

diff --git gcc/cp/pt.c gcc/cp/pt.c
index 05d5371d8a6..fa30a7f00c8 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -24192,6 +24192,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);
@@ -24228,37 +24239,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);
@@ -24278,6 +24293,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)
diff --git gcc/testsuite/g++.dg/cpp0x/noexcept38.C 
gcc/testsuite/g++.dg/cpp0x/noexcept38.C
new file mode 100644
index 00000000000..ecab59df694
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/noexcept38.C
@@ -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 gcc/testsuite/g++.dg/cpp0x/noexcept39.C 
gcc/testsuite/g++.dg/cpp0x/noexcept39.C
new file mode 100644
index 00000000000..fbebbed5e4c
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/noexcept39.C
@@ -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 gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C 
gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C
new file mode 100644
index 00000000000..d0a61d95e87
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1z/noexcept-type21.C
@@ -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, [] {});
+}


Reply via email to