https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114867
Nathaniel Shead <nshead at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 CC| |nshead at gcc dot gnu.org Status|UNCONFIRMED |NEW Last reconfirmed| |2024-05-25 --- Comment #2 from Nathaniel Shead <nshead at gcc dot gnu.org> --- Confirmed. The issue is that this part of 'do_nonmember_using_decl' for the 'using std::swap' declaration in the module purview removes the template candidate and reinserts it to "reveal" it (possibly as newly exported): if (new_fn == old_fn) { /* The function already exists in the current namespace. We will still want to insert it if it is revealing a not-revealed thing. */ found = true; if (!revealing_p) ; else if (old.using_p ()) { if (exporting) /* Update in place. 'tis ok. */ OVL_EXPORT_P (old.get_using ()) = true; ; } else if (DECL_MODULE_EXPORT_P (new_fn)) ; else { value = old.remove_node (value); found = false; } break; } // ... if (!found && insert_p) /* Unlike the decl-pushing case we don't drop anticipated builtins here. They don't cause a problem, and we'd like to match them with a future declaration. */ value = ovl_insert (new_fn, value, 1 + exporting); However, within the 'shared_ptr::swap' template it's already holding a pointer to the OVERLOAD, and the 'remove_node' call drops it from this existing overload set but the 'ovl_insert' doesn't add it back to that set, rather returning a new one. I suppose a fix is possibly to ensure that we only do this update in-place but I don't know if that'll work with OVL_HIDDEN declarations, since they need to always be kept at the front of the list, and reordering might still cause the same issues.