Message ID | 20190220203109.GA20014@redhat.com |
---|---|
State | New |
Headers | show |
Series | C++ PATCH for c++/88294 - ICE with non-constant noexcept-specifier | expand |
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
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 (); +}
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
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
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
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; +}
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
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); +}