Skip to content

Commit d4dc36d

Browse files
committed
[Strict memory safety] Lift "unsafe" in pattern match expressions
When an "unsafe" expression is used as the case expression, lift it up so it also covers the synthesized matching expression (`=~`). This eliminates some unsuppressible strict memory safety warnings. Fixes rdar://151731850.
1 parent ee9c0cc commit d4dc36d

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
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

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 'T'}}
338+
// expected-note@-3{{argument #1 in call to operator function '~=' has unsafe type 'T'}}
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+
}

0 commit comments

Comments
 (0)