diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 00ef3ca26f..0c8f29670f 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -692,7 +692,10 @@ bool HasCallableCopyConstructor(const clang::RecordDecl *decl) { ctor->getDefinition(); }); } - if (cxx->defaultedCopyConstructorIsDeleted()) { + if (cxx->defaultedCopyConstructorIsDeleted() || + std::ranges::any_of(cxx->ctors(), [](const auto *ctor) { + return ctor->isCopyConstructor() && ctor->isDeleted(); + })) { return false; } auto &ctx = cxx->getASTContext(); @@ -1636,27 +1639,48 @@ void DefineImplicitMembers(clang::Sema &sema, clang::CXXRecordDecl *decl) { tu_scope.setEntity(sema.Context.getTranslationUnitDecl()); auto *saved_tu_scope = std::exchange(sema.TUScope, &tu_scope); sema.ForceDeclarationOfImplicitMembers(decl); + auto define = [&](clang::FunctionDecl *fn, auto &&definer) { + RuleDecls::Trial trial(sema); + clang::DiagnosticErrorTrap errors(sema.getDiagnostics()); + { + clang::Sema::GlobalEagerInstantiationScope instantiations( + sema, /*Enabled=*/true, /*AtEndOfTU=*/false); + definer(); + instantiations.perform(); + } + if (trial.failed() || errors.hasErrorOccurred()) { + fn->setDeletedAsWritten(true); + } + }; for (auto ctor : decl->ctors()) { if (ctor->isCopyConstructor() && ctor->isImplicit() && !ctor->doesThisDeclarationHaveABody() && !ctor->isDeleted()) { - sema.DefineImplicitCopyConstructor(decl->getLocation(), ctor); + define(ctor, [&] { + sema.DefineImplicitCopyConstructor(decl->getLocation(), ctor); + }); } if (ctor->isMoveConstructor() && !ctor->isUserProvided() && !ctor->doesThisDeclarationHaveABody() && !ctor->isDeleted() && !HasDefaultedCopyConstructor(decl)) { - sema.DefineImplicitMoveConstructor(decl->getLocation(), ctor); + define(ctor, [&] { + sema.DefineImplicitMoveConstructor(decl->getLocation(), ctor); + }); } } for (auto *method : decl->methods()) { if (method->isMoveAssignmentOperator() && !method->isUserProvided() && !method->doesThisDeclarationHaveABody() && !method->isDeleted() && !HasDefaultedCopyAssignment(decl)) { - sema.DefineImplicitMoveAssignment(decl->getLocation(), method); + define(method, [&] { + sema.DefineImplicitMoveAssignment(decl->getLocation(), method); + }); } if (method->isCopyAssignmentOperator() && !method->isUserProvided() && !method->doesThisDeclarationHaveABody() && !method->isDeleted() && NeedsDefaultedCopyAssignment(decl)) { - sema.DefineImplicitCopyAssignment(decl->getLocation(), method); + define(method, [&] { + sema.DefineImplicitCopyAssignment(decl->getLocation(), method); + }); } } auto define_defaulted_comparison = [&](clang::FunctionDecl *fn) { @@ -1669,7 +1693,9 @@ void DefineImplicitMembers(clang::Sema &sema, clang::CXXRecordDecl *decl) { #else auto kind = sema.getDefaultedComparisonKind(fn); #endif - sema.DefineDefaultedComparison(decl->getLocation(), fn, kind); + define(fn, [&] { + sema.DefineDefaultedComparison(decl->getLocation(), fn, kind); + }); }; for (auto *method : decl->methods()) { define_defaulted_comparison(method); diff --git a/tests/unit/copy_move_deleted.cpp b/tests/unit/copy_move_deleted.cpp index 4f7eabed10..ee53272108 100644 --- a/tests/unit/copy_move_deleted.cpp +++ b/tests/unit/copy_move_deleted.cpp @@ -1,5 +1,6 @@ #include #include +#include struct NoCopy { int v; @@ -43,6 +44,10 @@ struct Container { int tag; }; +struct VecHolder { + std::vector items; +}; + static void bump(NoCopy *p) { p->v++; } static void bump_ref(Immovable &r) { r.v++; } @@ -71,5 +76,9 @@ int main() { Container c{NoCopy(6), 7}; Container d(std::move(c)); assert(d.inner.v == 6 && d.tag == 7 && c.inner.v == 0); + + VecHolder h; + VecHolder h2(std::move(h)); + assert(h2.items.size() == 0); return 0; } diff --git a/tests/unit/out/refcount/copy_move_deleted.rs b/tests/unit/out/refcount/copy_move_deleted.rs index 10d02ffcfc..7ba64f1518 100644 --- a/tests/unit/out/refcount/copy_move_deleted.rs +++ b/tests/unit/out/refcount/copy_move_deleted.rs @@ -80,6 +80,20 @@ impl Container { } } } +#[derive(Record, ByteRepr, FnPtrArg, MoveCtor, Default)] +#[byte_size(24)] +pub struct VecHolder { + #[offset(0)] + #[byte_size(24)] + pub items: Vec, +} +impl VecHolder { + pub fn move_from(_a0: Ptr) -> Self { + Self { + items: field!(_a0, items).with_mut(std::mem::take), + } + } +} pub fn bump_0(mut p: Ptr) { field!(p, v).with_mut(|__v| __v.postfix_inc()); } @@ -115,6 +129,9 @@ fn main_0() -> i32 { })); let mut d: Container = Container::move_from({ c.as_pointer() }); assert!(((d.inner.v == 6) && (d.tag == 7)) && ({ (*c.borrow()).inner.v } == 0)); + let h: Value = Rc::new(RefCell::new(::default())); + let mut h2: VecHolder = VecHolder::move_from({ h.as_pointer() }); + assert!((h2.items.len() == 0_usize)); return 0; } pub trait ContainerImpl { diff --git a/tests/unit/out/unsafe/copy_move_deleted.rs b/tests/unit/out/unsafe/copy_move_deleted.rs index 8387b63705..1be051764a 100644 --- a/tests/unit/out/unsafe/copy_move_deleted.rs +++ b/tests/unit/out/unsafe/copy_move_deleted.rs @@ -92,6 +92,19 @@ impl Container { return &mut (*(self as *mut Container)); } } +#[repr(C)] +#[derive(FnPtrArg, MoveCtorUnsafe, Default)] +pub struct VecHolder { + pub items: Vec, +} +impl VecHolder { + pub unsafe fn move_from(_a0: *mut VecHolder) -> Self { + let mut this = Self { + items: std::mem::take(&mut (*_a0).items), + }; + this + } +} pub unsafe fn bump_0(mut p: *mut NoCopy) { (*p).v.postfix_inc(); } @@ -129,6 +142,9 @@ unsafe fn main_0() -> i32 { }; let mut d: Container = Container::move_from({ &mut c }); assert!((((d.inner.v) == (6)) && ((d.tag) == (7))) && ((c.inner.v) == (0))); + let mut h: VecHolder = ::default(); + let mut h2: VecHolder = VecHolder::move_from({ &mut h }); + assert!(((h2.items.len()) == (0_usize))); return 0; } pub unsafe fn __cpp2rust_init_globals() {}