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.
This commit is contained in:
Patrick Palka 2022-02-03 18:54:23 -05:00
parent 3ef328c293
commit 82e31c8973
4 changed files with 59 additions and 10 deletions

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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()), "");
}
};

View File

@ -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()), "");
}
};