mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
328 lines
6.9 KiB
Swift
328 lines
6.9 KiB
Swift
// RUN: %target-swift-frontend -emit-sil -primary-file %s -o /dev/null -verify
|
|
func ifFalse() -> Int {
|
|
if false { // expected-note {{always evaluates to false}}
|
|
return 0 // expected-warning {{will never be executed}}
|
|
} else {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
func ifTrue() -> Int {
|
|
_ = 0
|
|
if true { // expected-note {{always evaluates to true}}
|
|
return 1
|
|
}
|
|
return 0 // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
// Work-around <rdar://problem/17687851> by ensuring there is
|
|
// something that appears to be user code in unreachable blocks.
|
|
func userCode() {}
|
|
|
|
func whileTrue() {
|
|
var x = 0
|
|
while true { // expected-note {{always evaluates to true}}
|
|
x += 1
|
|
}
|
|
userCode() // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
func whileTrueSilent() {
|
|
while true {
|
|
}
|
|
} // no warning!
|
|
|
|
func whileTrueReachable(_ v: Int) -> () {
|
|
var x = 0
|
|
while true {
|
|
if v == 0 {
|
|
break
|
|
}
|
|
x += 1
|
|
}
|
|
x -= 1
|
|
}
|
|
|
|
func whileTrueTwoPredecessorsEliminated() -> () {
|
|
var x = 0
|
|
while (true) { // expected-note {{always evaluates to true}}
|
|
if false {
|
|
break
|
|
}
|
|
x += 1
|
|
}
|
|
userCode() // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
func unreachableBranch() -> Int {
|
|
if false { // expected-note {{always evaluates to false}}
|
|
// FIXME: It'd be nice if the warning were on 'if true' instead of the
|
|
// body.
|
|
if true {
|
|
return 0 // expected-warning {{will never be executed}}
|
|
}
|
|
} else {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
// We should not report unreachable user code inside inlined transparent function.
|
|
@_transparent
|
|
func ifTrueTransparent(_ b: Bool) -> Int {
|
|
_ = 0
|
|
if b {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
func testIfTrueTransparent() {
|
|
_ = ifTrueTransparent(true) // no-warning
|
|
_ = ifTrueTransparent(false) // no-warning
|
|
}
|
|
|
|
// We should not report unreachable user code inside generic instantiations.
|
|
// TODO: This test should start failing after we add support for generic
|
|
// specialization in SIL. To fix it, add generic instantiation detection
|
|
// within the DeadCodeElimination pass to address the corresponding FIXME note.
|
|
protocol HavingGetCond {
|
|
func getCond() -> Bool
|
|
}
|
|
struct ReturnsTrue : HavingGetCond {
|
|
func getCond() -> Bool { return true }
|
|
}
|
|
struct ReturnsOpaque : HavingGetCond {
|
|
var b: Bool
|
|
func getCond() -> Bool { return b }
|
|
}
|
|
func ifTrueGeneric<T : HavingGetCond>(_ x: T) -> Int {
|
|
if x.getCond() {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
func testIfTrueGeneric(_ b1: ReturnsOpaque, b2: ReturnsTrue) {
|
|
_ = ifTrueGeneric(b1) // no-warning
|
|
_ = ifTrueGeneric(b2) // no-warning
|
|
}
|
|
|
|
// Test switch_enum folding/diagnostic.
|
|
enum X {
|
|
case One
|
|
case Two
|
|
case Three
|
|
}
|
|
|
|
func testSwitchEnum(_ xi: Int) -> Int {
|
|
var x = xi
|
|
let cond: X = .Two
|
|
switch cond { // expected-warning {{switch condition evaluates to a constant}}
|
|
case .One:
|
|
userCode() // expected-note {{will never be executed}}
|
|
case .Two:
|
|
x -= 1
|
|
case .Three:
|
|
x -= 1
|
|
}
|
|
|
|
switch cond { // no warning
|
|
default:
|
|
x += 1
|
|
}
|
|
|
|
switch cond { // expected-warning{{switch condition evaluates to a constant}}
|
|
case .Two:
|
|
x += 1
|
|
default:
|
|
userCode() // expected-note{{will never be executed}}
|
|
}
|
|
|
|
switch cond { // expected-warning{{switch condition evaluates to a constant}}
|
|
case .One:
|
|
userCode() // expected-note{{will never be executed}}
|
|
default:
|
|
x -= 1
|
|
}
|
|
|
|
return x
|
|
}
|
|
|
|
@_silgen_name("exit") func exit() -> Never
|
|
|
|
func reachableThroughNonFoldedPredecessor(fn: @autoclosure () -> Bool = false) {
|
|
if !_fastPath(fn()) {
|
|
exit()
|
|
}
|
|
var _: Int = 0 // no warning
|
|
}
|
|
|
|
func intConstantTest() -> Int{
|
|
let y: Int = 1
|
|
if y == 1 { // expected-note {{condition always evaluates to true}}
|
|
return y
|
|
}
|
|
|
|
return 1 // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
func intConstantTest2() -> Int{
|
|
let y:Int = 1
|
|
let x:Int = y
|
|
|
|
if x != 1 { // expected-note {{condition always evaluates to false}}
|
|
return y // expected-warning {{will never be executed}}
|
|
}
|
|
return 3
|
|
}
|
|
|
|
func test_single_statement_closure(_ fn:() -> ()) {}
|
|
test_single_statement_closure() {
|
|
exit() // no-warning
|
|
}
|
|
|
|
class C { }
|
|
class Super {
|
|
var s = C()
|
|
deinit { // no-warning
|
|
}
|
|
}
|
|
class D : Super {
|
|
var c = C()
|
|
deinit { // no-warning
|
|
exit()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// <rdar://problem/20097963> incorrect DI diagnostic in unreachable code
|
|
enum r20097963Test {
|
|
case A
|
|
case B
|
|
}
|
|
|
|
class r20097963MyClass {
|
|
func testStr(_ t: r20097963Test) -> String {
|
|
let str: String
|
|
switch t {
|
|
case .A:
|
|
str = "A"
|
|
case .B:
|
|
str = "B"
|
|
default: // expected-warning {{default will never be executed}}
|
|
str = "unknown" // Should not be rejected.
|
|
}
|
|
return str
|
|
}
|
|
}
|
|
|
|
func die() -> Never { die() }
|
|
|
|
func testGuard(_ a : Int) {
|
|
guard case 4 = a else { } // expected-error {{'guard' body may not fall through, consider using a 'return' or 'throw'}}
|
|
|
|
guard case 4 = a else { return } // ok
|
|
guard case 4 = a else { die() } // ok
|
|
guard case 4 = a else { fatalError("baaad") } // ok
|
|
|
|
for _ in 0...100 {
|
|
guard case 4 = a else { continue } // ok
|
|
}
|
|
}
|
|
|
|
func testFailingCast(_ s:String) -> Int {
|
|
// There should be no notes or warnings about a call to a noreturn function, because we do not expose
|
|
// how casts are lowered.
|
|
return s as! Int // expected-warning {{cast from 'String' to unrelated type 'Int' always fails}}
|
|
}
|
|
|
|
enum MyError : Error { case A }
|
|
|
|
func raise() throws -> Never { throw MyError.A }
|
|
|
|
func test_raise_1() throws -> Int {
|
|
try raise()
|
|
}
|
|
|
|
func test_raise_2() throws -> Int {
|
|
try raise() // expected-note {{a call to a never-returning function}}
|
|
try raise() // expected-warning {{will never be executed}}
|
|
}
|
|
|
|
// If a guaranteed self call requires cleanup, don't warn about
|
|
// release instructions
|
|
struct Algol {
|
|
var x: [UInt8]
|
|
|
|
func fail() throws -> Never { throw MyError.A }
|
|
|
|
mutating func blah() throws -> Int {
|
|
try fail() // no-warning
|
|
}
|
|
}
|
|
|
|
class Lisp {
|
|
func fail() throws -> Never { throw MyError.A }
|
|
}
|
|
|
|
func transform<Scheme : Lisp>(_ s: Scheme) throws {
|
|
try s.fail() // no-warning
|
|
}
|
|
|
|
func deferNoReturn() throws {
|
|
defer {
|
|
_ = Lisp() // no-warning
|
|
}
|
|
|
|
die()
|
|
}
|
|
|
|
func deferTryNoReturn() throws {
|
|
defer {
|
|
_ = Lisp() // no-warning
|
|
}
|
|
|
|
try raise()
|
|
}
|
|
|
|
func noReturnInDefer() {
|
|
defer {
|
|
_ = Lisp()
|
|
die() // expected-note {{a call to a never-returning function}}
|
|
die() // expected-warning {{will never be executed}}
|
|
}
|
|
}
|
|
|
|
while true {
|
|
}
|
|
// no warning!
|
|
|
|
|
|
// SR-1010 - rdar://25278336 - Spurious "will never be executed" warnings when building standard library
|
|
struct SR1010<T> {
|
|
var a : T
|
|
}
|
|
|
|
extension SR1010 {
|
|
@available(*, unavailable, message: "use the 'enumerated()' method on the sequence")
|
|
init(_ base: Int) {
|
|
fatalError("unavailable function can't be called")
|
|
}
|
|
}
|
|
|
|
// More spurious 'will never be executed' warnings
|
|
struct FailingStruct {
|
|
init?(x: ()) {
|
|
fatalError("gotcha")
|
|
}
|
|
}
|
|
|
|
class FailingClass {
|
|
init?(x: ()) {
|
|
fatalError("gotcha")
|
|
}
|
|
|
|
convenience init?(y: ()) {
|
|
fatalError("gotcha")
|
|
}
|
|
}
|