On 2/3/22 11:49, Patrick Palka wrote:
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?
OK for trunk now, 11 in about a month. Since it was reported against
11, I'm not sure we need to backport further.
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()), "");
+ }
+};