Skip to content

Commit 689491c

Browse files
authored
Merge pull request #81675 from DougGregor/unsafe-pattern-match
[Strict memory safety] Lift "unsafe" in pattern match expressions
2 parents bc94ac3 + d5476ae commit 689491c

File tree

5 files changed

+52
-6
lines changed

5 files changed

+52
-6
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,13 +768,27 @@ ExprPatternMatchRequest::evaluate(Evaluator &evaluator,
768768
DeclNameLoc(EP->getLoc()));
769769
matchOp->setImplicit();
770770

771+
auto subExpr = EP->getSubExpr();
772+
773+
// Pull off the outer "unsafe" expression.
774+
UnsafeExpr *unsafeExpr = dyn_cast<UnsafeExpr>(subExpr);
775+
if (unsafeExpr) {
776+
subExpr = unsafeExpr->getSubExpr();
777+
}
778+
771779
// Note we use getEndLoc here to have the BinaryExpr source range be the same
772780
// as the expr pattern source range.
773781
auto *matchVarRef =
774782
new (ctx) DeclRefExpr(matchVar, DeclNameLoc(EP->getEndLoc()),
775783
/*Implicit=*/true);
776-
auto *matchCall = BinaryExpr::create(ctx, EP->getSubExpr(), matchOp,
784+
Expr *matchCall = BinaryExpr::create(ctx, subExpr, matchOp,
777785
matchVarRef, /*implicit*/ true);
786+
787+
// If there was an "unsafe", put it outside of the match call.
788+
if (unsafeExpr) {
789+
matchCall = UnsafeExpr::createImplicit(ctx, unsafeExpr->getLoc(), matchCall);
790+
}
791+
778792
return {matchVar, matchCall};
779793
}
780794

lib/Sema/TypeCheckUnsafe.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,20 @@ void swift::diagnoseUnsafeUse(const UnsafeUse &use) {
165165
ctx.Diags.diagnose(
166166
loc,
167167
diag::note_unsafe_call_decl_argument_indexed,
168-
calleeDecl, argumentIndex, paramType)
168+
calleeDecl, argumentIndex, argument->getType())
169169
.highlight(argument->getSourceRange());
170170
} else {
171171
ctx.Diags.diagnose(
172172
loc,
173173
diag::note_unsafe_call_decl_argument_named,
174-
calleeDecl, argumentName, paramType)
174+
calleeDecl, argumentName, argument->getType())
175175
.highlight(argument->getSourceRange());
176176
}
177177
} else {
178178
ctx.Diags.diagnose(
179179
loc,
180180
diag::note_unsafe_call_argument_indexed,
181-
argumentIndex, paramType)
181+
argumentIndex, argument->getType())
182182
.highlight(argument->getSourceRange());
183183
}
184184

test/Unsafe/safe.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,35 @@ extension Slice {
317317
}
318318
}
319319
}
320+
321+
@unsafe enum SomeEnum {
322+
case first
323+
case second
324+
}
325+
326+
@unsafe var someEnumValue: SomeEnum = unsafe .first
327+
328+
func testSwitch(se: SomeEnum) {
329+
switch unsafe se {
330+
case unsafe someEnumValue: break
331+
default: break
332+
}
333+
334+
switch unsafe se {
335+
case someEnumValue: break
336+
// expected-warning@-1{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{8-8=unsafe }}
337+
// expected-note@-2{{argument #0 in call to operator function '~=' has unsafe type 'SomeEnum'}}
338+
// expected-note@-3{{argument #1 in call to operator function '~=' has unsafe type 'SomeEnum'}}
339+
// expected-note@-4{{reference to unsafe type 'SomeEnum'}}
340+
// expected-note@-5{{reference to unsafe var 'someEnumValue'}}
341+
// expected-note@-6{{reference to let '$match' involves unsafe type 'SomeEnum'}}
342+
default: break
343+
}
344+
345+
// expected-note@+2{{reference to parameter 'se' involves unsafe type 'SomeEnum'}}
346+
// expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{10-10=unsafe }}
347+
switch se {
348+
case unsafe someEnumValue: break
349+
default: break
350+
}
351+
}

test/Unsafe/unsafe.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ extension ConformsToMultiP: MultiP {
4949
// expected-note@-1{{unsafe type 'UnsafeSuper' cannot satisfy safe associated type 'Ptr'}}
5050
@unsafe func f() -> UnsafeSuper {
5151
.init() // expected-warning{{expression uses unsafe constructs but is not marked with 'unsafe'}}
52-
// expected-note@-1{{argument 'self' in call to initializer 'init' has unsafe type 'UnsafeSuper'}}
52+
// expected-note@-1{{argument 'self' in call to initializer 'init' has unsafe type 'UnsafeSuper.Type'}}
5353
}
5454
}
5555

test/Unsafe/unsafe_stdlib.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ func test(
99
) {
1010
var array = [1, 2, 3]
1111
// expected-warning@+2{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{3-3=unsafe }}
12-
// expected-note@+1{{argument #0 in call to instance method 'withUnsafeBufferPointer' has unsafe type '(UnsafeBufferPointer<Element>) throws(E) -> R'}}
12+
// expected-note@+1{{argument #0 in call to instance method 'withUnsafeBufferPointer' has unsafe type '(UnsafeBufferPointer<Int>) -> ()'}}
1313
array.withUnsafeBufferPointer{ buffer in
1414
// expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}{{5-5=unsafe }}
1515
print(buffer) // expected-note{{reference to parameter 'buffer' involves unsafe type 'UnsafeBufferPointer<Int>'}}

0 commit comments

Comments
 (0)