@@ -1436,6 +1436,7 @@ struct TestDynamic {
1436
1436
1437
1437
@_hasStorage @_hasInitialValue var s: S { get set }
1438
1438
1439
+ // CHECK-LABEL: sil hidden [ossa] @testCallDynamic : $@convention(method) (@inout TestDynamic) -> () {
1439
1440
sil hidden [ossa] @testCallDynamic : $@convention(method) (@inout TestDynamic) -> () {
1440
1441
bb0(%0 : $*TestDynamic):
1441
1442
%access = begin_access [modify] [unknown] %0 : $*TestDynamic // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
@@ -1462,3 +1463,137 @@ bb0(%0 : $*Builtin.Int64, %1 : $*TestDynamic):
1462
1463
%19 = tuple ()
1463
1464
return %19 : $()
1464
1465
}
1466
+
1467
+ // Dictionary.subscript.modify
1468
+ sil [serialized] [always_inline] @$sSD_7defaultq_x_q_yXKtciM : $@yield_once @convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @noescape @callee_guaranteed () -> @out τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1
1469
+
1470
+ // -----------------------------------------------------------------------------
1471
+ // testBeginApplyOfClosure: DiagnoseStaticExclusivity must consider
1472
+ // begin_apply as a user of accessed variables.
1473
+ //
1474
+ // Test a static exclusivity conflict between an outgoing coroutine
1475
+ // argument and the closure passed to the coroutine.
1476
+ // %access = begin_access [modify] %0
1477
+ // begin_apply %coroutine(%access, %closure) -- where the closure captures %0
1478
+
1479
+ // CHECK-LABEL: sil private [ossa] @closureForBeginApplyOfClosure : $@convention(thin) (@inout_aliasable Int) -> @out Int {
1480
+ sil private [ossa] @closureForBeginApplyOfClosure : $@convention(thin) (@inout_aliasable Int) -> @out Int {
1481
+ bb0(%0 : $*Int, %1 : $*Int):
1482
+ %access = begin_access [read] [static] %1 : $*Int // expected-note {{conflicting access is here}}
1483
+ %val = load [trivial] %access : $*Int
1484
+ end_access %access : $*Int
1485
+ store %val to [trivial] %0 : $*Int
1486
+ %v = tuple ()
1487
+ return %v : $()
1488
+ }
1489
+
1490
+ // CHECK-LABEL: sil [ossa] @testBeginApplyOfClosure : $@convention(thin) (@inout Int, @inout Dictionary<Int, Int>) -> () {
1491
+ sil [ossa] @testBeginApplyOfClosure : $@convention(thin) (@inout Int, @inout Dictionary<Int, Int>) -> () {
1492
+ bb0(%0 : $*Int, %1 : $*Dictionary<Int, Int>):
1493
+ %f = function_ref @closureForBeginApplyOfClosure : $@convention(thin) (@inout_aliasable Int) -> @out Int
1494
+ %pa = partial_apply [callee_guaranteed] %f(%0) : $@convention(thin) (@inout_aliasable Int) -> @out Int
1495
+ %cvt = convert_escape_to_noescape [not_guaranteed] %pa : $@callee_guaranteed () -> @out Int to $@noescape @callee_guaranteed () -> @out Int
1496
+ // function_ref Dictionary.subscript.modify
1497
+ %mod = function_ref @$sSD_7defaultq_x_q_yXKtciM : $@yield_once @convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @noescape @callee_guaranteed () -> @out τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1
1498
+ %access = begin_access [modify] [static] %0 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
1499
+ (%yield, %token) = begin_apply %mod<Int, Int>(%access, %cvt, %1) : $@yield_once @convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @noescape @callee_guaranteed () -> @out τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1
1500
+ end_apply %token
1501
+ end_access %access : $*Int
1502
+ destroy_value %pa : $@callee_guaranteed () -> @out Int
1503
+ %v = tuple ()
1504
+ return %v : $()
1505
+ }
1506
+
1507
+ // -----------------------------------------------------------------------------
1508
+ // testCoroutineWithClosureArg: AccessedSummaryAnalysis must consider
1509
+ // begin_apply a valid user of partial_apply.
1510
+ //
1511
+ // Test that this does not assert in hasExpectedUsesOfNoEscapePartialApply.
1512
+ //
1513
+ // This test needs two closures, one to capture the variable, another
1514
+ // to recapture the variable, so AccessSummary is forced to process
1515
+ // the closure.
1516
+ // CHECK-LABEL: sil hidden [ossa] @testCoroutineWithClosureArg : $@convention(thin) (Int, @inout Int, @inout Dictionary<Int, Int>) -> () {
1517
+ sil hidden [ossa] @testCoroutineWithClosureArg : $@convention(thin) (Int, @inout Int, @inout Dictionary<Int, Int>) -> () {
1518
+ bb0(%0 : $Int, %1 : $*Int, %2 : $*Dictionary<Int, Int>):
1519
+ %6 = function_ref @closureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Dictionary<Int, Int>, Int, @inout_aliasable Int) -> ()
1520
+ %7 = apply %6(%2, %0, %1) : $@convention(thin) (@inout_aliasable Dictionary<Int, Int>, Int, @inout_aliasable Int) -> ()
1521
+ %8 = tuple ()
1522
+ return %8 : $()
1523
+ }
1524
+
1525
+ // thunk for @callee_guaranteed () -> (@unowned Int)
1526
+ sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sSiIgd_SiIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int {
1527
+ bb0(%0 : $*Int, %1 : $@noescape @callee_guaranteed () -> Int):
1528
+ %2 = apply %1() : $@noescape @callee_guaranteed () -> Int
1529
+ store %2 to [trivial] %0 : $*Int
1530
+ %4 = tuple ()
1531
+ return %4 : $()
1532
+ }
1533
+
1534
+ // CHECK-LABEL: sil private [ossa] @closureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Dictionary<Int, Int>, Int, @inout_aliasable Int) -> () {
1535
+ sil private [ossa] @closureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Dictionary<Int, Int>, Int, @inout_aliasable Int) -> () {
1536
+ bb0(%0 : $*Dictionary<Int, Int>, %1 : $Int, %2 : $*Int):
1537
+ %6 = function_ref @implicitClosureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> Int
1538
+ %7 = partial_apply [callee_guaranteed] %6(%2) : $@convention(thin) (@inout_aliasable Int) -> Int
1539
+ %8 = convert_escape_to_noescape [not_guaranteed] %7 : $@callee_guaranteed () -> Int to $@noescape @callee_guaranteed () -> Int
1540
+ %13 = begin_access [modify] [unknown] %0 : $*Dictionary<Int, Int>
1541
+ %14 = alloc_stack $Int
1542
+ store %1 to [trivial] %14 : $*Int
1543
+ // thunk for @callee_guaranteed () -> (@unowned Int)
1544
+ %16 = function_ref @$sSiIgd_SiIegr_TR : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int
1545
+ %17 = partial_apply [callee_guaranteed] %16(%8) : $@convention(thin) (@noescape @callee_guaranteed () -> Int) -> @out Int
1546
+ %18 = convert_escape_to_noescape [not_guaranteed] %17 : $@callee_guaranteed () -> @out Int to $@noescape @callee_guaranteed () -> @out Int
1547
+ destroy_value %17 : $@callee_guaranteed () -> @out Int
1548
+ // Dictionary.subscript.modify
1549
+ %20 = function_ref @$sSD_7defaultq_x_q_yXKtciM : $@yield_once @convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @noescape @callee_guaranteed () -> @out τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1
1550
+ (%21, %22) = begin_apply %20<Int, Int>(%14, %18, %13) : $@yield_once @convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in_guaranteed τ_0_0, @noescape @callee_guaranteed () -> @out τ_0_1, @inout Dictionary<τ_0_0, τ_0_1>) -> @yields @inout τ_0_1
1551
+ assign %1 to %21 : $*Int
1552
+ end_apply %22
1553
+ end_access %13 : $*Dictionary<Int, Int>
1554
+ dealloc_stack %14 : $*Int
1555
+ destroy_value %7 : $@callee_guaranteed () -> Int
1556
+ %28 = tuple ()
1557
+ return %28 : $()
1558
+ }
1559
+
1560
+ // CHECK-LABEL: sil private [transparent] [ossa] @implicitClosureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> Int {
1561
+ sil private [transparent] [ossa] @implicitClosureForTestCoroutineWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> Int {
1562
+ bb0(%0 : $*Int):
1563
+ %2 = begin_access [read] [unknown] %0 : $*Int
1564
+ %3 = load [trivial] %2 : $*Int
1565
+ end_access %2 : $*Int
1566
+ return %3 : $Int
1567
+ }
1568
+
1569
+ // -----------------------------------------------------------------------------
1570
+ // testExternalWithClosureArg: handle inout arguments to resilient functions
1571
+ // conservatively.
1572
+
1573
+ sil [ossa] @externalWithInout : $@convention(thin) (@inout Int) -> ()
1574
+
1575
+ // CHECK-LABEL: sil private [ossa] @closureForTestExternalWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> () {
1576
+ sil private [ossa] @closureForTestExternalWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> () {
1577
+ bb0(%0 : $*Int):
1578
+ %f = function_ref @externalWithInout : $@convention(thin) (@inout Int) -> ()
1579
+ %call = apply %f(%0) : $@convention(thin) (@inout Int) -> () // expected-note {{conflicting access is here}}
1580
+ %v = tuple ()
1581
+ return %v : $()
1582
+ }
1583
+
1584
+ sil [ossa] @calleeForTestExternalWithClosureArg : $@convention(thin) (@inout Int, @noescape @callee_guaranteed () -> ()) -> ()
1585
+
1586
+ // CHECK-LABEL: sil hidden [ossa] @testExternalWithClosureArg : $@convention(thin) (@inout Int) -> () {
1587
+ sil hidden [ossa] @testExternalWithClosureArg : $@convention(thin) (@inout Int) -> () {
1588
+ bb0(%0 : $*Int):
1589
+ %2 = function_ref @closureForTestExternalWithClosureArg : $@convention(thin) (@inout_aliasable Int) -> ()
1590
+ %3 = partial_apply [callee_guaranteed] %2(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
1591
+ %4 = convert_escape_to_noescape [not_guaranteed] %3 : $@callee_guaranteed () -> () to $@noescape @callee_guaranteed () -> ()
1592
+ %5 = begin_access [modify] [unknown] %0 : $*Int // expected-error {{overlapping accesses, but modification requires exclusive access; consider copying to a local variable}}
1593
+ %6 = function_ref @calleeForTestExternalWithClosureArg : $@convention(thin) (@inout Int, @noescape @callee_guaranteed () -> ()) -> ()
1594
+ %7 = apply %6(%5, %4) : $@convention(thin) (@inout Int, @noescape @callee_guaranteed () -> ()) -> ()
1595
+ end_access %5 : $*Int
1596
+ destroy_value %3 : $@callee_guaranteed () -> ()
1597
+ %10 = tuple ()
1598
+ return %10 : $()
1599
+ }
0 commit comments