From 82e31c8973eb1a752c2ffd01005efe291d35cee3 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Thu, 3 Feb 2022 18:54:23 -0500 Subject: [PATCH] c++: dependence of member noexcept-spec [PR104079] Here a stale TYPE_DEPENDENT_P/_P_VALID value for f's function type after replacing the type's DEFERRED_NOEXCEPT with the parsed dependent noexcept-spec causes us to try to instantiate g's noexcept-spec ahead of time (since it in turn appears non-dependent), leading to an ICE. This patch fixes this by clearing TYPE_DEPENDENT_P_VALID in fixup_deferred_exception_variants appropriately (as in build_cp_fntype_variant). That turns out to fix the testcase for C++17 but not for C++11/14, because it's not until C++17 that a noexcept-spec is part of (and therefore affects dependence of) the function type. Since dependence of NOEXCEPT_EXPR is defined in terms of instantiation dependence, the most appropriate fix for earlier dialects seems to be to make instantiation dependence consider dependence of a noexcept-spec. PR c++/104079 gcc/cp/ChangeLog: * pt.cc (value_dependent_noexcept_spec_p): New predicate split out from ... (dependent_type_p_r): ... here. (instantiation_dependent_r): Use value_dependent_noexcept_spec_p to consider dependence of a noexcept-spec before C++17. * tree.cc (fixup_deferred_exception_variants): Clear TYPE_DEPENDENT_P_VALID. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept74.C: New test. * g++.dg/cpp0x/noexcept74a.C: New test. --- gcc/cp/pt.cc | 42 ++++++++++++++++++++++++-------- gcc/cp/tree.cc | 4 +++ gcc/testsuite/g++.dg/cpp0x/noexcept74.C | 11 +++++++++ gcc/testsuite/g++.dg/cpp0x/noexcept74a.C | 12 +++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept74.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept74a.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 6e129da..60641d8 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -27003,6 +27003,24 @@ invalid_nontype_parm_type_p (tree type, tsubst_flags_t complain) return true; } +/* Returns true iff the noexcept-specifier for TYPE is value-dependent. */ + +static bool +value_dependent_noexcept_spec_p (tree type) +{ + if (tree spec = TYPE_RAISES_EXCEPTIONS (type)) + if (tree noex = TREE_PURPOSE (spec)) + /* Treat DEFERRED_NOEXCEPT as non-dependent, since it doesn't + affect overload resolution and treating it as dependent breaks + things. Same for an unparsed noexcept expression. */ + if (TREE_CODE (noex) != DEFERRED_NOEXCEPT + && TREE_CODE (noex) != DEFERRED_PARSE + && value_dependent_expression_p (noex)) + return true; + + return false; +} + /* Returns TRUE if TYPE is dependent, in the sense of [temp.dep.type]. Assumes that TYPE really is a type, and not the ERROR_MARK_NODE.*/ @@ -27055,17 +27073,10 @@ dependent_type_p_r (tree type) arg_type = TREE_CHAIN (arg_type)) if (dependent_type_p (TREE_VALUE (arg_type))) return true; - if (cxx_dialect >= cxx17) + if (cxx_dialect >= cxx17 + && value_dependent_noexcept_spec_p (type)) /* A value-dependent noexcept-specifier makes the type dependent. */ - if (tree spec = TYPE_RAISES_EXCEPTIONS (type)) - if (tree noex = TREE_PURPOSE (spec)) - /* Treat DEFERRED_NOEXCEPT as non-dependent, since it doesn't - affect overload resolution and treating it as dependent breaks - things. Same for an unparsed noexcept expression. */ - if (TREE_CODE (noex) != DEFERRED_NOEXCEPT - && TREE_CODE (noex) != DEFERRED_PARSE - && value_dependent_expression_p (noex)) - return true; + return true; return false; } /* -- an array type constructed from any dependent type or whose @@ -27874,6 +27885,17 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, return *tp; break; + case TEMPLATE_DECL: + case FUNCTION_DECL: + /* Before C++17, a noexcept-specifier isn't part of the function type + so it doesn't affect type dependence, but we still want to consider it + for instantiation dependence. */ + if (cxx_dialect < cxx17 + && DECL_DECLARES_FUNCTION_P (*tp) + && value_dependent_noexcept_spec_p (TREE_TYPE (*tp))) + return *tp; + break; + default: break; } diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 056f10f..2d8f2c5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -2839,6 +2839,10 @@ fixup_deferred_exception_variants (tree type, tree raises) } else TYPE_RAISES_EXCEPTIONS (variant) = raises; + + if (!TYPE_DEPENDENT_P (variant)) + /* We no longer know that it's not type-dependent. */ + TYPE_DEPENDENT_P_VALID (variant) = false; } } diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept74.C b/gcc/testsuite/g++.dg/cpp0x/noexcept74.C new file mode 100644 index 0000000..c439c9d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept74.C @@ -0,0 +1,11 @@ +// PR c++/104079 +// { dg-do compile { target c++11 } } + +template +struct AT { + static void f() noexcept(B); + + void g() noexcept(noexcept(f())) { + static_assert(noexcept(f()), ""); + } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept74a.C b/gcc/testsuite/g++.dg/cpp0x/noexcept74a.C new file mode 100644 index 0000000..008654d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept74a.C @@ -0,0 +1,12 @@ +// PR c++/104079 +// { dg-do compile { target c++11 } } +// A variant of noexcept74.C where f is a function template. + +template +struct AT { + template static void f() noexcept(B); + + void g() noexcept(noexcept(f())) { + static_assert(noexcept(f()), ""); + } +}; -- 2.7.4