@@ -2939,7 +2939,48 @@ static void emitDelayedArguments(SILGenFunction &SGF,
2939
2939
}
2940
2940
}
2941
2941
2942
- static Expr *findStorageReferenceExprForBorrow (Expr *e) {
2942
+ namespace {
2943
+ // / Container to hold the result of a search for the storage reference
2944
+ // / when determining to emit a borrow.
2945
+ struct StorageRefResult {
2946
+ private:
2947
+ Expr *storageRef;
2948
+ Expr *transitiveRoot;
2949
+
2950
+ public:
2951
+ // Represents an empty result
2952
+ StorageRefResult () : storageRef(nullptr ), transitiveRoot(nullptr ) {}
2953
+ bool isEmpty () const { return transitiveRoot == nullptr ; }
2954
+ operator bool () const { return !isEmpty (); }
2955
+
2956
+ // / The root of the expression that accesses the storage in \c storageRef.
2957
+ // / When in doubt, this is probably what you want, as it includes the
2958
+ // / entire expression tree involving the reference.
2959
+ Expr *getTransitiveRoot () const { return transitiveRoot; }
2960
+
2961
+ // / The direct storage reference that was discovered.
2962
+ Expr *getStorageRef () const { return storageRef; }
2963
+
2964
+ StorageRefResult (Expr *storageRef, Expr *transitiveRoot)
2965
+ : storageRef(storageRef), transitiveRoot(transitiveRoot) {
2966
+ assert (storageRef && transitiveRoot && " use the zero-arg init for empty" );
2967
+ }
2968
+
2969
+ // Initializes a storage reference where the base matches the ref.
2970
+ StorageRefResult (Expr *storageRef)
2971
+ : StorageRefResult(storageRef, storageRef) {}
2972
+
2973
+ StorageRefResult withTransitiveRoot (StorageRefResult refResult) const {
2974
+ return withTransitiveRoot (refResult.transitiveRoot );
2975
+ }
2976
+
2977
+ StorageRefResult withTransitiveRoot (Expr *newRoot) const {
2978
+ return StorageRefResult (storageRef, newRoot);
2979
+ }
2980
+ };
2981
+ } // namespace
2982
+
2983
+ static StorageRefResult findStorageReferenceExprForBorrow (Expr *e) {
2943
2984
e = e->getSemanticsProvidingExpr ();
2944
2985
2945
2986
// These are basically defined as the cases implemented by SILGenLValue.
@@ -2962,71 +3003,100 @@ static Expr *findStorageReferenceExprForBorrow(Expr *e) {
2962
3003
// sub-expression is a storage reference, but don't return the
2963
3004
// sub-expression.
2964
3005
} else if (auto tue = dyn_cast<TupleElementExpr>(e)) {
2965
- if (findStorageReferenceExprForBorrow (tue->getBase ()))
2966
- return tue;
3006
+ if (auto result = findStorageReferenceExprForBorrow (tue->getBase ()))
3007
+ return result.withTransitiveRoot (tue);
3008
+
2967
3009
} else if (auto fve = dyn_cast<ForceValueExpr>(e)) {
2968
- if (findStorageReferenceExprForBorrow (fve->getSubExpr ()))
2969
- return fve;
3010
+ if (auto result = findStorageReferenceExprForBorrow (fve->getSubExpr ()))
3011
+ return result.withTransitiveRoot (fve);
3012
+
2970
3013
} else if (auto boe = dyn_cast<BindOptionalExpr>(e)) {
2971
- if (findStorageReferenceExprForBorrow (boe->getSubExpr ()))
2972
- return boe;
3014
+ if (auto result = findStorageReferenceExprForBorrow (boe->getSubExpr ()))
3015
+ return result.withTransitiveRoot (boe);
3016
+
2973
3017
} else if (auto oe = dyn_cast<OpenExistentialExpr>(e)) {
2974
- if (findStorageReferenceExprForBorrow (oe->getExistentialValue ()) &&
2975
- findStorageReferenceExprForBorrow (oe->getSubExpr ()))
2976
- return oe;
3018
+ if (findStorageReferenceExprForBorrow (oe->getExistentialValue ()))
3019
+ if (auto result = findStorageReferenceExprForBorrow (oe->getSubExpr ()))
3020
+ return result.withTransitiveRoot (oe);
3021
+
2977
3022
} else if (auto bie = dyn_cast<DotSyntaxBaseIgnoredExpr>(e)) {
2978
- if (findStorageReferenceExprForBorrow (bie->getRHS ()))
2979
- return bie;
3023
+ if (auto result = findStorageReferenceExprForBorrow (bie->getRHS ()))
3024
+ return result.withTransitiveRoot (bie);
3025
+
2980
3026
} else if (auto te = dyn_cast<AnyTryExpr>(e)) {
2981
- if (findStorageReferenceExprForBorrow (te->getSubExpr ()))
2982
- return te;
3027
+ if (auto result = findStorageReferenceExprForBorrow (te->getSubExpr ()))
3028
+ return result.withTransitiveRoot (te);
3029
+
2983
3030
} else if (auto ioe = dyn_cast<InOutExpr>(e)) {
2984
3031
return ioe;
2985
3032
}
2986
3033
2987
- return nullptr ;
3034
+ return StorageRefResult () ;
2988
3035
}
2989
3036
2990
- Expr *ArgumentSource::findStorageReferenceExprForMoveOnlyBorrow (
2991
- SILGenFunction &SGF) && {
3037
+ Expr *ArgumentSource::findStorageReferenceExprForMoveOnly (
3038
+ SILGenFunction &SGF, StorageReferenceOperationKind kind ) && {
2992
3039
if (!isExpr ())
2993
3040
return nullptr ;
2994
3041
2995
3042
auto argExpr = asKnownExpr ();
2996
- auto *li = dyn_cast<LoadExpr>(argExpr);
2997
- if (!li)
3043
+
3044
+ // If there's a load around the outer part of this arg expr, look past it.
3045
+ bool sawLoad = false ;
3046
+ if (auto *li = dyn_cast<LoadExpr>(argExpr)) {
3047
+ argExpr = li->getSubExpr ();
3048
+ sawLoad = true ;
3049
+ }
3050
+
3051
+ // If we're consuming instead, then the load _must_ have been there.
3052
+ if (kind == StorageReferenceOperationKind::Consume && !sawLoad)
2998
3053
return nullptr ;
2999
3054
3000
- auto *lvExpr = ::findStorageReferenceExprForBorrow (li-> getSubExpr () );
3055
+ auto result = ::findStorageReferenceExprForBorrow (argExpr );
3001
3056
3002
- // Claim the value of this argument if we found a storage reference that has a
3003
- // move only base.
3004
- if (lvExpr) {
3005
- // We want to perform a borrow if our initial type is a pure move only /or/
3006
- // if after looking through multiple copyable member ref expr, we get to a
3007
- // move only member ref expr or a move only decl ref expr.
3008
- //
3009
- // NOTE: We purposely do not look through load implying that if we have
3010
- // copyable types extracted from a move only class, we will not borrow.
3011
- auto *iterExpr = lvExpr;
3012
- while (true ) {
3013
- SILType ty = SGF.getLoweredType (
3014
- iterExpr->getType ()->getWithoutSpecifierType ()->getCanonicalType ());
3015
- if (ty.isPureMoveOnly ())
3016
- break ;
3057
+ if (!result)
3058
+ return nullptr ;
3017
3059
3018
- if (auto *mre = dyn_cast<MemberRefExpr>(iterExpr)) {
3019
- iterExpr = mre->getBase ();
3020
- continue ;
3021
- }
3060
+ // We want to perform a borrow/consume if the first piece of storage being
3061
+ // referenced is a move-only type.
3062
+
3063
+ VarDecl *storage = nullptr ;
3064
+ Type type;
3065
+ if (auto dre = dyn_cast<DeclRefExpr>(result.getStorageRef ())) {
3066
+ storage = dyn_cast<VarDecl>(dre->getDecl ());
3067
+ type = dre->getType ();
3068
+ } else if (auto mre = dyn_cast<MemberRefExpr>(result.getStorageRef ())) {
3069
+ storage = dyn_cast<VarDecl>(mre->getDecl ().getDecl ());
3070
+ type = mre->getType ();
3071
+ }
3022
3072
3073
+ if (!storage)
3023
3074
return nullptr ;
3024
- }
3075
+ assert (type);
3025
3076
3026
- (void )std::move (*this ).asKnownExpr ();
3027
- }
3077
+ SILType ty =
3078
+ SGF.getLoweredType (type->getWithoutSpecifierType ()->getCanonicalType ());
3079
+ if (!ty.isPureMoveOnly ())
3080
+ return nullptr ;
3028
3081
3029
- return lvExpr;
3082
+ // It makes sense to borrow any kind of storage we refer to at this stage,
3083
+ // but SILGenLValue does not currently handle some kinds of references well.
3084
+ //
3085
+ // When rejecting to do the LValue-style borrow here, it'll end up going thru
3086
+ // the RValue-style emission, after which the extra copy will get eliminated.
3087
+ //
3088
+ // If we did not see a LoadExpr around the argument expression, then only
3089
+ // do the borrow if the storage is non-local.
3090
+ // FIXME: I don't have a principled reason for why this matters and hope that
3091
+ // we can fix the AST we're working with.
3092
+ if (!sawLoad && storage->getDeclContext ()->isLocalContext ())
3093
+ return nullptr ;
3094
+
3095
+ // Claim the value of this argument since we found a storage reference that
3096
+ // has a move only base.
3097
+ (void )std::move (*this ).asKnownExpr ();
3098
+
3099
+ return result.getTransitiveRoot ();
3030
3100
}
3031
3101
3032
3102
Expr *
@@ -3054,7 +3124,8 @@ ArgumentSource::findStorageReferenceExprForBorrowExpr(SILGenFunction &SGF) && {
3054
3124
if (!borrowExpr)
3055
3125
return nullptr ;
3056
3126
3057
- auto *lvExpr = ::findStorageReferenceExprForBorrow (borrowExpr->getSubExpr ());
3127
+ Expr *lvExpr = ::findStorageReferenceExprForBorrow (borrowExpr->getSubExpr ())
3128
+ .getTransitiveRoot ();
3058
3129
3059
3130
// Claim the value of this argument.
3060
3131
if (lvExpr) {
@@ -3068,7 +3139,8 @@ Expr *ArgumentSource::findStorageReferenceExprForBorrow() && {
3068
3139
if (!isExpr ()) return nullptr ;
3069
3140
3070
3141
auto argExpr = asKnownExpr ();
3071
- auto lvExpr = ::findStorageReferenceExprForBorrow (argExpr);
3142
+ auto *lvExpr =
3143
+ ::findStorageReferenceExprForBorrow (argExpr).getTransitiveRoot();
3072
3144
3073
3145
// Claim the value of this argument if we found a storage reference.
3074
3146
if (lvExpr) {
@@ -3318,8 +3390,8 @@ class ArgEmitter {
3318
3390
}
3319
3391
3320
3392
if (IsYield) {
3321
- if (auto lvExpr = findStorageReferenceExprForBorrow (e)) {
3322
- emitExpandedBorrowed (lvExpr , origParamType);
3393
+ if (auto result = findStorageReferenceExprForBorrow (e)) {
3394
+ emitExpandedBorrowed (result. getTransitiveRoot () , origParamType);
3323
3395
return ;
3324
3396
}
3325
3397
}
@@ -3431,7 +3503,8 @@ class ArgEmitter {
3431
3503
assert (paramsSlice.size () == 1 );
3432
3504
3433
3505
// Try to find an expression we can emit as a borrowed l-value.
3434
- auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnlyBorrow (SGF);
3506
+ auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnly (
3507
+ SGF, ArgumentSource::StorageReferenceOperationKind::Borrow);
3435
3508
if (!lvExpr)
3436
3509
return false ;
3437
3510
@@ -3503,8 +3576,9 @@ class ArgEmitter {
3503
3576
ClaimedParamsRef paramsSlice) {
3504
3577
assert (paramsSlice.size () == 1 );
3505
3578
3506
- // Try to find an expression we can emit as a borrowed l-value.
3507
- auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnlyBorrow (SGF);
3579
+ // Try to find an expression we can emit as a consumed l-value.
3580
+ auto lvExpr = std::move (arg).findStorageReferenceExprForMoveOnly (
3581
+ SGF, ArgumentSource::StorageReferenceOperationKind::Consume);
3508
3582
if (!lvExpr)
3509
3583
return false ;
3510
3584
0 commit comments