@@ -561,45 +561,28 @@ bool ConverterRefCount::RecordDerivesClone(const clang::RecordDecl *decl) {
561561 });
562562}
563563
564- void ConverterRefCount::AddCloneTrait (const clang::RecordDecl *decl) {
565- auto record_name = GetRecordName (decl);
566-
564+ bool ConverterRefCount::RecordDerivesDeepClone (const clang::RecordDecl *decl) {
567565 if (decl->isUnion ()) {
568- StrCat (" impl Clone for" , record_name);
569- PushBrace impl_brace (*this );
570- StrCat (" fn clone(&self) -> Self" );
571- PushBrace fn_brace (*this );
572- StrCat (record_name,
573- " { __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())) }" );
574- return ;
566+ return true ;
575567 }
576-
577568 if (RecordDerivesClone (decl) || !RecordImplementsClone (decl)) {
578- return ;
569+ return false ;
579570 }
580571 // Without a user-defined copy constructor, each field is copied with its
581572 // own clone(), and Values are copied deeply.
582573 auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
583- if (!cxx ||
584- (!GetUserDefinedCopyConstructor (cxx) && cxx->getNumBases () == 0 )) {
585- StrCat (keyword::kImpl , " Clone for" , record_name);
586- PushBrace impl_brace (*this );
587- StrCat (" fn clone(&self) -> Self" );
588- PushBrace fn_brace (*this );
589- StrCat (" Self" );
590- PushBrace init_brace (*this );
591- for (auto *field : decl->fields ()) {
592- auto name = GetNamedDeclAsString (field);
593- auto value = std::format (" self.{}.clone()" , name);
594- if (IsValueField (ctx_, field)) {
595- value = std::format (
596- " Rc::new(RefCell::new((*self.{}.borrow()).clone()))" , name);
597- }
598- StrCat (std::format (" {}: {}," , name, value));
599- }
574+ return !cxx ||
575+ (!GetUserDefinedCopyConstructor (cxx) && cxx->getNumBases () == 0 );
576+ }
577+
578+ void ConverterRefCount::AddCloneTrait (const clang::RecordDecl *decl) {
579+ if (RecordDerivesClone (decl) || RecordDerivesDeepClone (decl) ||
580+ !RecordImplementsClone (decl)) {
600581 return ;
601582 }
602583
584+ auto record_name = GetRecordName (decl);
585+ auto *cxx = clang::cast<clang::CXXRecordDecl>(decl);
603586 StrCat (keyword::kImpl , " Clone for" , record_name, ' {' );
604587 StrCat (" fn clone(&self) -> Self {" );
605588
@@ -648,10 +631,10 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) {
648631 std::vector<std::string>(attrs.begin (), attrs.end ()));
649632
650633 auto size = ctx_.getTypeSizeInChars (ctx_.getCanonicalTagType (decl));
651- StrCat (std::format (" #[derive(ByteRepr)] #[byte_size({0})] pub struct {1} {{ "
652- " #[offset(0 )] #[byte_size({0})] __bytes: Value<Box<[u8]>> "
653- " }}" ,
654- size.getQuantity (), name));
634+ StrCat (std::format (
635+ " #[derive(ByteRepr, DeepClone )] #[byte_size({0})] pub struct {1} {{ "
636+ " #[offset(0)] #[byte_size({0})] __bytes: Value<Box<[u8]>> }}" ,
637+ size.getQuantity (), name));
655638
656639 StrCat (" impl" , name);
657640 {
@@ -1833,12 +1816,16 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
18331816 return false ;
18341817 }
18351818
1819+ // A pointer to a Value field is made without copying the Value out.
1820+ bool value_field_ptr = isAddrOf () && !known &&
1821+ clang::isa<clang::FieldDecl>(member) &&
1822+ !member->getType ()->isReferenceType ();
18361823 std::string str;
18371824 if (known) {
18381825 str = GetMappedAsString (expr);
18391826 } else if (clang::isa<clang::FieldDecl>(member)) {
18401827 // The Value or the pointer that the field holds.
1841- str = ReadField (expr);
1828+ str = ReadField (expr, value_field_ptr ? " .as_pointer() " : " .clone() " );
18421829 } else {
18431830 Buffer buf (*this );
18441831 PushExprKind push (*this , ExprKind::RValue);
@@ -1851,7 +1838,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
18511838 if (member->getType ()->isReferenceType ()) {
18521839 computed_expr_type_ = ComputedExprType::Pointer;
18531840 } else {
1854- StrCat (" .as_pointer()" );
1841+ StrCat (value_field_ptr ? " " : " .as_pointer()" );
18551842 computed_expr_type_ = ComputedExprType::FreshPointer;
18561843 }
18571844 return false ;
@@ -1924,7 +1911,8 @@ std::string ConverterRefCount::ConvertRecordPtr(clang::MemberExpr *expr) {
19241911 return std::move (buf).str ();
19251912}
19261913
1927- std::string ConverterRefCount::ReadField (clang::MemberExpr *expr) {
1914+ std::string ConverterRefCount::ReadField (clang::MemberExpr *expr,
1915+ std::string_view copy) {
19281916 // Unless the struct is reached through a pointer, in which case the field
19291917 // is read in a closure, the borrow of the struct ends at the end of the
19301918 // block.
@@ -1939,7 +1927,7 @@ std::string ConverterRefCount::ReadField(clang::MemberExpr *expr) {
19391927 str = std::move (buf).str ();
19401928 }
19411929 if (!TypeIsCopyable (expr->getMemberDecl ()->getType ())) {
1942- str += " .clone() " ;
1930+ str += copy ;
19431931 }
19441932 return ptr.empty () ? std::format (" {{ {} }}" , str)
19451933 : std::format (" {}.with(|__s| {})" , ptr, str);
@@ -2298,6 +2286,8 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
22982286
22992287 if (RecordDerivesClone (decl)) {
23002288 attrs.emplace_back (" Clone" );
2289+ } else if (RecordDerivesDeepClone (decl)) {
2290+ attrs.emplace_back (" DeepClone" );
23012291 }
23022292
23032293 // Gives access to the fields through pointers to them.
@@ -2426,7 +2416,10 @@ void ConverterRefCount::ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
24262416
24272417 PushBrace brace (*this , isRValue ());
24282418
2429- if (MayCauseBorrowMutError (lhs, rhs)) {
2419+ // C++ evaluates the assigned value first, which may modify what the place
2420+ // is computed from, like a pointer it is reached through.
2421+ if (MayCauseBorrowMutError (lhs, rhs) ||
2422+ (rhs->HasSideEffects (ctx_) && ReadsMemory (lhs))) {
24302423 if (CanBraceAssignedValue (lhs, rhs, assign_operator)) {
24312424 rhs_as_string = std::format (" {{ {} }}" , rhs_as_string);
24322425 } else {
@@ -2589,7 +2582,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
25892582 if (isLValue ()) {
25902583 PushConversionKind push_ck (*this , ConversionKind::Unboxed);
25912584 pending_deref_.set (
2592- std::format (" ( {} as {}).offset( {})" ,
2585+ std::format (" elem!(( {} as {}), {})" ,
25932586 ConvertObject (expr->getArg (0 ), ObjectShape::Element),
25942587 ConvertPtrType (expr->getArg (0 )->getType ()),
25952588 ConvertSubscriptIndex (expr->getArg (1 ))),
@@ -2609,10 +2602,12 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
26092602 }
26102603
26112604 PushConversionKind push (*this , ConversionKind::Unboxed);
2612- StrCat (std::format (" ({} as {}).offset({})" ,
2613- ConvertObject (expr->getArg (0 ), ObjectShape::Element),
2614- ConvertPtrType (expr->getArg (0 )->getType ()),
2615- ConvertSubscriptIndex (expr->getArg (1 ))));
2605+ auto ptr = std::format (
2606+ " ({} as {})" , ConvertObject (expr->getArg (0 ), ObjectShape::Element),
2607+ ConvertPtrType (expr->getArg (0 )->getType ()));
2608+ auto idx = ConvertSubscriptIndex (expr->getArg (1 ));
2609+ StrCat (deref && !is_inner_boxed ? std::format (" elem!({}, {})" , ptr, idx)
2610+ : std::format (" {}.offset({})" , ptr, idx));
26162611
26172612 if (is_inner_boxed) {
26182613 StrCat (GetPointerDerefSuffix (expr->getType ()), " .as_pointer()" );
@@ -2739,6 +2734,12 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
27392734 }
27402735}
27412736
2737+ void ConverterRefCount::ConvertPointerElem (clang::Expr *base,
2738+ clang::Expr *idx) {
2739+ StrCat (std::format (" elem!({}, {})" , ToString (base), ConvertRValue (idx)));
2740+ computed_expr_type_ = ComputedExprType::FreshPointer;
2741+ }
2742+
27422743void ConverterRefCount::ConvertPointerSubscript (
27432744 clang::ArraySubscriptExpr *expr) {
27442745 auto *base = expr->getBase ();
@@ -2747,7 +2748,7 @@ void ConverterRefCount::ConvertPointerSubscript(
27472748 if (isLValue ()) {
27482749 pending_deref_.assert_consumed ();
27492750 Buffer buf (*this );
2750- ConvertPointerOffset (base, idx);
2751+ ConvertPointerElem (base, idx);
27512752 pending_deref_.set_unchecked (std::move (buf).str (), isFresh (), expr);
27522753 return ;
27532754 }
@@ -2756,8 +2757,10 @@ void ConverterRefCount::ConvertPointerSubscript(
27562757 PushParen paren (*this , deref);
27572758 if (deref) {
27582759 StrCat (GetPointerDerefPrefix (expr->getType ()));
2760+ ConvertPointerElem (base, idx);
2761+ } else {
2762+ ConvertPointerOffset (base, idx);
27592763 }
2760- ConvertPointerOffset (base, idx);
27612764 if (deref) {
27622765 StrCat (GetPointerDerefSuffix (expr->getType ()));
27632766 SetValueFreshness (expr->getType ());
0 commit comments