* C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
@ 2019-02-20 20:38 Marek Polacek
2019-02-20 23:59 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Marek Polacek @ 2019-02-20 20:38 UTC (permalink / raw)
To: GCC Patches, Jason Merrill
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 <polacek@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);
+}
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-20 20:38 C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier Marek Polacek
@ 2019-02-20 23:59 ` Jason Merrill
2019-02-21 21:09 ` Marek Polacek
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2019-02-20 23:59 UTC (permalink / raw)
To: Marek Polacek, GCC Patches
On 2/20/19 10:31 AM, Marek Polacek wrote:
> 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.
I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
I think we want to register_parameter_specializations when instantiating
deferred noexcept, so that tsubst_copy can find the right decls.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-20 23:59 ` Jason Merrill
@ 2019-02-21 21:09 ` Marek Polacek
2019-02-21 21:43 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Marek Polacek @ 2019-02-21 21:09 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches
On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
> On 2/20/19 10:31 AM, Marek Polacek wrote:
> > 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.
>
> I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
Makes sense -- I wasn't aware of that.
> I think we want to register_parameter_specializations when instantiating
> deferred noexcept, so that tsubst_copy can find the right decls.
Thanks for the suggestion -- that works with one catch: we need to replace the
fake 'this' in the noexcept- specifier with a real 'this' (the template one),
one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
Before calling register_parameter_specializations one apparently has to set up
a local specializations stack.
Does this look reasonable? It no longer fixes the other PR; we'll likely have
to play some register_local_specialization games there, too.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2019-02-21 Marek Polacek <polacek@redhat.com>
PR c++/88294 - ICE with non-constant noexcept-specifier.
* pt.c (replace_this_r): New function.
(maybe_instantiate_noexcept): Set up the list of local
specializations. Replace the fake 'this' with the real one.
* g++.dg/cpp0x/noexcept34.C: New test.
diff --git gcc/cp/pt.c gcc/cp/pt.c
index a212be8c747..abbec8f53b9 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -24158,6 +24158,20 @@ always_instantiate_p (tree decl)
&& decl_maybe_constant_var_p (decl)));
}
+/* Replace all fake 'this' parameters (i.e. the ones created by
+ inject_this_parameter) with the real 'this'. */
+
+static tree
+replace_this_r (tree *t, int *, void *data_)
+{
+ tree *d = static_cast<tree *>(data_);
+ if (TREE_CODE (*t) == PARM_DECL
+ && DECL_NAME (*t) == this_identifier
+ && DECL_CONTEXT (*t) == NULL_TREE)
+ *t = *d;
+ return NULL_TREE;
+}
+
/* If FN has a noexcept-specifier that hasn't been instantiated yet,
instantiate it now, modifying TREE_TYPE (fn). Returns false on
error, true otherwise. */
@@ -24203,12 +24217,34 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
push_access_scope (fn);
push_deferring_access_checks (dk_no_deferred);
input_location = DECL_SOURCE_LOCATION (fn);
- noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
- DEFERRED_NOEXCEPT_ARGS (noex),
- tf_warning_or_error, fn,
- /*function_p=*/false,
- /*integral_constant_expression_p=*/true);
- spec = build_noexcept_spec (noex, tf_warning_or_error);
+
+ /* A new stack interferes with pop_access_scope. */
+ {
+ /* Set up the list of local specializations. */
+ local_specialization_stack lss (lss_copy);
+
+ /* Replace the fake 'this' with the real 'this'. */
+ tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
+ {
+ tree real_this = DECL_ARGUMENTS (tdecl);
+ tree *p = &DEFERRED_NOEXCEPT_PATTERN (noex);
+ cp_walk_tree_without_duplicates (p, replace_this_r,
+ &real_this);
+ }
+
+ /* Create substitution entries for the parameters. */
+ register_parameter_specializations (tdecl, fn);
+
+ /* 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);
+ spec = build_noexcept_spec (noex, tf_warning_or_error);
+ }
+
pop_deferring_access_checks ();
pop_access_scope (fn);
pop_tinst_level ();
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 ();
+}
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-21 21:09 ` Marek Polacek
@ 2019-02-21 21:43 ` Jason Merrill
2019-02-22 0:09 ` Marek Polacek
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2019-02-21 21:43 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
On 2/21/19 10:56 AM, Marek Polacek wrote:
> On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
>> On 2/20/19 10:31 AM, Marek Polacek wrote:
>>> 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.
>>
>> I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
>
> Makes sense -- I wasn't aware of that.
>
>> I think we want to register_parameter_specializations when instantiating
>> deferred noexcept, so that tsubst_copy can find the right decls.
>
> Thanks for the suggestion -- that works with one catch: we need to replace the
> fake 'this' in the noexcept- specifier with a real 'this' (the template one),
> one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
> when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
If you set current_class_ptr appropriately tsubst_copy will use it, so
you shouldn't need to do a walk_tree.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-21 21:43 ` Jason Merrill
@ 2019-02-22 0:09 ` Marek Polacek
2019-02-22 1:15 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Marek Polacek @ 2019-02-22 0:09 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches
On Thu, Feb 21, 2019 at 11:22:41AM -1000, Jason Merrill wrote:
> On 2/21/19 10:56 AM, Marek Polacek wrote:
> > On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
> > > On 2/20/19 10:31 AM, Marek Polacek wrote:
> > > > 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.
> > >
> > > I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
> >
> > Makes sense -- I wasn't aware of that.
> >
> > > I think we want to register_parameter_specializations when instantiating
> > > deferred noexcept, so that tsubst_copy can find the right decls.
> >
> > Thanks for the suggestion -- that works with one catch: we need to replace the
> > fake 'this' in the noexcept- specifier with a real 'this' (the template one),
> > one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
> > when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
>
> If you set current_class_ptr appropriately tsubst_copy will use it, so you
> shouldn't need to do a walk_tree.
Unfortunately that broke a lot of libstdc++ tests. I can poke at it more if
you feel stronly about it.
Marek
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-22 0:09 ` Marek Polacek
@ 2019-02-22 1:15 ` Jason Merrill
2019-02-23 0:21 ` Marek Polacek
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2019-02-22 1:15 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
On 2/21/19 1:34 PM, Marek Polacek wrote:
> On Thu, Feb 21, 2019 at 11:22:41AM -1000, Jason Merrill wrote:
>> On 2/21/19 10:56 AM, Marek Polacek wrote:
>>> On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
>>>> On 2/20/19 10:31 AM, Marek Polacek wrote:
>>>>> 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.
>>>>
>>>> I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
>>>
>>> Makes sense -- I wasn't aware of that.
>>>
>>>> I think we want to register_parameter_specializations when instantiating
>>>> deferred noexcept, so that tsubst_copy can find the right decls.
>>>
>>> Thanks for the suggestion -- that works with one catch: we need to replace the
>>> fake 'this' in the noexcept- specifier with a real 'this' (the template one),
>>> one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
>>> when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
>>
>> If you set current_class_ptr appropriately tsubst_copy will use it, so you
>> shouldn't need to do a walk_tree.
>
> Unfortunately that broke a lot of libstdc++ tests. I can poke at it more if
> you feel stronly about it.
Please do poke a bit more, that surprises me.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-22 1:15 ` Jason Merrill
@ 2019-02-23 0:21 ` Marek Polacek
2019-02-23 9:05 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Marek Polacek @ 2019-02-23 0:21 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches
On Thu, Feb 21, 2019 at 02:57:28PM -1000, Jason Merrill wrote:
> On 2/21/19 1:34 PM, Marek Polacek wrote:
> > On Thu, Feb 21, 2019 at 11:22:41AM -1000, Jason Merrill wrote:
> > > On 2/21/19 10:56 AM, Marek Polacek wrote:
> > > > On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
> > > > > On 2/20/19 10:31 AM, Marek Polacek wrote:
> > > > > > 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.
> > > > >
> > > > > I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
> > > >
> > > > Makes sense -- I wasn't aware of that.
> > > >
> > > > > I think we want to register_parameter_specializations when instantiating
> > > > > deferred noexcept, so that tsubst_copy can find the right decls.
> > > >
> > > > Thanks for the suggestion -- that works with one catch: we need to replace the
> > > > fake 'this' in the noexcept- specifier with a real 'this' (the template one),
> > > > one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
> > > > when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
> > >
> > > If you set current_class_ptr appropriately tsubst_copy will use it, so you
> > > shouldn't need to do a walk_tree.
> >
> > Unfortunately that broke a lot of libstdc++ tests. I can poke at it more if
> > you feel stronly about it.
>
> Please do poke a bit more, that surprises me.
Apparently *someone* needs to learn how to properly restore c_c_{ptr,ref}...
noexcept35.C is a new test reduced from something from libstdc++. Since it
exercises codepaths that nothing in dg.exp does, I think it's worth adding.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2019-02-22 Marek Polacek <polacek@redhat.com>
PR c++/88294 - ICE with non-constant noexcept-specifier.
* pt.c (maybe_instantiate_noexcept): Set up the list of local
specializations. Set current_class_{ptr,ref}.
* g++.dg/cpp0x/noexcept34.C: New test.
* g++.dg/cpp0x/noexcept35.C: New test.
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 42dd095a6b0..d678e278078 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -24203,12 +24203,39 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
push_access_scope (fn);
push_deferring_access_checks (dk_no_deferred);
input_location = DECL_SOURCE_LOCATION (fn);
- noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
- DEFERRED_NOEXCEPT_ARGS (noex),
- tf_warning_or_error, fn,
- /*function_p=*/false,
- /*integral_constant_expression_p=*/true);
- spec = build_noexcept_spec (noex, tf_warning_or_error);
+
+ /* 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;
+ }
+
+ /* Create substitution entries for the parameters. */
+ register_parameter_specializations (tdecl, fn);
+
+ /* 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);
+ }
+
pop_deferring_access_checks ();
pop_access_scope (fn);
pop_tinst_level ();
diff --git gcc/testsuite/g++.dg/cpp0x/noexcept34.C gcc/testsuite/g++.dg/cpp0x/noexcept34.C
new file mode 100644
index 00000000000..dce35652ef5
--- /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 "use of parameter" }
+ void g2 () noexcept (this->f()) { } // { dg-error "use of parameter" }
+ void g3 () noexcept (b) { } // { dg-error "use of .this. in a constant expression|use of parameter" }
+ void g4 (int i) noexcept (i) { } // { dg-error "use of parameter" }
+ void g5 () noexcept (A::f()) { } // { dg-error "use of parameter" }
+ void g6 () noexcept (foo(b)) { } // { dg-error "use of .this. in a constant expression|use of parameter" }
+ void g7 () noexcept (int{f()}) { } // { dg-error "use of parameter" }
+};
+
+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/cpp0x/noexcept35.C gcc/testsuite/g++.dg/cpp0x/noexcept35.C
new file mode 100644
index 00000000000..8606b1ad28c
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/noexcept35.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+
+template <typename _Tp, _Tp __v> struct A { static constexpr _Tp value = __v; };
+typedef A<bool, false> false_type;
+struct is_same : false_type {};
+template <bool> struct enable_if;
+template <typename> using __remove_cvref_t = int;
+template <typename _Tp> class reference_wrapper {
+ static _Tp _S_fun();
+ template <typename _Up, typename = __remove_cvref_t<_Up>>
+ using __not_same = enable_if<is_same::value>;
+
+public:
+ template <typename _Up, typename = __not_same<_Up>>
+ reference_wrapper(_Up) noexcept(noexcept(reference_wrapper::_S_fun));
+};
+
+reference_wrapper<int> fn1() {
+ int __t = 10;
+ return __t;
+}
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier
2019-02-23 0:21 ` Marek Polacek
@ 2019-02-23 9:05 ` Jason Merrill
0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2019-02-23 9:05 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
On Fri, Feb 22, 2019 at 1:17 PM Marek Polacek <polacek@redhat.com> wrote:
> On Thu, Feb 21, 2019 at 02:57:28PM -1000, Jason Merrill wrote:
> > On 2/21/19 1:34 PM, Marek Polacek wrote:
> > > On Thu, Feb 21, 2019 at 11:22:41AM -1000, Jason Merrill wrote:
> > > > On 2/21/19 10:56 AM, Marek Polacek wrote:
> > > > > On Wed, Feb 20, 2019 at 01:53:18PM -1000, Jason Merrill wrote:
> > > > > > On 2/20/19 10:31 AM, Marek Polacek wrote:
> > > > > > > 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.
> > > > > >
> > > > > > I'm reluctant to mess with this assert, as it catches a lot of lambda bugs.
> > > > >
> > > > > Makes sense -- I wasn't aware of that.
> > > > >
> > > > > > I think we want to register_parameter_specializations when instantiating
> > > > > > deferred noexcept, so that tsubst_copy can find the right decls.
> > > > >
> > > > > Thanks for the suggestion -- that works with one catch: we need to replace the
> > > > > fake 'this' in the noexcept- specifier with a real 'this' (the template one),
> > > > > one that has DECL_CONTEXT set. The fake one comes from inject_this_parameter,
> > > > > when we were parsing the noexcept-specifier. The real one was set in grokfndecl.
> > > >
> > > > If you set current_class_ptr appropriately tsubst_copy will use it, so you
> > > > shouldn't need to do a walk_tree.
> > >
> > > Unfortunately that broke a lot of libstdc++ tests. I can poke at it more if
> > > you feel stronly about it.
> >
> > Please do poke a bit more, that surprises me.
>
> Apparently *someone* needs to learn how to properly restore c_c_{ptr,ref}...
>
> noexcept35.C is a new test reduced from something from libstdc++. Since it
> exercises codepaths that nothing in dg.exp does, I think it's worth adding.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2019-02-22 Marek Polacek <polacek@redhat.com>
>
> PR c++/88294 - ICE with non-constant noexcept-specifier.
> * pt.c (maybe_instantiate_noexcept): Set up the list of local
> specializations. Set current_class_{ptr,ref}.
OK, thanks.
Jason
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-02-23 7:17 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-20 20:38 C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier Marek Polacek
2019-02-20 23:59 ` Jason Merrill
2019-02-21 21:09 ` Marek Polacek
2019-02-21 21:43 ` Jason Merrill
2019-02-22 0:09 ` Marek Polacek
2019-02-22 1:15 ` Jason Merrill
2019-02-23 0:21 ` Marek Polacek
2019-02-23 9:05 ` Jason Merrill
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).