Skip to content

Commit 92f0d9e

Browse files
authored
Merge pull request #4114 from atrick/rawptr-diag
Improve diagnostics on invalid UnsafePointer conversion.
2 parents 48bfec4 + 56f68c4 commit 92f0d9e

File tree

5 files changed

+44
-45
lines changed

5 files changed

+44
-45
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ ERROR(cannot_call_with_params, none,
210210
"cannot invoke %select{|initializer for type }2'%0' with an argument list"
211211
" of type '%1'", (StringRef, StringRef, bool))
212212

213-
NOTE(pointer_init_add_mutating,none,
214-
"do you want to add 'mutating'", ())
213+
NOTE(pointer_init_to_type,none,
214+
"Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.", ())
215+
215216
ERROR(expected_do_in_statement,none,
216217
"expected 'do' keyword to designate a block of statements", ())
217218

lib/Sema/CSDiag.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4976,26 +4976,37 @@ bool FailureDiagnosis::diagnoseNilLiteralComparison(
49764976
return true;
49774977
}
49784978

4979-
/// When initializing UnsafeMutablePointer from a given UnsafePointer, we need
4980-
/// to insert "mutating:" label before the argument to ensure the correct
4981-
/// intializer gets called. This function checks if we need to add the label.
4982-
static bool shouldAddMutating(ASTContext &Ctx, const Expr *Fn,
4983-
const Expr* Arg) {
4979+
/// When initializing Unsafe[Mutable]Pointer<T> from Unsafe[Mutable]RawPointer,
4980+
/// issue a diagnostic that refers to the API for binding memory to a type.
4981+
static bool isCastToTypedPointer(ASTContext &Ctx, const Expr *Fn,
4982+
const Expr* Arg) {
49844983
auto *TypeExp = dyn_cast<TypeExpr>(Fn);
49854984
auto *ParenExp = dyn_cast<ParenExpr>(Arg);
49864985
if (!TypeExp || !ParenExp)
49874986
return false;
4987+
49884988
auto InitType = TypeExp->getInstanceType();
49894989
auto ArgType = ParenExp->getSubExpr()->getType();
49904990
if (InitType.isNull() || ArgType.isNull())
49914991
return false;
4992-
if (auto *InitNom = InitType->getAnyNominal()) {
4993-
if (auto *ArgNom = ArgType->getAnyNominal()) {
4994-
return InitNom == Ctx.getUnsafeMutablePointerDecl() &&
4995-
ArgNom == Ctx.getUnsafePointerDecl();
4996-
}
4992+
4993+
auto *InitNom = InitType->getAnyNominal();
4994+
if (!InitNom)
4995+
return false;
4996+
4997+
if (InitNom != Ctx.getUnsafeMutablePointerDecl()
4998+
&& InitNom != Ctx.getUnsafePointerDecl()) {
4999+
return false;
49975000
}
4998-
return false;
5001+
auto *ArgNom = ArgType->getAnyNominal();
5002+
if (!ArgNom)
5003+
return false;
5004+
5005+
if (ArgNom != Ctx.getUnsafeMutableRawPointerDecl()
5006+
&& ArgNom != Ctx.getUnsafeRawPointerDecl()) {
5007+
return false;
5008+
}
5009+
return true;
49995010
}
50005011

50015012
bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
@@ -5313,10 +5324,9 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
53135324
overloadName, argString, isInitializer);
53145325
}
53155326

5316-
5317-
if (shouldAddMutating(CS->DC->getASTContext(), fnExpr, argExpr)) {
5318-
diagnose(fnExpr->getLoc(), diag::pointer_init_add_mutating).fixItInsert(
5319-
cast<ParenExpr>(argExpr)->getSubExpr()->getStartLoc(), "mutating: ");
5327+
if (isCastToTypedPointer(CS->DC->getASTContext(), fnExpr, argExpr)) {
5328+
diagnose(fnExpr->getLoc(), diag::pointer_init_to_type)
5329+
.highlight(argExpr->getSourceRange());
53205330
}
53215331

53225332
// Did the user intend on invoking a different overload?

stdlib/public/core/UnsafePointer.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ extension ${Self} {
532532
"use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.")
533533
public init?<U>(_ from : UnsafePointer<U>?) { Builtin.unreachable(); return nil }
534534

535-
% if mutable:
535+
% if mutable:
536536
@available(*, unavailable, renamed: "init(mutating:)")
537537
public init(_ from : UnsafePointer<Pointee>) { Builtin.unreachable() }
538538

test/1_stdlib/UnsafePointerDiagnostics.swift

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@
22

33
// Test availability attributes on UnsafePointer initializers.
44
// Assume the original source contains no UnsafeRawPointer types.
5-
//
6-
// TODO:
7-
// - implement the Unsafe[Mutable]Pointer<Void> to Unsafe[Mutable]RawPointer rename
8-
// - test multiple fix-its per line: type rename + initializer rename/diagnostic
95
func unsafePointerConversionAvailability(
106
mrp: UnsafeMutableRawPointer,
117
rp: UnsafeRawPointer,
12-
umpv: UnsafeMutablePointer<Void>,
13-
upv: UnsafePointer<Void>,
8+
umpv: UnsafeMutablePointer<Void>, // FIXME: This should yield a warning to rename UnsafeMutablePointer<Void> to UnsafeMutableRawPointer
9+
upv: UnsafePointer<Void>, // FIXME: This should yield a warning to rename UnsafePointer<Void> to UnsafeRawPointer
1410
umpi: UnsafeMutablePointer<Int>,
1511
upi: UnsafePointer<Int>,
1612
umps: UnsafeMutablePointer<String>,
@@ -35,42 +31,39 @@ func unsafePointerConversionAvailability(
3531
_ = UnsafeRawPointer(umps)
3632
_ = UnsafeRawPointer(ups)
3733

38-
// FIXME: All of these should yield a fix-it to rename
39-
// UnsafeMutablePointer<Void> to UnsafeMutableRawPointer(umpv)
40-
_ = UnsafeMutablePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}}
41-
_ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}}
34+
// FIXME: All of these should yield a warning to rename
35+
// UnsafeMutablePointer<Void> to UnsafeMutableRawPointer.
36+
_ = UnsafeMutablePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
37+
_ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
4238
_ = UnsafeMutablePointer<Void>(umpv)
4339
_ = UnsafeMutablePointer<Void>(upv) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
4440
_ = UnsafeMutablePointer<Void>(umpi)
4541
_ = UnsafeMutablePointer<Void>(upi) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
4642
_ = UnsafeMutablePointer<Void>(umps)
4743
_ = UnsafeMutablePointer<Void>(ups) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
4844

49-
// FIXME: All of these should yield a fix-it to rename
50-
// UnsafePointer<Void> to UnsafeRawPointer(umpv)
51-
_ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}}
52-
_ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}}
53-
_ = UnsafePointer<Void>(umpv)
45+
// FIXME: All of these should yield a warning to rename
46+
// UnsafePointer<Void> to UnsafeRawPointer.
47+
_ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
48+
_ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
49+
_ = UnsafePointer<Void>(umpv)
5450
_ = UnsafePointer<Void>(upv)
5551
_ = UnsafePointer<Void>(umpi)
5652
_ = UnsafePointer<Void>(upi)
5753
_ = UnsafePointer<Void>(umps)
5854
_ = UnsafePointer<Void>(ups)
5955

60-
// FIXME: Conversion from UnsafePointer<Void> or UnsafeRawPointer to a typed
61-
// pointer should have a diagnostic: 'init' is unavailable: Conversion
62-
// restricted. Use 'assumingMemoryBound(to:)' or 'bindMemory(to:capacity:)'
63-
_ = UnsafeMutablePointer<Int>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}}
64-
_ = UnsafeMutablePointer<Int>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}}
56+
_ = UnsafeMutablePointer<Int>(rp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
57+
_ = UnsafeMutablePointer<Int>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Int>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
6558
_ = UnsafeMutablePointer<Int>(umpv) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
6659
_ = UnsafeMutablePointer<Int>(upv) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
6760
_ = UnsafeMutablePointer<Int>(umpi)
6861
_ = UnsafeMutablePointer<Int>(upi) // expected-error {{'init' has been renamed to 'init(mutating:)'}}
6962
_ = UnsafeMutablePointer<Int>(umps) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
7063
_ = UnsafeMutablePointer<Int>(ups) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
7164

72-
_ = UnsafePointer<Int>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Int>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}}
73-
_ = UnsafePointer<Int>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Int>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}}
65+
_ = UnsafePointer<Int>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Int>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
66+
_ = UnsafePointer<Int>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Int>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type.}} expected-note {{}}
7467
_ = UnsafePointer<Int>(umpv) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
7568
_ = UnsafePointer<Int>(upv) // expected-error {{'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.}}
7669
_ = UnsafePointer<Int>(umpi)

test/Sema/diag_init.swift

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)