c++/modules: Propagate bits to DECL_MAYBE_DELETED dups [PR119462]

In the linked PR, we're importing over a DECL_MAYBE_DELETED decl with a
decl that has already been instantiated.  This patch ensures that the
needed bits are propagated across and that DECL_MAYBE_DELETED is cleared
from the existing decl, so that later synthesize_method doesn't crash
due to a definition unexpectedly already existing.

	PR c++/119462

gcc/cp/ChangeLog:

	* module.cc (trees_in::is_matching_decl): Propagate exception
	spec and constexpr to DECL_MAYBE_DELETED; clear if appropriate.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/noexcept-3_a.C: New test.
	* g++.dg/modules/noexcept-3_b.C: New test.
	* g++.dg/modules/noexcept-3_c.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
Nathaniel Shead 2025-04-04 19:08:40 +11:00
parent 6602fc076a
commit f4a3ae1ef5
4 changed files with 52 additions and 1 deletions

View file

@ -12122,7 +12122,7 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
instantiate it in the middle of loading. */
tree e_spec = TYPE_RAISES_EXCEPTIONS (e_type);
tree d_spec = TYPE_RAISES_EXCEPTIONS (d_type);
if (DEFERRED_NOEXCEPT_SPEC_P (e_spec))
if (DECL_MAYBE_DELETED (e_inner) || DEFERRED_NOEXCEPT_SPEC_P (e_spec))
{
if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec)
|| (UNEVALUATED_NOEXCEPT_SPEC_P (e_spec)
@ -12161,6 +12161,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef)
else if (type_uses_auto (d_ret)
&& !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type)))
goto mismatch;
/* Similarly if EXISTING has undeduced constexpr, but DECL's
is already deduced. */
if (DECL_MAYBE_DELETED (e_inner) && !DECL_MAYBE_DELETED (d_inner)
&& DECL_DECLARED_CONSTEXPR_P (d_inner))
DECL_DECLARED_CONSTEXPR_P (e_inner) = true;
else if (DECL_DECLARED_CONSTEXPR_P (e_inner)
!= DECL_DECLARED_CONSTEXPR_P (d_inner))
goto mismatch;
/* Don't synthesize a defaulted function if we're importing one
we've already determined. */
if (!DECL_MAYBE_DELETED (d_inner))
DECL_MAYBE_DELETED (e_inner) = false;
}
else if (is_typedef)
{

View file

@ -0,0 +1,14 @@
// PR c++/119462
// { dg-additional-options "-fmodules -std=c++20 -Wno-global-module" }
// { dg-module-cmi M:part }
module;
struct exception_ptr {
// implicitly noexcept and constexpr
friend bool operator==(const exception_ptr&, const exception_ptr&) = default;
};
export module M:part;
export template <typename = int> void enqueue() {
exception_ptr e;
e == e;
}

View file

@ -0,0 +1,12 @@
// PR c++/119462
// { dg-additional-options "-fmodules -std=c++20 -Wno-global-module" }
// { dg-module-cmi M }
module;
struct exception_ptr {
// implicitly noexcept and constexpr, but this isn't known yet
friend bool operator==(const exception_ptr&, const exception_ptr&) = default;
};
export module M;
export import :part;
export using ::exception_ptr;

View file

@ -0,0 +1,11 @@
// PR c++/119462
// { dg-additional-options "-fmodules -std=c++20" }
import M;
int main() {
enqueue();
constexpr exception_ptr e;
static_assert(e == e);
static_assert(noexcept(e == e));
}