6
6
// (Some static/dynamic enforcement selection is done in SILGen, and some is
7
7
// deferred. That may change over time but we want the outcome to be the same).
8
8
//
9
- // Each FIXME line is a case that the current implementation misses.
10
- // The model is currently being refined, so this isn't set in stone.
11
- //
12
- // TODO: Ensure that each dynamic case is covered by
13
- // Interpreter/enforce_exclusive_access.swift.
9
+ // These tests attempt to fully cover the possibilities of reads and
10
+ // modifications to captures along with `inout` arguments on both the caller and
11
+ // callee side.
14
12
15
13
// Helper
16
14
func doOne( _ f: ( ) -> ( ) ) {
@@ -24,10 +22,8 @@ func doTwo(_: ()->(), _: ()->()) {}
24
22
func doOneInout( _: ( ) -> ( ) , _: inout Int ) { }
25
23
26
24
// Error: Cannot capture nonescaping closure.
27
- // Verification disabled because it suppresses all the other errors.
28
- // disabled-note@+1{{parameter 'fn' is implicitly non-escaping}}
25
+ // This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift.
29
26
// func reentrantCapturedNoescape(fn: (() -> ()) -> ()) {
30
- // disabled-error@+1{{closure use of non-escaping parameter 'fn' may allow it to escape}}
31
27
// let c = { fn {} }
32
28
// fn(c)
33
29
// }
@@ -308,8 +304,8 @@ func inoutReadWriteInout(x: inout Int) {
308
304
// CHECK: end_access [[ACCESS]]
309
305
// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19inoutReadWriteInoutySiz1x_tFyycfU_'
310
306
311
- // Trap on boxed read + write inout.
312
- // FIXME: Passing a captured var as inout needs dynamic enforcement .
307
+ // Traps on boxed read + write inout.
308
+ // Covered by Interpreter/enforce_exclusive_access.swift .
313
309
func readBoxWriteInout( ) {
314
310
var x = 3
315
311
let c = { _ = x }
@@ -333,12 +329,11 @@ func readBoxWriteInout() {
333
329
// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape17readBoxWriteInoutyyFyycfU_'
334
330
335
331
// Error: inout cannot be captured.
336
- // Verification disabled because is suppresses other errors.
337
- //func inoutReadBoxWriteInout(x: inout Int) {
338
- // disabled-error@+1{{escaping closures can only capture inout parameters explicitly by value}}
339
- // let c = { _ = x }
340
- // doOneInout(c, &x)
341
- //}
332
+ // This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift.
333
+ // func inoutReadBoxWriteInout(x: inout Int) {
334
+ // let c = { _ = x }
335
+ // doOneInout(c, &x)
336
+ // }
342
337
343
338
// Allow aliased noescape write + write.
344
339
func writeWrite( ) {
@@ -395,9 +390,8 @@ func inoutWriteWrite(x: inout Int) {
395
390
// CHECK: end_access [[ACCESS]]
396
391
// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE0ySiz1x_tFyycfU0_'
397
392
398
- // FIXME: Trap on aliased boxed write + noescape write.
399
- //
400
- // See the note above.
393
+ // Traps on aliased boxed write + noescape write.
394
+ // Covered by Interpreter/enforce_exclusive_access.swift.
401
395
func writeWriteBox( ) {
402
396
var x = 3
403
397
let c = { x = 87 }
@@ -479,8 +473,8 @@ func inoutWriteWriteInout(x: inout Int) {
479
473
// CHECK: end_access [[ACCESS]]
480
474
// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape010inoutWriteE5InoutySiz1x_tFyycfU_'
481
475
482
- // Trap on boxed write + write inout.
483
- // FIXME: Passing a captured var as inout needs dynamic enforcement .
476
+ // Traps on boxed write + write inout.
477
+ // Covered by Interpreter/enforce_exclusive_access.swift .
484
478
func writeBoxWriteInout( ) {
485
479
var x = 3
486
480
let c = { x = 42 }
@@ -504,9 +498,67 @@ func writeBoxWriteInout() {
504
498
// CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape18writeBoxWriteInoutyyFyycfU_'
505
499
506
500
// Error: Cannot capture inout
507
- // Verification disabled because it suppresses other errors .
501
+ // This triggers an early diagnostics, so it's handled in inout_capture_disgnostics.swift .
508
502
// func inoutWriteBoxWriteInout(x: inout Int) {
509
- // disabled-error@+1{{escaping closures can only capture inout parameters explicitly by value}}
510
503
// let c = { x = 42 }
511
504
// doOneInout(c, &x)
512
505
// }
506
+
507
+ // Helper
508
+ func doBlockInout( _: @convention ( block) ( ) -> ( ) , _: inout Int ) { }
509
+
510
+ // FIXME: This case could be statically enforced, but requires quite a bit of SIL pattern matching.
511
+ func readBlockWriteInout( ) {
512
+ var x = 3
513
+ // Around the call: [modify] [static]
514
+ // Inside closure: [modify] [static]
515
+ doBlockInout ( { _ = x } , & x)
516
+ }
517
+
518
+ // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape19readBlockWriteInoutyyF : $@convention(thin) () -> () {
519
+ // CHECK: [[F1:%.*]] = function_ref @_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> ()
520
+ // CHECK: [[PA:%.*]] = partial_apply [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> ()
521
+ // CHECK-NOT: begin_access
522
+ // CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int
523
+ // CHECK: apply
524
+ // CHECK: end_access [[WRITE]] : $*Int
525
+ // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19readBlockWriteInoutyyF'
526
+
527
+ // CHECK-LABEL: sil private @_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
528
+ // CHECK: begin_access [read] [static] %0 : $*Int
529
+ // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape19readBlockWriteInoutyyFyycfU_'
530
+
531
+ // Test AccessSummaryAnalysis.
532
+ //
533
+ // The captured @inout_aliasable argument to `doOne` is re-partially applied,
534
+ // then stored is a box before passing it to doBlockInout.
535
+ func noEscapeBlock( ) {
536
+ var x = 3
537
+ doOne {
538
+ doBlockInout ( { _ = x } , & x)
539
+ }
540
+ }
541
+ // CHECK-LABEL: sil hidden @_T027access_enforcement_noescape13noEscapeBlockyyF : $@convention(thin) () -> () {
542
+ // CHECK: partial_apply
543
+ // CHECK-NOT: begin_access
544
+ // CHECK: apply
545
+ // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyF'
546
+
547
+ // CHECK-LABEL: sil private @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
548
+ // CHECK: [[F1:%.*]] = function_ref @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_ : $@convention(thin) (@inout_aliasable Int) -> ()
549
+ // CHECK: [[PA:%.*]] = partial_apply [[F1]](%0) : $@convention(thin) (@inout_aliasable Int) -> ()
550
+ // CHECK: [[STORAGE:%.*]] = alloc_stack $@block_storage @callee_owned () -> ()
551
+ // CHECK: [[ADDR:%.*]] = project_block_storage %5 : $*@block_storage @callee_owned () -> ()
552
+ // CHECK: store [[PA]] to [[ADDR]] : $*@callee_owned () -> ()
553
+ // CHECK: [[BLOCK:%.*]] = init_block_storage_header [[STORAGE]] : $*@block_storage @callee_owned () -> (), invoke %8 : $@convention(c) (@inout_aliasable @block_storage @callee_owned () -> ()) -> (), type $@convention(block) () -> ()
554
+ // CHECK: [[ARG:%.*]] = copy_block [[BLOCK]] : $@convention(block) () -> ()
555
+ // CHECK: [[WRITE:%.*]] = begin_access [modify] [static] %0 : $*Int
556
+ // CHECK: apply %{{.*}}([[ARG]], [[WRITE]]) : $@convention(thin) (@owned @convention(block) () -> (), @inout Int) -> ()
557
+ // CHECK: end_access [[WRITE]] : $*Int
558
+ // CHECK: dealloc_stack [[STORAGE]] : $*@block_storage @callee_owned () -> ()
559
+ // CHECK: strong_release [[PA]] : $@callee_owned () -> ()
560
+ // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_'
561
+
562
+ // CHECK-LABEL: sil private @_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_ : $@convention(thin) (@inout_aliasable Int) -> () {
563
+ // CHECK: begin_access [read] [static] %0 : $*Int
564
+ // CHECK-LABEL: } // end sil function '_T027access_enforcement_noescape13noEscapeBlockyyFyycfU_yycfU_'
0 commit comments