@@ -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,12 @@ 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 = std::format (
2639+ " ({} as {})" , ConvertObject (expr->getArg (0 ), ObjectShape::Element),
2640+ ConvertPtrType (expr->getArg (0 )->getType ()));
2641+ auto idx = ConvertSubscriptIndex (expr->getArg (1 ));
2642+ StrCat (deref && !is_inner_boxed ? std::format (" elem!({}, {})" , ptr, idx)
2643+ : std::format (" {}.offset({})" , ptr, idx));
26342644
26352645 if (is_inner_boxed) {
26362646 StrCat (GetPointerDerefSuffix (expr->getType ()), " .as_pointer()" );
@@ -2757,6 +2767,12 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
27572767 }
27582768}
27592769
2770+ void ConverterRefCount::ConvertPointerElem (clang::Expr *base,
2771+ clang::Expr *idx) {
2772+ StrCat (std::format (" elem!({}, {})" , ToString (base), ConvertRValue (idx)));
2773+ computed_expr_type_ = ComputedExprType::FreshPointer;
2774+ }
2775+
27602776void ConverterRefCount::ConvertPointerSubscript (
27612777 clang::ArraySubscriptExpr *expr) {
27622778 auto *base = expr->getBase ();
@@ -2765,7 +2781,7 @@ void ConverterRefCount::ConvertPointerSubscript(
27652781 if (isLValue ()) {
27662782 pending_deref_.assert_consumed ();
27672783 Buffer buf (*this );
2768- ConvertPointerOffset (base, idx);
2784+ ConvertPointerElem (base, idx);
27692785 pending_deref_.set_unchecked (std::move (buf).str (), isFresh (), expr);
27702786 return ;
27712787 }
@@ -2774,8 +2790,10 @@ void ConverterRefCount::ConvertPointerSubscript(
27742790 PushParen paren (*this , deref);
27752791 if (deref) {
27762792 StrCat (GetPointerDerefPrefix (expr->getType ()));
2793+ ConvertPointerElem (base, idx);
2794+ } else {
2795+ ConvertPointerOffset (base, idx);
27772796 }
2778- ConvertPointerOffset (base, idx);
27792797 if (deref) {
27802798 StrCat (GetPointerDerefSuffix (expr->getType ()));
27812799 SetValueFreshness (expr->getType ());
0 commit comments