Skip to content

Commit bc405c5

Browse files
authored
Merge pull request #78457 from jckarter/addressable-for-depedencies-2
`@_addressableForDependencies` fixes
2 parents 0ba886d + d9ee3f4 commit bc405c5

File tree

9 files changed

+169
-109
lines changed

9 files changed

+169
-109
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ class TypeLowering {
222222
IsNotTypeExpansionSensitive,
223223
HasRawPointer_t hasRawPointer = DoesNotHaveRawPointer,
224224
IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack,
225-
IsAddressableForDependencies_t isAFD = IsAddressableForDependencies)
225+
IsAddressableForDependencies_t isAFD = IsNotAddressableForDependencies)
226226
: Flags((isTrivial ? 0U : NonTrivialFlag) |
227227
(isFixedABI ? 0U : NonFixedABIFlag) |
228228
(isAddressOnly ? AddressOnlyFlag : 0U) |

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,20 +1779,17 @@ class DestructureInputs {
17791779
ParameterTypeFlags origFlags) {
17801780
assert(!isa<InOutType>(substType));
17811781

1782-
if (TC.Context.LangOpts.hasFeature(Feature::AddressableTypes)
1783-
|| TC.Context.LangOpts.hasFeature(Feature::AddressableParameters)) {
1784-
// If the parameter is marked addressable, lower it with maximal
1785-
// abstraction.
1786-
if (origFlags.isAddressable()) {
1782+
// If the parameter is marked addressable, lower it with maximal
1783+
// abstraction.
1784+
if (origFlags.isAddressable()) {
1785+
origType = AbstractionPattern::getOpaque();
1786+
} else if (hasScopedDependency) {
1787+
// If there is a scoped dependency on this parameter, and the parameter
1788+
// is addressable-for-dependencies, then lower it with maximal abstraction
1789+
// as well.
1790+
auto &initialSubstTL = TC.getTypeLowering(origType, substType, expansion);
1791+
if (initialSubstTL.getRecursiveProperties().isAddressableForDependencies()) {
17871792
origType = AbstractionPattern::getOpaque();
1788-
} else if (hasScopedDependency) {
1789-
// If there is a scoped dependency on this parameter, and the parameter
1790-
// is addressable-for-dependencies, then lower it with maximal abstraction
1791-
// as well.
1792-
auto &initialSubstTL = TC.getTypeLowering(origType, substType, expansion);
1793-
if (initialSubstTL.getRecursiveProperties().isAddressableForDependencies()) {
1794-
origType = AbstractionPattern::getOpaque();
1795-
}
17961793
}
17971794
}
17981795

lib/SIL/IR/TypeLowering.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2510,6 +2510,7 @@ namespace {
25102510
}
25112511

25122512
if (D->isCxxNonTrivial()) {
2513+
properties.setAddressableForDependencies();
25132514
properties.setAddressOnly();
25142515
properties.setNonTrivial();
25152516
properties.setLexical(IsLexical);
@@ -2550,6 +2551,10 @@ namespace {
25502551
properties.setLexical(IsLexical);
25512552
return handleAddressOnly(structType, properties);
25522553
}
2554+
2555+
if (D->getAttrs().hasAttribute<AddressableForDependenciesAttr>()) {
2556+
properties.setAddressableForDependencies();
2557+
}
25532558

25542559
auto subMap = structType->getContextSubstitutionMap();
25552560

@@ -2620,6 +2625,10 @@ namespace {
26202625
if (handleResilience(enumType, D, properties))
26212626
return handleAddressOnly(enumType, properties);
26222627

2628+
if (D->getAttrs().hasAttribute<AddressableForDependenciesAttr>()) {
2629+
properties.setAddressableForDependencies();
2630+
}
2631+
26232632
// [is_or_contains_pack_unsubstituted] Visit the elements of the
26242633
// unsubstituted type to find pack types which would be substituted away.
26252634
for (auto elt : D->getAllElements()) {

lib/SILGen/SILGenLValue.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5015,23 +5015,22 @@ SILValue SILGenFunction::emitSemanticLoad(SILLocation loc,
50155015
}
50165016

50175017
// Harder case: the srcTL and the rvalueTL match without move only.
5018-
if (srcType.removingMoveOnlyWrapper() ==
5019-
rvalueType.removingMoveOnlyWrapper()) {
5018+
if (srcType.removingMoveOnlyWrapper()
5019+
== rvalueType.removingMoveOnlyWrapper()) {
50205020
// Ok, we know that one must be move only and the other must not be. Thus we
50215021
// perform one of two things:
50225022
//
50235023
// 1. If our source address is move only and our rvalue type is not move
5024-
// only, lets perform a load [copy] and a moveonly_to_copyable. We just need
5025-
// to insert something so that the move only checker knows that this copy of
5026-
// the move only address must be a last use.
5024+
// only, let's perform a load [copy] from the unwrapped address.
50275025
//
50285026
// 2. If our dest value type is move only and our rvalue type is not move
50295027
// only, then we perform a load [copy] + copyable_to_moveonly.
5030-
SILValue newCopy = srcTL.emitLoadOfCopy(B, loc, src, isTake);
5031-
if (newCopy->getType().isMoveOnlyWrapped()) {
5032-
return B.createOwnedMoveOnlyWrapperToCopyableValue(loc, newCopy);
5028+
if (src->getType().isMoveOnlyWrapped()) {
5029+
auto copyableSrc = B.createMoveOnlyWrapperToCopyableAddr(loc, src);
5030+
return rvalueTL.emitLoadOfCopy(B, loc, copyableSrc, isTake);
50335031
}
50345032

5033+
SILValue newCopy = srcTL.emitLoadOfCopy(B, loc, src, isTake);
50355034
return B.createOwnedCopyableToMoveOnlyWrapperValue(loc, newCopy);
50365035
}
50375036

lib/SILGen/SILGenProlog.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,7 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
210210
return handleInOut(origType, substType, pd->isAddressable());
211211
}
212212
// Addressability also suppresses exploding the parameter.
213-
if ((SGF.getASTContext().LangOpts.hasFeature(Feature::AddressableTypes)
214-
|| SGF.getASTContext().LangOpts.hasFeature(Feature::AddressableParameters))
215-
&& isAddressable) {
213+
if (isAddressable) {
216214
return handleScalar(claimNextParameter(),
217215
AbstractionPattern::getOpaque(), substType,
218216
/*emitInto*/ nullptr,
@@ -740,15 +738,12 @@ class ArgumentInitHelper {
740738
// addressability can be implied by a scoped dependency.
741739
bool isAddressable = false;
742740

743-
if (SGF.getASTContext().LangOpts.hasFeature(Feature::AddressableTypes)
744-
|| SGF.getASTContext().LangOpts.hasFeature(Feature::AddressableParameters)) {
745-
isAddressable = pd->isAddressable()
746-
|| (ScopedDependencies.contains(pd)
747-
&& SGF.getTypeLowering(origType, substType)
748-
.getRecursiveProperties().isAddressableForDependencies());
749-
if (isAddressable) {
750-
AddressableParams.insert(pd);
751-
}
741+
isAddressable = pd->isAddressable()
742+
|| (ScopedDependencies.contains(pd)
743+
&& SGF.getTypeLowering(origType, substType)
744+
.getRecursiveProperties().isAddressableForDependencies());
745+
if (isAddressable) {
746+
AddressableParams.insert(pd);
752747
}
753748
paramValue = argEmitter.handleParam(origType, substType, pd,
754749
isAddressable);

test/Concurrency/transfernonsendable_ownership.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ func testConsumingError(_ x: consuming Klass) async {
5050
print(x)
5151
}
5252

53-
func testConsumingUseAfterConsumeError(_ x: consuming Klass) async { // expected-error {{'x' consumed more than once}}
53+
func testConsumingUseAfterConsumeError(_ x: consuming Klass) async { // expected-error {{'x' used after consume}}
5454
await consumeTransferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
5555
// expected-note @-1 {{sending task-isolated 'x' to main actor-isolated global function 'consumeTransferToMain' risks causing data races between main actor-isolated and task-isolated uses}}
5656
// expected-note @-2 {{consumed here}}
5757
print(x)
58-
// expected-note @-1 {{consumed again here}}
58+
// expected-note @-1 {{used here}}
5959
}
6060

61-
@CustomActor func testConsumingUseAfterConsumeErrorGlobalActor(_ x: consuming Klass) async { // expected-error {{'x' consumed more than once}}
61+
@CustomActor func testConsumingUseAfterConsumeErrorGlobalActor(_ x: consuming Klass) async { // expected-error {{'x' used after consume}}
6262
await consumeTransferToMain(x) // expected-warning {{sending 'x' risks causing data races}}
6363
// expected-note @-1 {{sending global actor 'CustomActor'-isolated 'x' to main actor-isolated global function 'consumeTransferToMain' risks causing data races between main actor-isolated and global actor 'CustomActor'-isolated uses}}
6464
// expected-note @-2 {{consumed here}}
6565
print(x)
66-
// expected-note @-1 {{consumed again here}}
66+
// expected-note @-1 {{used here}}
6767
}
6868

6969
func testBorrowing(_ x: borrowing Klass) async {

test/SILOptimizer/addressable_dependencies.swift

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@
66

77
import Builtin
88

9+
struct NodeRef: ~Escapable {
10+
private var parent: UnsafePointer<Node>
11+
12+
// CHECK-LABEL: sil {{.*}}@${{.*}}7NodeRefV4node{{.*}}fC :
13+
// CHECK-SAME: (@in_guaranteed Node,
14+
@lifetime(borrow node)
15+
init(node: borrowing Node) {
16+
// CHECK: bb0(%0 : @noImplicitCopy $*Node,
17+
// CHECK: [[RAW_PTR:%.*]] = address_to_pointer {{.*}}%0
18+
// CHECK: struct $UnsafePointer<Node> ([[RAW_PTR]])
19+
self.parent = UnsafePointer(Builtin.addressOfBorrow(node))
20+
}
21+
22+
// CHECK-LABEL: sil {{.*}}@${{.*}}7NodeRefV9allocated{{.*}}fC :
23+
// CHECK-SAME: (@guaranteed AllocatedNode,
24+
@lifetime(borrow allocated)
25+
init(allocated: borrowing AllocatedNode) {
26+
self.parent = allocated.node
27+
}
28+
}
29+
930
@_addressableForDependencies
1031
struct Node {
1132
var id: String
@@ -23,16 +44,17 @@ struct Node {
2344
}
2445
}
2546

26-
struct NodeRef: ~Escapable {
27-
private var parent: UnsafePointer<Node>
47+
// not addressable for dependencies
48+
struct AllocatedNode: ~Copyable {
49+
fileprivate var node: UnsafePointer<Node>
2850

29-
// CHECK-LABEL: sil {{.*}}@${{.*}}7NodeRefV4node{{.*}}fC :
30-
// CHECK-SAME: (@in_guaranteed Node,
31-
@lifetime(borrow node)
32-
init(node: borrowing Node) {
33-
// CHECK: bb0(%0 : @noImplicitCopy $*Node,
34-
// CHECK: [[RAW_PTR:%.*]] = address_to_pointer {{.*}}%0
35-
// CHECK: struct $UnsafePointer<Node> ([[RAW_PTR]])
36-
self.parent = UnsafePointer(Builtin.addressOfBorrow(node))
51+
var ref: NodeRef {
52+
// CHECK-LABEL: sil {{.*}}@${{.*}}13AllocatedNodeV3ref{{.*}}Vvg :
53+
// CHECK-SAME: (@guaranteed AllocatedNode) ->
54+
@lifetime(borrow self)
55+
borrowing get {
56+
return NodeRef(allocated: self)
57+
}
3758
}
3859
}
60+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-swift-frontend -emit-sil -enable-experimental-feature BuiltinModule -enable-experimental-feature LifetimeDependence -enable-experimental-feature AddressableTypes -enable-experimental-feature AddressableParameters -verify %s
2+
3+
// REQUIRES: swift_feature_BuiltinModule
4+
// REQUIRES: swift_feature_AddressableParameters
5+
// REQUIRES: swift_feature_AddressableTypes
6+
// REQUIRES: swift_feature_LifetimeDependence
7+
8+
@_addressableForDependencies
9+
struct Node {
10+
var id: AnyObject
11+
12+
func grungle() {}
13+
}
14+
15+
struct NodeRef: ~Escapable {
16+
private var parent: UnsafePointer<Node>
17+
18+
@lifetime(borrow node)
19+
init(node: borrowing Node) { fatalError() }
20+
}
21+
22+
// Ensure there aren't spurious errors about consumption when an addressable
23+
// parameter is passed as a normal loadable parameter to another function
24+
// or method.
25+
@lifetime(borrow node)
26+
func test(node: borrowing Node) -> NodeRef {
27+
node.grungle()
28+
return NodeRef(node: node)
29+
}
30+

0 commit comments

Comments
 (0)