diff options
author | Marek Polacek <polacek@redhat.com> | 2025-02-06 08:57:22 -0500 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2025-02-07 09:04:17 -0500 |
commit | f5ef1f9e8589697086c8cfea6ad07d56050dde96 (patch) | |
tree | 8e0768bd393d85d80eb73dc0839c61869816ad0a /gcc | |
parent | 0b2f34ca19edf2b033c90ff378f561429b82a77a (diff) | |
download | gcc-f5ef1f9e8589697086c8cfea6ad07d56050dde96.zip gcc-f5ef1f9e8589697086c8cfea6ad07d56050dde96.tar.gz gcc-f5ef1f9e8589697086c8cfea6ad07d56050dde96.tar.bz2 |
c++: ICE with unparsed noexcept [PR117106]
In a member-specification of a class, a noexcept-specifier is
a complete-class context. Thus we delay parsing until the end of
the class via our DEFERRED_PARSE mechanism; see cp_parser_save_noexcept
and cp_parser_late_noexcept_specifier.
We also attempt to defer instantiation of noexcept-specifiers in order
to reduce the number of instantiations; this is done via DEFERRED_NOEXCEPT.
We can even have both, as in noexcept65.C: a DEFERRED_PARSE wrapped in
DEFERRED_NOEXCEPT, which uses the DEFPARSE_INSTANTIATIONS mechanism.
noexcept65.C works, because when we really need the noexcept, which is
when parsing the body of S::A::A(), the noexcept will have been parsed
already; noexcepts are parsed before bodies of member function.
But in this test we have:
struct A {
int x;
template<class>
void foo() noexcept(noexcept(x)) {}
auto bar() -> decltype(foo<int>()) {} // #1
};
and I think the decltype in #1 needs the unparsed noexcept before it
could have been parsed. clang++ rejects the test and I suppose we
should reject it as well, rather than crashing on a DEFERRED_PARSE
in tsubst_expr.
PR c++/117106
PR c++/118190
gcc/cp/ChangeLog:
* pt.cc (maybe_instantiate_noexcept): Give an error if the noexcept
hasn't been parsed yet.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/noexcept89.C: New test.
* g++.dg/cpp0x/noexcept90.C: New test.
Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/pt.cc | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept89.C | 9 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/noexcept90.C | 12 |
3 files changed, 32 insertions, 5 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 39232b5..8108bf5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -27453,7 +27453,8 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) { static hash_set<tree>* fns = new hash_set<tree>; bool added = false; - if (DEFERRED_NOEXCEPT_PATTERN (noex) == NULL_TREE) + tree pattern = DEFERRED_NOEXCEPT_PATTERN (noex); + if (pattern == NULL_TREE) { spec = get_defaulted_eh_spec (fn, complain); if (spec == error_mark_node) @@ -27464,13 +27465,19 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) else if (!(added = !fns->add (fn))) { /* If hash_set::add returns true, the element was already there. */ - location_t loc = cp_expr_loc_or_loc (DEFERRED_NOEXCEPT_PATTERN (noex), - DECL_SOURCE_LOCATION (fn)); + location_t loc = cp_expr_loc_or_loc (pattern, + DECL_SOURCE_LOCATION (fn)); error_at (loc, "exception specification of %qD depends on itself", fn); spec = noexcept_false_spec; } + else if (TREE_CODE (pattern) == DEFERRED_PARSE) + { + error ("exception specification of %qD is not available " + "until end of class definition", fn); + spec = noexcept_false_spec; + } else if (push_tinst_level (fn)) { const bool push_to_top = maybe_push_to_top_level (fn); @@ -27497,8 +27504,7 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain) ++processing_template_decl; /* Do deferred instantiation of the noexcept-specifier. */ - noex = tsubst_expr (DEFERRED_NOEXCEPT_PATTERN (noex), - DEFERRED_NOEXCEPT_ARGS (noex), + noex = tsubst_expr (pattern, DEFERRED_NOEXCEPT_ARGS (noex), tf_warning_or_error, fn); /* Build up the noexcept-specification. */ spec = build_noexcept_spec (noex, tf_warning_or_error); diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept89.C b/gcc/testsuite/g++.dg/cpp0x/noexcept89.C new file mode 100644 index 0000000..308abf6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept89.C @@ -0,0 +1,9 @@ +// PR c++/117106 +// { dg-do compile { target c++11 } } + +struct A { + int x; + template<class> + void foo() noexcept(noexcept(x)) {} + auto bar() -> decltype(foo<int>()) {} // { dg-error "not available until end of class" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept90.C b/gcc/testsuite/g++.dg/cpp0x/noexcept90.C new file mode 100644 index 0000000..6d403f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept90.C @@ -0,0 +1,12 @@ +// PR c++/118190 +// { dg-do compile { target c++11 } } + +struct S { + template<typename T> + struct S5 { + void f1() noexcept(noexcept(i)) { } + int i; + }; + S5<int> s5; + static_assert (noexcept(s5.f1()), ""); // { dg-error "not available until end of class|static assertion failed" } +}; |