FrontendTool: Stop if SILGen emits diagnostics even when lazy type checking is off

We've had several bugs lately where SILGen produces a diagnostic,
but the resulting invalid SIL causes crashes further down in the
mandatory pipeline. To prevent this from happening, just stop after
SILGen if diagnostics were emitted, even if lazy type checking is
disabled, because the same rationale applies in either case.
This commit is contained in:
Slava Pestov
2026-01-13 09:18:22 -05:00
parent 95bd190c54
commit 5bcdcd1fa6
8 changed files with 83 additions and 62 deletions

View File

@@ -2053,11 +2053,11 @@ static bool performCompileStepsPostSILGen(
return writeSIL(*SM, PSPs, Instance, Invocation.getSILOptions());
}
// In lazy typechecking mode, SILGen may have triggered requests which
// resulted in errors. We don't want to proceed with optimization or
// serialization if there were errors since the SIL may be incomplete or
// invalid.
if (Context.TypeCheckerOpts.EnableLazyTypecheck && Context.hadError())
// SILGen emits certain diagnostics of its own, and it can also trigger
// requests which result in errors. We don't want to proceed with
// optimization or serialization if there were errors since the SIL
// may be incomplete or invalid.
if (!Context.LangOpts.AllowModuleWithCompilerErrors && Context.hadError())
return true;
if (Action == FrontendOptions::ActionType::EmitSIBGen) {

View File

@@ -0,0 +1,46 @@
// RUN: %target-swift-frontend -enforce-exclusivity=checked -swift-version 4 -emit-sil -primary-file %s -o /dev/null -verify
import Swift
func takesTwoInouts<T>(_ p1: inout T, _ p2: inout T) { }
func simpleInoutDiagnostic() {
var i = 7
// FIXME: This diagnostic should be removed if static enforcement is
// turned on by default.
// expected-error@+2{{inout arguments are not allowed to alias each other}}
// expected-note@+1{{previous aliasing argument}}
takesTwoInouts(&i, &i)
}
func inoutOnInoutParameter(p: inout Int) {
// expected-error@+2{{inout arguments are not allowed to alias each other}}
// expected-note@+1{{previous aliasing argument}}
takesTwoInouts(&p, &p)
}
class SomeClass { }
struct StructWithMutatingMethodThatTakesSelfInout {
var f = SomeClass()
mutating func mutate(_ other: inout StructWithMutatingMethodThatTakesSelfInout) { }
mutating func mutate(_ other: inout SomeClass) { }
mutating func callMutatingMethodThatTakesSelfInout() {
// expected-error@+2{{inout arguments are not allowed to alias each other}}
// expected-note@+1{{previous aliasing argument}}
mutate(&self)
}
mutating func callMutatingMethodThatTakesSelfStoredPropInout() {
mutate(&self.f)
}
}
func violationWithGenericType<T>(_ p: T) {
var local = p
// expected-error@+2{{inout arguments are not allowed to alias each other}}
// expected-note@+1{{previous aliasing argument}}
takesTwoInouts(&local, &local)
}

View File

@@ -0,0 +1,13 @@
// RUN: %target-swift-frontend -enable-experimental-move-only -verify %s -emit-silgen
func useValue<T>(_ x: T) {}
func consumeValue<T>(_ x: __owned T) {}
struct GenericAggregate<T> {
var value: T
}
func test1<T>(_ x: T) {
@_noImplicitCopy let x2 = x // expected-error {{'@_noImplicitCopy' can not be used on a generic or existential typed binding or a nominal type containing such typed things}}
_ = x2
}

View File

@@ -1,31 +1,14 @@
// RUN: %target-swift-emit-sil -verify %s
// RUN: %target-swift-frontend -emit-sil -verify %s
// RUN: %target-swift-emit-silgen -verify %s
struct Block {}
class Story {
final var finalStored = [Block]()
var overridableStored = [Block]()
var computed: [Block] {
get { return [] }
set {}
}
func test() {
// expected-error@+2 {{overlapping accesses to 'finalStored', but modification requires exclusive access; consider calling MutableCollection.swapAt(_:_:)}}
// expected-note@+1 {{conflicting access is here}}
swap(&self.finalStored[0], &self.finalStored[1])
swap(&self.overridableStored[0], &self.overridableStored[1])
swap(&self.computed[0], &self.computed[1]) // expected-error{{invalid aliasing}} expected-note{{concurrent writeback}}
}
}
protocol Storied {
var protocolRequirement: [Block] { get set }
}
func testProtocol<T: Storied>(x: inout T) {
// expected-error@+2 {{overlapping accesses to 'x', but modification requires exclusive access; consider calling MutableCollection.swapAt(_:_:)}}
// expected-note@+1 {{conflicting access is here}}
swap(&x.protocolRequirement[0], &x.protocolRequirement[1])
}

View File

@@ -4,26 +4,6 @@ import Swift
func takesTwoInouts<T>(_ p1: inout T, _ p2: inout T) { }
func simpleInoutDiagnostic() {
var i = 7
// FIXME: This diagnostic should be removed if static enforcement is
// turned on by default.
// expected-error@+4{{inout arguments are not allowed to alias each other}}
// expected-note@+3{{previous aliasing argument}}
// expected-error@+2{{overlapping accesses to 'i', but modification requires exclusive access; consider copying to a local variable}}
// expected-note@+1{{conflicting access is here}}
takesTwoInouts(&i, &i)
}
func inoutOnInoutParameter(p: inout Int) {
// expected-error@+4{{inout arguments are not allowed to alias each other}}
// expected-note@+3{{previous aliasing argument}}
// expected-error@+2{{overlapping accesses to 'p', but modification requires exclusive access; consider copying to a local variable}}
// expected-note@+1{{conflicting access is here}}
takesTwoInouts(&p, &p)
}
func swapNoSuppression(_ i: Int, _ j: Int) {
var a: [Int] = [1, 2, 3]
@@ -39,14 +19,6 @@ struct StructWithMutatingMethodThatTakesSelfInout {
mutating func mutate(_ other: inout StructWithMutatingMethodThatTakesSelfInout) { }
mutating func mutate(_ other: inout SomeClass) { }
mutating func callMutatingMethodThatTakesSelfInout() {
// expected-error@+4{{inout arguments are not allowed to alias each other}}
// expected-note@+3{{previous aliasing argument}}
// expected-error@+2{{overlapping accesses to 'self', but modification requires exclusive access; consider copying to a local variable}}
// expected-note@+1{{conflicting access is here}}
mutate(&self)
}
mutating func callMutatingMethodThatTakesSelfStoredPropInout() {
// expected-error@+2{{overlapping accesses to 'self', but modification requires exclusive access; consider copying to a local variable}}
// expected-note@+1{{conflicting access is here}}
@@ -81,16 +53,6 @@ class ClassWithFinalStoredProp {
}
}
func violationWithGenericType<T>(_ p: T) {
var local = p
// expected-error@+4{{inout arguments are not allowed to alias each other}}
// expected-note@+3{{previous aliasing argument}}
// expected-error@+2{{overlapping accesses to 'local', but modification requires exclusive access; consider copying to a local variable}}
// expected-note@+1{{conflicting access is here}}
takesTwoInouts(&local, &local)
}
// Helper.
struct StructWithTwoStoredProp {
var f1: Int = 7

View File

@@ -1,5 +1,7 @@
// RUN: %target-swift-frontend -enable-experimental-move-only -verify %s -emit-sil
// REQUIRES: rdar168066916
func useValue<T>(_ x: T) {}
func consumeValue<T>(_ x: __owned T) {}

View File

@@ -0,0 +1,15 @@
// RUN: %target-swift-emit-sil -verify %s
struct Block {}
class Story {
final var finalStored = [Block]()
var overridableStored = [Block]()
func test() {
// expected-error@+2 {{overlapping accesses to 'finalStored', but modification requires exclusive access; consider calling MutableCollection.swapAt(_:_:)}}
// expected-note@+1 {{conflicting access is here}}
swap(&self.finalStored[0], &self.finalStored[1])
swap(&self.overridableStored[0], &self.overridableStored[1])
}
}

View File

@@ -1,5 +1,5 @@
// {"kind":"emit-sil","languageMode":6,"signature":"swift::regionanalysisimpl::BlockPartitionState::recomputeExitFromEntry(swift::regionanalysisimpl::PartitionOpTranslator&)","signatureAssert":"Assertion failed: (p.isTrackingElement(op.getOpArg1()) && \"Require PartitionOp's argument should already be tracked\"), function apply"}
// RUN: not --crash %target-swift-frontend -emit-sil -swift-version 6 %s
// RUN: not %target-swift-frontend -emit-sil -swift-version 6 %s
func a<b>(d: b) {
var e = 0
let d: @convention(c) () -> Void = {