Here we ICE when substituting a deferred noexcept-specifier, because it
contains 'this', a PARM_DECL, in an evaluated context.  This is different
from "noexcept(noexcept(this))" where the noexcept operator's operand is
an unevaluated operand.  We crash within tsubst_copy's PARM_DECL handling
of a 'this' PARM_DECL:
15488           gcc_assert (cp_unevaluated_operand != 0)
It'd be wrong to mess with cp_unevaluated_operand (or current_class_*), and
since we only check the expression's constness after substituting in
maybe_instantiate_noexcept, one fix would be the following.

This is not just about 'this', as the 87844 test shows: here we also have
a parameter whose value we're trying to determine -- it's a template arg
of a late-specified return type.  Returning the original value in tsubst_copy
and leaving the later code to complain seems to work here as well.  Just
removing the assert should work as well.

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

2019-02-20  Marek Polacek  <pola...@redhat.com>

        PR c++/88294 - ICE with non-constant noexcept-specifier.
        PR c++/87844 - ICE with non-constant template argument.
        * pt.c (tsubst_copy): Turn gcc_assert into a condition.

        * g++.dg/cpp0x/noexcept34.C: New test.
        * g++.dg/cpp1y/auto-fn56.C: New test.

diff --git gcc/cp/pt.c gcc/cp/pt.c
index 8c5a1b312fc..5286b7dac59 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -15484,8 +15484,12 @@ tsubst_copy (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
          /* This can happen for a parameter name used later in a function
             declaration (such as in a late-specified return type).  Just
-            make a dummy decl, since it's only used for its type.  */
-         gcc_assert (cp_unevaluated_operand != 0);
+            make a dummy decl, since it's only used for its type.
+            We may also end up here in invalid code trying to get a value
+            of a parameter when parsing a deferred noexcept.  Just return
+            the original value so that we can issue an error later.  */
+         if (cp_unevaluated_operand == 0)
+           return t;
          r = tsubst_decl (t, args, complain);
          /* Give it the template pattern as its context; its true context
             hasn't been instantiated yet and this is good enough for
diff --git gcc/testsuite/g++.dg/cpp0x/noexcept34.C 
gcc/testsuite/g++.dg/cpp0x/noexcept34.C
new file mode 100644
index 00000000000..495cc260d9b
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/noexcept34.C
@@ -0,0 +1,29 @@
+// PR c++/88294
+// { dg-do compile { target c++11 } }
+
+constexpr int foo (bool b) { return b; }
+
+template<typename> struct A
+{
+  constexpr int f () { return 0; }
+  bool b = true;
+  void g () noexcept (f()) { } // { dg-error ".this. is not a constant 
expression" }
+  void g2 () noexcept (this->f()) { } // { dg-error ".this. is not a constant 
expression" }
+  void g3 () noexcept (b) { } // { dg-error ".this. is not a constant 
expression|use of .this." }
+  void g4 (int i) noexcept (i) { } // { dg-error "use of parameter outside 
function body" }
+  void g5 () noexcept (A::f()) { } // { dg-error ".this. is not a constant 
expression" }
+  void g6 () noexcept (foo(b)) { } // { dg-error ".this. is not a constant 
expression|use of .this. in a constant expression" }
+  void g7 () noexcept (int{f()}) { } // { dg-error ".this. is not a constant 
expression" }
+};
+
+int main ()
+{
+  A<int> a;
+  a.g ();
+  a.g2 ();
+  a.g3 ();
+  a.g4 (1);
+  a.g5 ();
+  a.g6 ();
+  a.g7 ();
+}
diff --git gcc/testsuite/g++.dg/cpp1y/auto-fn56.C 
gcc/testsuite/g++.dg/cpp1y/auto-fn56.C
new file mode 100644
index 00000000000..ecf8a0b776e
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1y/auto-fn56.C
@@ -0,0 +1,18 @@
+// PR c++/87844
+// { dg-do compile { target c++14 } }
+
+struct C {
+  static constexpr bool call(bool) { return true; }
+};
+
+template<bool b>
+struct B {};
+
+auto foo(bool b) {
+  auto f = [](auto c) -> B<decltype(c)::call(b)> { }; // { dg-error "use of 
parameter from containing function" }
+  f(C()); // { dg-error "no match for call" }
+}
+
+int main() {
+  foo(true);
+}

Reply via email to