Skip to content

Commit 96e5f2a

Browse files
committed
Allow non-ephemeral diag to refer to argument labels
Use getArgDescription to improve the diagnostic for invalid temporary pointer conversions.
1 parent 912a7ac commit 96e5f2a

File tree

6 files changed

+48
-30
lines changed

6 files changed

+48
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -401,18 +401,18 @@ ERROR(cannot_convert_argument_value_generic,none,
401401

402402
// @_nonEphemeral conversion diagnostics
403403
ERROR(cannot_pass_type_to_non_ephemeral,none,
404-
"cannot pass %0 to parameter; argument #%1 must be a pointer that "
405-
"outlives the call%select{| to %3}2", (Type, unsigned, bool, DeclName))
404+
"cannot pass %0 to parameter; argument %1 must be a pointer that "
405+
"outlives the call%select{| to %3}2", (Type, StringRef, bool, DeclName))
406406
WARNING(cannot_pass_type_to_non_ephemeral_warning,none,
407-
"passing %0 to parameter, but argument #%1 should be a pointer that "
408-
"outlives the call%select{| to %3}2", (Type, unsigned, bool, DeclName))
407+
"passing %0 to parameter, but argument %1 should be a pointer that "
408+
"outlives the call%select{| to %3}2", (Type, StringRef, bool, DeclName))
409409
ERROR(cannot_use_inout_non_ephemeral,none,
410-
"cannot use inout expression here; argument #%0 must be a pointer that "
411-
"outlives the call%select{| to %2}1", (unsigned, bool, DeclName))
410+
"cannot use inout expression here; argument %0 must be a pointer that "
411+
"outlives the call%select{| to %2}1", (StringRef, bool, DeclName))
412412
WARNING(cannot_use_inout_non_ephemeral_warning,none,
413-
"inout expression creates a temporary pointer, but argument #%0 should "
413+
"inout expression creates a temporary pointer, but argument %0 should "
414414
"be a pointer that outlives the call%select{| to %2}1",
415-
(unsigned, bool, DeclName))
415+
(StringRef, bool, DeclName))
416416
ERROR(cannot_construct_dangling_pointer,none,
417417
"initialization of %0 results in a dangling %select{|buffer }1pointer",
418418
(Type, unsigned))

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5680,21 +5680,24 @@ bool NonEphemeralConversionFailure::diagnoseAsError() {
56805680
return true;
56815681

56825682
// Otherwise, emit a more general diagnostic.
5683+
SmallString<8> scratch;
5684+
auto argDesc = getArgDescription(scratch);
5685+
56835686
auto *argExpr = getArgExpr();
56845687
if (isa<InOutExpr>(argExpr)) {
56855688
auto diagID = DowngradeToWarning
56865689
? diag::cannot_use_inout_non_ephemeral_warning
56875690
: diag::cannot_use_inout_non_ephemeral;
56885691

5689-
emitDiagnostic(argExpr->getLoc(), diagID, getArgPosition(), getCallee(),
5692+
emitDiagnostic(argExpr->getLoc(), diagID, argDesc, getCallee(),
56905693
getCalleeFullName())
56915694
.highlight(argExpr->getSourceRange());
56925695
} else {
56935696
auto diagID = DowngradeToWarning
56945697
? diag::cannot_pass_type_to_non_ephemeral_warning
56955698
: diag::cannot_pass_type_to_non_ephemeral;
56965699

5697-
emitDiagnostic(argExpr->getLoc(), diagID, getArgType(), getArgPosition(),
5700+
emitDiagnostic(argExpr->getLoc(), diagID, getArgType(), argDesc,
56985701
getCallee(), getCalleeFullName())
56995702
.highlight(argExpr->getSourceRange());
57005703
}

test/IDE/infer_import_as_member.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,10 @@ func testNonEphemeralInitParams(x: Double) {
126126
var x = x
127127

128128
_ = IAMPointerStruct(ptr1: &x, ptr2: &x)
129-
// expected-error@-1 {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
129+
// expected-error@-1 {{cannot use inout expression here; argument 'ptr1' must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
130130
// expected-note@-2 {{implicit argument conversion from 'Double' to 'UnsafeMutablePointer<Double>?' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
131131
// expected-note@-3 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
132-
// expected-error@-4 {{cannot use inout expression here; argument #2 must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
132+
// expected-error@-4 {{cannot use inout expression here; argument 'ptr2' must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
133133
// expected-note@-5 {{implicit argument conversion from 'Double' to 'UnsafeMutablePointer<Double>?' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
134134
// expected-note@-6 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
135135

test/IDE/newtype.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,15 +242,15 @@ func testNonEphemeralInitParams(x: OpaquePointer) {
242242
// expected-note@-1 {{implicit argument conversion from 'OpaquePointer' to 'UnsafeMutablePointer<OpaquePointer>' produces a pointer valid only for the duration of the call}}
243243
// expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
244244

245-
_ = TRefRef(rawValue: &x) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'init(rawValue:)'}}
245+
_ = TRefRef(rawValue: &x) // expected-warning {{inout expression creates a temporary pointer, but argument 'rawValue' should be a pointer that outlives the call to 'init(rawValue:)'}}
246246
// expected-note@-1 {{implicit argument conversion from 'OpaquePointer' to 'UnsafeMutablePointer<OpaquePointer>' produces a pointer valid only for the duration of the call}}
247247
// expected-note@-2 {{use 'withUnsafeMutablePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
248248

249249
_ = ConstTRefRef(&x) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'init(_:)'}}
250250
// expected-note@-1 {{implicit argument conversion from 'OpaquePointer' to 'UnsafePointer<OpaquePointer>' produces a pointer valid only for the duration of the call}}
251251
// expected-note@-2 {{use 'withUnsafePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
252252

253-
_ = ConstTRefRef(rawValue: &x) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'init(rawValue:)'}}
253+
_ = ConstTRefRef(rawValue: &x) // expected-warning {{inout expression creates a temporary pointer, but argument 'rawValue' should be a pointer that outlives the call to 'init(rawValue:)'}}
254254
// expected-note@-1 {{implicit argument conversion from 'OpaquePointer' to 'UnsafePointer<OpaquePointer>' produces a pointer valid only for the duration of the call}}
255255
// expected-note@-2 {{use 'withUnsafePointer' in order to explicitly convert argument to pointer valid for a defined scope}}
256256
}

test/Sema/diag_non_ephemeral.swift

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -374,29 +374,29 @@ func testNonEphemeralInMembers() {
374374
// expected-note@-1 {{implicit argument conversion from '[Int]' to 'UnsafePointer<Int>' produces a pointer valid only for the duration of the call to 'takesConstStaticAndReturns'}}
375375
// expected-note@-2 {{use the 'withUnsafeBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope}}
376376

377-
S2.takesMutableRawStatic(ptr: &local) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
377+
S2.takesMutableRawStatic(ptr: &local) // expected-error {{cannot use inout expression here; argument 'ptr' must be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
378378
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRawStatic(_:ptr:)'}}
379379
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
380380

381-
S2.takesMutableRawStatic("", ptr: &local) // expected-error {{cannot use inout expression here; argument #2 must be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
381+
S2.takesMutableRawStatic("", ptr: &local) // expected-error {{cannot use inout expression here; argument 'ptr' must be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
382382
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRawStatic(_:ptr:)'}}
383383
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
384384

385385
var s2 = S2()
386386
s2.takesMutableRaw()
387-
s2.takesMutableRaw(ptr: &local) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'takesMutableRaw(ptr:)'}}
387+
s2.takesMutableRaw(ptr: &local) // expected-error {{cannot use inout expression here; argument 'ptr' must be a pointer that outlives the call to 'takesMutableRaw(ptr:)'}}
388388
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw(ptr:)'}}
389389
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
390390

391-
_ = s2[takesConstInt8: ""] // expected-error {{cannot pass 'String' to parameter; argument #1 must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
391+
_ = s2[takesConstInt8: ""] // expected-error {{cannot pass 'String' to parameter; argument 'takesConstInt8' must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
392392
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
393393
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
394394

395-
s2[takesConstInt8: ""] += 1 // expected-error {{cannot pass 'String' to parameter; argument #1 must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
395+
s2[takesConstInt8: ""] += 1 // expected-error {{cannot pass 'String' to parameter; argument 'takesConstInt8' must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
396396
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
397397
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
398398

399-
_ = \S2.[takesConstInt8: ""] // expected-error {{cannot pass 'String' to parameter; argument #1 must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
399+
_ = \S2.[takesConstInt8: ""] // expected-error {{cannot pass 'String' to parameter; argument 'takesConstInt8' must be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
400400
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
401401
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
402402
}
@@ -451,11 +451,11 @@ enum E {
451451
func testNonEphemeralInMemberwiseInits() {
452452
var local = 0
453453

454-
_ = S3(ptr1: &topLevelS, ptr2: &local) // expected-error {{cannot use inout expression here; argument #2 must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
454+
_ = S3(ptr1: &topLevelS, ptr2: &local) // expected-error {{cannot use inout expression here; argument 'ptr2' must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
455455
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer?' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
456456
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
457457

458-
_ = S3.init(ptr1: &local, ptr2: &topLevelS) // expected-error {{cannot use inout expression here; argument #1 must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
458+
_ = S3.init(ptr1: &local, ptr2: &topLevelS) // expected-error {{cannot use inout expression here; argument 'ptr1' must be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
459459
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
460460
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
461461

@@ -505,3 +505,18 @@ func testNonEphemeralErrorDoesntAffectOverloadResolution() {
505505
// expected-note@-1 {{implicit argument conversion from '[Int]' to 'UnsafePointer<Int>' produces a pointer valid only for the duration of the call to 'takesPointerOverload2'}}
506506
// expected-note@-2 {{use the 'withUnsafeBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope}}
507507
}
508+
509+
func takesTwoPointers(@_nonEphemeral ptr _: UnsafePointer<Int>, @_nonEphemeral ptr _: UnsafePointer<Int>) {}
510+
511+
func testArgumentLabelReferencing() {
512+
// Because takesTwoPointers has two argument labels with the same name, refer
513+
// to the argument by position.
514+
var arr = [1, 2, 3]
515+
takesTwoPointers(ptr: arr, ptr: arr)
516+
// expected-error@-1 {{cannot pass '[Int]' to parameter; argument #1 must be a pointer that outlives the call to 'takesTwoPointers(ptr:ptr:)'}}
517+
// expected-note@-2 {{implicit argument conversion from '[Int]' to 'UnsafePointer<Int>' produces a pointer valid only for the duration of the call to 'takesTwoPointers(ptr:ptr:)'}}
518+
// expected-note@-3 {{use the 'withUnsafeBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope}}
519+
// expected-error@-4 {{cannot pass '[Int]' to parameter; argument #2 must be a pointer that outlives the call to 'takesTwoPointers(ptr:ptr:)'}}
520+
// expected-note@-5 {{implicit argument conversion from '[Int]' to 'UnsafePointer<Int>' produces a pointer valid only for the duration of the call to 'takesTwoPointers(ptr:ptr:)'}}
521+
// expected-note@-6 {{use the 'withUnsafeBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope}}
522+
}

test/Sema/diag_non_ephemeral_warning.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -374,29 +374,29 @@ func testNonEphemeralInMembers() {
374374
// expected-note@-1 {{implicit argument conversion from '[Int]' to 'UnsafePointer<Int>' produces a pointer valid only for the duration of the call to 'takesConstStaticAndReturns'}}
375375
// expected-note@-2 {{use the 'withUnsafeBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope}}
376376

377-
S2.takesMutableRawStatic(ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
377+
S2.takesMutableRawStatic(ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument 'ptr' should be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
378378
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRawStatic(_:ptr:)'}}
379379
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
380380

381-
S2.takesMutableRawStatic("", ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument #2 should be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
381+
S2.takesMutableRawStatic("", ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument 'ptr' should be a pointer that outlives the call to 'takesMutableRawStatic(_:ptr:)'}}
382382
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRawStatic(_:ptr:)'}}
383383
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
384384

385385
var s2 = S2()
386386
s2.takesMutableRaw()
387-
s2.takesMutableRaw(ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'takesMutableRaw(ptr:)'}}
387+
s2.takesMutableRaw(ptr: &local) // expected-warning {{inout expression creates a temporary pointer, but argument 'ptr' should be a pointer that outlives the call to 'takesMutableRaw(ptr:)'}}
388388
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'takesMutableRaw(ptr:)'}}
389389
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
390390

391-
_ = s2[takesConstInt8: ""] // expected-warning {{passing 'String' to parameter, but argument #1 should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
391+
_ = s2[takesConstInt8: ""] // expected-warning {{passing 'String' to parameter, but argument 'takesConstInt8' should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
392392
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
393393
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
394394

395-
s2[takesConstInt8: ""] += 1 // expected-warning {{passing 'String' to parameter, but argument #1 should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
395+
s2[takesConstInt8: ""] += 1 // expected-warning {{passing 'String' to parameter, but argument 'takesConstInt8' should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
396396
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
397397
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
398398

399-
_ = \S2.[takesConstInt8: ""] // expected-warning {{passing 'String' to parameter, but argument #1 should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
399+
_ = \S2.[takesConstInt8: ""] // expected-warning {{passing 'String' to parameter, but argument 'takesConstInt8' should be a pointer that outlives the call to 'subscript(takesConstInt8:)'}}
400400
// expected-note@-1 {{implicit argument conversion from 'String' to 'UnsafePointer<Int8>' produces a pointer valid only for the duration of the call to 'subscript(takesConstInt8:)'}}
401401
// expected-note@-2 {{use the 'withCString' method on String in order to explicitly convert argument to pointer valid for a defined scope}}
402402
}
@@ -447,11 +447,11 @@ enum E {
447447
func testNonEphemeralInMemberwiseInits() {
448448
var local = 0
449449

450-
_ = S3(ptr1: &topLevelS, ptr2: &local) // expected-warning {{inout expression creates a temporary pointer, but argument #2 should be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
450+
_ = S3(ptr1: &topLevelS, ptr2: &local) // expected-warning {{inout expression creates a temporary pointer, but argument 'ptr2' should be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
451451
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer?' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
452452
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
453453

454-
_ = S3.init(ptr1: &local, ptr2: &topLevelS) // expected-warning {{inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
454+
_ = S3.init(ptr1: &local, ptr2: &topLevelS) // expected-warning {{inout expression creates a temporary pointer, but argument 'ptr1' should be a pointer that outlives the call to 'init(ptr1:ptr2:)'}}
455455
// expected-note@-1 {{implicit argument conversion from 'Int' to 'UnsafeMutableRawPointer' produces a pointer valid only for the duration of the call to 'init(ptr1:ptr2:)'}}
456456
// expected-note@-2 {{use 'withUnsafeMutableBytes' in order to explicitly convert argument to buffer pointer valid for a defined scope}}
457457

0 commit comments

Comments
 (0)