@@ -1822,12 +1822,16 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
18221822 return false ;
18231823 }
18241824
1825+ // A pointer to a Value field is made without copying the Value out.
1826+ bool value_field_ptr = isAddrOf () && !known &&
1827+ clang::isa<clang::FieldDecl>(member) &&
1828+ !member->getType ()->isReferenceType ();
18251829 std::string str;
18261830 if (known) {
18271831 str = GetMappedAsString (expr);
18281832 } else if (clang::isa<clang::FieldDecl>(member)) {
18291833 // The Value or the pointer that the field holds.
1830- str = ReadField (expr);
1834+ str = ReadField (expr, value_field_ptr ? " .as_pointer() " : " .clone() " );
18311835 } else {
18321836 Buffer buf (*this );
18331837 PushExprKind push (*this , ExprKind::RValue);
@@ -1840,7 +1844,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
18401844 if (member->getType ()->isReferenceType ()) {
18411845 computed_expr_type_ = ComputedExprType::Pointer;
18421846 } else {
1843- StrCat (" .as_pointer()" );
1847+ StrCat (value_field_ptr ? " " : " .as_pointer()" );
18441848 computed_expr_type_ = ComputedExprType::FreshPointer;
18451849 }
18461850 return false ;
@@ -1913,7 +1917,8 @@ std::string ConverterRefCount::ConvertRecordPtr(clang::MemberExpr *expr) {
19131917 return std::move (buf).str ();
19141918}
19151919
1916- std::string ConverterRefCount::ReadField (clang::MemberExpr *expr) {
1920+ std::string ConverterRefCount::ReadField (clang::MemberExpr *expr,
1921+ std::string_view copy) {
19171922 // Unless the struct is reached through a pointer, in which case the field
19181923 // is read in a closure, the borrow of the struct ends at the end of the
19191924 // block.
@@ -1928,7 +1933,7 @@ std::string ConverterRefCount::ReadField(clang::MemberExpr *expr) {
19281933 str = std::move (buf).str ();
19291934 }
19301935 if (!TypeIsCopyable (expr->getMemberDecl ()->getType ())) {
1931- str += " .clone() " ;
1936+ str += copy ;
19321937 }
19331938 return ptr.empty () ? std::format (" {{ {} }}" , str)
19341939 : std::format (" {}.with(|__s| {})" , ptr, str);
@@ -2444,7 +2449,10 @@ void ConverterRefCount::ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
24442449
24452450 PushBrace brace (*this , isRValue ());
24462451
2447- if (MayCauseBorrowMutError (lhs, rhs)) {
2452+ // C++ evaluates the assigned value first, which may modify what the place
2453+ // is computed from, like a pointer it is reached through.
2454+ if (MayCauseBorrowMutError (lhs, rhs) ||
2455+ (rhs->HasSideEffects (ctx_) && ReadsMemory (lhs))) {
24482456 if (CanBraceAssignedValue (lhs, rhs, assign_operator)) {
24492457 rhs_as_string = std::format (" {{ {} }}" , rhs_as_string);
24502458 } else {
@@ -2607,7 +2615,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
26072615 if (isLValue ()) {
26082616 PushConversionKind push_ck (*this , ConversionKind::Unboxed);
26092617 pending_deref_.set (
2610- std::format (" ( {} as {}).offset( {})" ,
2618+ std::format (" elem!(( {} as {}), {})" ,
26112619 ConvertObject (expr->getArg (0 ), ObjectShape::Element),
26122620 ConvertPtrType (expr->getArg (0 )->getType ()),
26132621 ConvertSubscriptIndex (expr->getArg (1 ))),
@@ -2627,10 +2635,14 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
26272635 }
26282636
26292637 PushConversionKind push (*this , ConversionKind::Unboxed);
2630- StrCat (std::format (" ({} as {}).offset({})" ,
2631- ConvertObject (expr->getArg (0 ), ObjectShape::Element),
2632- ConvertPtrType (expr->getArg (0 )->getType ()),
2633- ConvertSubscriptIndex (expr->getArg (1 ))));
2638+ auto ptr =
2639+ std::format (" ({} as {})" ,
2640+ ConvertObject (expr->getArg (0 ), ObjectShape::Element),
2641+ ConvertPtrType (expr->getArg (0 )->getType ()));
2642+ auto idx = ConvertSubscriptIndex (expr->getArg (1 ));
2643+ StrCat (deref && !is_inner_boxed
2644+ ? std::format (" elem!({}, {})" , ptr, idx)
2645+ : std::format (" {}.offset({})" , ptr, idx));
26342646
26352647 if (is_inner_boxed) {
26362648 StrCat (GetPointerDerefSuffix (expr->getType ()), " .as_pointer()" );
@@ -2757,6 +2769,12 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
27572769 }
27582770}
27592771
2772+ void ConverterRefCount::ConvertPointerElem (clang::Expr *base,
2773+ clang::Expr *idx) {
2774+ StrCat (std::format (" elem!({}, {})" , ToString (base), ConvertRValue (idx)));
2775+ computed_expr_type_ = ComputedExprType::FreshPointer;
2776+ }
2777+
27602778void ConverterRefCount::ConvertPointerSubscript (
27612779 clang::ArraySubscriptExpr *expr) {
27622780 auto *base = expr->getBase ();
@@ -2765,7 +2783,7 @@ void ConverterRefCount::ConvertPointerSubscript(
27652783 if (isLValue ()) {
27662784 pending_deref_.assert_consumed ();
27672785 Buffer buf (*this );
2768- ConvertPointerOffset (base, idx);
2786+ ConvertPointerElem (base, idx);
27692787 pending_deref_.set_unchecked (std::move (buf).str (), isFresh (), expr);
27702788 return ;
27712789 }
@@ -2774,8 +2792,10 @@ void ConverterRefCount::ConvertPointerSubscript(
27742792 PushParen paren (*this , deref);
27752793 if (deref) {
27762794 StrCat (GetPointerDerefPrefix (expr->getType ()));
2795+ ConvertPointerElem (base, idx);
2796+ } else {
2797+ ConvertPointerOffset (base, idx);
27772798 }
2778- ConvertPointerOffset (base, idx);
27792799 if (deref) {
27802800 StrCat (GetPointerDerefSuffix (expr->getType ()));
27812801 SetValueFreshness (expr->getType ());
0 commit comments