Here a stale value of TYPE_DEPENDENT_P/_P_VALID for f's function type after replacing its DEFERRED_NOEXCEPT with its parsed (dependent) noexcept-spec leads us to try to instantiate g's noexcept-spec (which incorrectly appears non-dependent) ahead of time, causing an ICE.
This patch fixes this by clearing TYPE_DEPENDENT_P_VALID in fixup_deferred_exception_variants appropriately, as is already done in build_cp_fntype_variant. This is sufficient for C++17, but not for earlier dialects, because it's not until C++17 that the noexcept-spec influences dependence of a function type, so even after this fix we still deem g's noexcept-spec to be non-dependent and incorrectly try to instantiate it ahead of time. Since dependence of NOEXCEPT_EXPR is defined in terms of instantiation dependence, the most appropriate fix for earlier dialects seems to be to consider dependence of a noexcept-spec for instantiation dependence. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps branches? 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): Consider dependence of a noexcept-specifier * tree.cc (fixup_deferred_exception_variants): Clear TYPE_DEPENDENT_P_VALID. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/noexcept74.C: New test. --- gcc/cp/pt.cc | 39 ++++++++++++++++++------ gcc/cp/tree.cc | 4 +++ gcc/testsuite/g++.dg/cpp0x/noexcept74.C | 11 +++++++ gcc/testsuite/g++.dg/cpp0x/noexcept74a.C | 12 ++++++++ 4 files changed, 57 insertions(+), 9 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 feee629f1dd..a7dc0bc5f86 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -26979,6 +26979,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.*/ @@ -27033,15 +27051,7 @@ dependent_type_p_r (tree type) return true; if (cxx_dialect >= cxx17) /* 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 value_dependent_noexcept_spec_p (type); return false; } /* -- an array type constructed from any dependent type or whose @@ -27850,6 +27860,17 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, return *tp; break; + case TEMPLATE_DECL: + case FUNCTION_DECL: + /* Before C++17, the noexcept-specifier wasn'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 056f10f13b4..2d8f2c551c0 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 00000000000..e43d21c201e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept74.C @@ -0,0 +1,11 @@ +// PR c++/104079 +// { dg-do compile { target c++11 } } + +template<bool b> +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 00000000000..8eb534c5506 --- /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<bool b> +struct AT { + template<class...> static void f() noexcept(b); + + void g() noexcept(noexcept(f())) { + static_assert(noexcept(f()), ""); + } +}; -- 2.35.0