[embedded] Allow string-interpolating fatalError in Embedded Swift

This commit is contained in:
Kuba Mracek
2025-02-24 11:15:06 -08:00
parent 62dc762c20
commit 01d7e231c3
6 changed files with 97 additions and 2 deletions

View File

@@ -275,7 +275,6 @@ public func preconditionFailure(
/// - line: The line number to print along with `message`. The default is the
/// line number where `fatalError(_:file:line:)` is called.
@_transparent
@_unavailableInEmbedded
#if $Embedded
@_disfavoredOverload
#endif
@@ -283,8 +282,19 @@ public func fatalError(
_ message: @autoclosure () -> String = String(),
file: StaticString = #file, line: UInt = #line
) -> Never {
#if !$Embedded
_assertionFailure("Fatal error", message(), file: file, line: line,
flags: _fatalErrorFlags())
#else
if _isDebugAssertConfiguration() {
_assertionFailure("Fatal error", message(), file: file, line: line,
flags: _fatalErrorFlags())
} else {
Builtin.condfail_message(true._value,
StaticString("fatal error").unsafeRawPointer)
Builtin.unreachable()
}
#endif
}
#if $Embedded

View File

@@ -134,15 +134,16 @@ internal func _assertionFailure(
#if !$Embedded
@inline(never)
#else
@_disfavoredOverload
@inline(__always)
#endif
@_semantics("programtermination_point")
@_unavailableInEmbedded
internal func _assertionFailure(
_ prefix: StaticString, _ message: String,
file: StaticString, line: UInt,
flags: UInt32
) -> Never {
#if !$Embedded
prefix.withUTF8Buffer {
(prefix) -> Void in
var message = message
@@ -158,6 +159,14 @@ internal func _assertionFailure(
}
}
}
#else
if _isDebugAssertConfiguration() {
var message = message
message.withUTF8 { (messageUTF8) -> Void in
_embeddedReportFatalErrorInFile(prefix: prefix, message: messageUTF8, file: file, line: line)
}
}
#endif
Builtin.int_trap()
}

View File

@@ -63,6 +63,17 @@ public func print(_ object: some CustomStringConvertible, terminator: StaticStri
}
}
func print(_ buf: UnsafeBufferPointer<UInt8>, terminator: StaticString = "\n") {
for c in buf {
putchar(CInt(c))
}
var p = terminator.utf8Start
while p.pointee != 0 {
putchar(CInt(p.pointee))
p += 1
}
}
func printCharacters(_ buf: UnsafeRawBufferPointer) {
for unsafe c in unsafe buf {
putchar(CInt(c))

View File

@@ -527,6 +527,7 @@ public func swift_clearSensitive(buf: UnsafeMutableRawPointer, nbytes: Int) {
}
@usableFromInline
@inline(never)
func _embeddedReportFatalError(prefix: StaticString, message: StaticString) {
print(prefix, terminator: "")
if message.utf8CodeUnitCount > 0 { print(": ", terminator: "") }
@@ -534,6 +535,7 @@ func _embeddedReportFatalError(prefix: StaticString, message: StaticString) {
}
@usableFromInline
@inline(never)
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: StaticString, file: StaticString, line: UInt) {
print(file, terminator: ":")
print(line, terminator: ": ")
@@ -541,3 +543,13 @@ func _embeddedReportFatalErrorInFile(prefix: StaticString, message: StaticString
if message.utf8CodeUnitCount > 0 { print(": ", terminator: "") }
print(message)
}
@usableFromInline
@inline(never)
func _embeddedReportFatalErrorInFile(prefix: StaticString, message: UnsafeBufferPointer<UInt8>, file: StaticString, line: UInt) {
print(file, terminator: ":")
print(line, terminator: ": ")
print(prefix, terminator: "")
if message.count > 0 { print(": ", terminator: "") }
print(message)
}

View File

@@ -0,0 +1,33 @@
// RUN: %empty-directory(%t)
// RUN: %target-clang -x c -c %S/Inputs/unbuffered-putchar.c -o %t/unbuffered-putchar.o
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -O
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-NOMESSAGE
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -Osize
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-NOMESSAGE
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -O -assert-config Debug
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
// RUN: %target-build-swift -enable-experimental-feature Embedded -wmo -runtime-compatibility-version none %s -Xlinker %t/unbuffered-putchar.o -o %t/a.out -Osize -assert-config Debug
// RUN: not --crash %t/a.out 2>&1 | %FileCheck %s --check-prefix=CHECK-MESSAGE
// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: OS=macosx || OS=linux-gnu
// REQUIRES: swift_test_mode_optimize_none
// REQUIRES: swift_feature_Embedded
func testWithInterpolation(i: Int) {
fatalError("task failed successfully \(i)")
// CHECK-MESSAGE: {{.*}}/traps-fatalerror-exec2.swift:[[@LINE-1]]: Fatal error: task failed successfully 42
// CHECK-NOMESSAGE-NOT: Fatal error
// CHECK-NOMESSAGE-NOT: task failed successfully 42
}
testWithInterpolation(i: 42)

View File

@@ -27,3 +27,23 @@ public func test() {
// CHECK-NOMESSAGE-NEXT: tail call void @llvm.trap()
// CHECK-NOMESSAGE-NEXT: unreachable
// CHECK-NOMESSAGE-NEXT: }
public func testWithInterpolation(i: Int) {
fatalError("task failed successfully \(i)")
}
// CHECK-MESSAGE: define {{.*}}void @"$e4main21testWithInterpolation1iySi_tF"(i64 %0){{.*}} {
// CHECK-MESSAGE: entry:
// CHECK-MESSAGE: task failed successfully
// CHECK-MESSAGE: {{.*}}call {{.*}}void @"${{(es17_assertionFailure__|es31_embeddedReportFatalErrorInFile6prefix7message4file4lineys12StaticStringV_SRys5UInt8VGAGSutF)}}
// CHECK-MESSAGE-SAME: Fatal error
// CHECK-MESSAGE-SAME: traps-fatalerror-ir.swift
// CHECK-MESSAGE: unreachable
// CHECK-MESSAGE: }
// CHECK-NOMESSAGE: define {{.*}}void @"$e4main21testWithInterpolation1iySi_tF"(i64 %0){{.*}} {
// CHECK-NOMESSAGE-NEXT: entry:
// CHECK-NOMESSAGE-NEXT: tail call void asm sideeffect "", "n"(i32 0)
// CHECK-NOMESSAGE-NEXT: tail call void @llvm.trap()
// CHECK-NOMESSAGE-NEXT: unreachable
// CHECK-NOMESSAGE-NEXT: }