@@ -581,16 +581,26 @@ bool ConverterRefCount::RecordImplementsClone(const clang::RecordDecl *decl) {
581581 HasCallableCopyConstructor (decl);
582582}
583583
584+ // Bases are translated to traits, so they hold no state of the struct; they
585+ // only need to be copied without side effects.
586+ static bool HasDefaultedBaseCopies (const clang::CXXRecordDecl *decl) {
587+ return std::ranges::all_of (decl->bases (), [](auto &base) {
588+ auto *record = base.getType ()->getAsCXXRecordDecl ();
589+ return record && HasDefaultedCopyConstructor (record) &&
590+ HasDefaultedBaseCopies (record);
591+ });
592+ }
593+
584594bool ConverterRefCount::RecordDerivesClone (const clang::RecordDecl *decl) {
585595 if (HasDefaultedCopyConstructor (decl) && RecordHasOnlyReferenceFields (decl)) {
586596 return true ;
587597 }
588598 // The copy of a struct copies each field, which a derived Clone does too,
589599 // except for Values, which it shares.
590600 auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
591- if (decl->isUnion () ||
592- (cxx && (! HasCallableCopyConstructor (cxx) ||
593- GetUserDefinedCopyConstructor (cxx) || cxx-> getNumBases () > 0 ))) {
601+ if (decl->isUnion () || (cxx && (! HasCallableCopyConstructor (cxx) ||
602+ GetUserDefinedCopyConstructor (cxx) ||
603+ ! HasDefaultedBaseCopies (cxx) ))) {
594604 return false ;
595605 }
596606 PushConversionKind push (*this , ConversionKind::Pointee);
@@ -611,7 +621,7 @@ bool ConverterRefCount::RecordDerivesDeepClone(const clang::RecordDecl *decl) {
611621 // own clone(), and Values are copied deeply.
612622 auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
613623 return !cxx ||
614- (!GetUserDefinedCopyConstructor (cxx) && cxx-> getNumBases () == 0 );
624+ (!GetUserDefinedCopyConstructor (cxx) && HasDefaultedBaseCopies (cxx) );
615625}
616626
617627void ConverterRefCount::AddCloneTrait (const clang::RecordDecl *decl) {
@@ -3146,6 +3156,7 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
31463156 bool in_ctor =
31473157 curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
31483158 if (in_ctor) {
3159+ ctor_uses_this_ = true ;
31493160 ufcs_receiver_ = " &this" ;
31503161 } else if (ThisIsRustPtr ()) {
31513162 ufcs_receiver_ = keyword::kSelfValue ;
@@ -3307,21 +3318,43 @@ void ConverterRefCount::ConvertCXXConstructorBody(
33073318 clang::CXXConstructorDecl *decl) {
33083319 EmitFunctionPreamble (decl);
33093320 auto record_name = GetRecordName (decl->getParent ());
3321+ auto saved_uses_this = std::exchange (ctor_uses_this_, false );
3322+ std::string init;
3323+ {
3324+ Buffer buf (*this );
3325+ if (decl->isDelegatingConstructor ()) {
3326+ Convert ((*decl->init_begin ())->getInit ());
3327+ } else {
3328+ StrCat (" Self" );
3329+ PushBrace this_init (*this );
3330+ EmitConstructorFieldInits (decl);
3331+ }
3332+ init = std::move (buf).str ();
3333+ }
3334+ std::string body;
3335+ {
3336+ Buffer buf (*this );
3337+ ConvertBodyStmts (decl->getBody ());
3338+ body = std::move (buf).str ();
3339+ }
3340+ bool uses_this = std::exchange (ctor_uses_this_, saved_uses_this);
3341+
3342+ if (!uses_this) {
3343+ if (Trim (body).empty ()) {
3344+ StrCat (init);
3345+ } else {
3346+ StrCat (keyword::kLet , " __this" , token::kColon , record_name,
3347+ token::kAssign , init, token::kSemiColon , body, " __this" );
3348+ }
3349+ return ;
3350+ }
33103351 StrCat (keyword::kLet , " __this" , token::kColon ,
33113352 std::format (" Value<{}>" , record_name), token::kAssign ,
3312- " Rc::new(RefCell::new(" );
3313- if (decl->isDelegatingConstructor ()) {
3314- Convert ((*decl->init_begin ())->getInit ());
3315- } else {
3316- StrCat (" Self" );
3317- PushBrace this_init (*this );
3318- EmitConstructorFieldInits (decl);
3319- }
3320- StrCat (" ))" , token::kSemiColon );
3353+ std::format (" Rc::new(RefCell::new({}))" , init), token::kSemiColon );
33213354 StrCat (keyword::kLet , " this" , token::kColon ,
33223355 std::format (" Ptr<{}>" , record_name), token::kAssign ,
33233356 " __this.as_pointer()" , token::kSemiColon );
3324- ConvertBodyStmts (decl-> getBody () );
3357+ StrCat (body );
33253358 StrCat (" Rc::try_unwrap(__this).ok().unwrap().into_inner()" );
33263359}
33273360
@@ -3338,6 +3371,7 @@ bool ConverterRefCount::VisitCXXThisExpr(
33383371 bool in_ctor =
33393372 curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
33403373 if (in_ctor) {
3374+ ctor_uses_this_ = true ;
33413375 StrCat (" this" );
33423376 } else {
33433377 StrCat (" (*" , keyword::kSelfValue , ' )' );
0 commit comments