From 771e9b522eb9620267b10c798804759c5810ba12 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Sat, 13 Sep 2025 18:00:57 -0700 Subject: [PATCH] Lifetimes: add a diagnostic note for implicit accessors Lifetime diagnostics may report an error within an implicit initializer or accessor. The source location is misleading in these cases and causes much consternation. --- .../LifetimeDependenceDiagnostics.swift | 18 ++++++++++++++++++ .../Sources/SIL/Function.swift | 12 ++++++++++++ include/swift/AST/DiagnosticsSIL.def | 2 ++ include/swift/SIL/SILBridging.h | 3 +++ include/swift/SIL/SILBridgingImpl.h | 15 +++++++++++++++ 5 files changed, 50 insertions(+) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift index ec92036c60de3..b7bd49bb7923a 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift @@ -284,6 +284,7 @@ private struct DiagnoseDependence { diagnose(sourceLoc, .lifetime_value_outside_thunk, thunkSelect, function.name) } } + diagnoseImplicitFunction() reportScope() // Identify the use point. if let userSourceLoc = operand.instruction.location.sourceLoc { @@ -323,6 +324,23 @@ private struct DiagnoseDependence { } } } + + func diagnoseImplicitFunction() { + guard let funcLoc = function.location.sourceLoc else { + return + } + if let kindName = { + if function.isInitializer { + return "init" + } + if function.isDeinitializer { + return "deinit" + } + return function.accessorKindName + }() { + diagnose(funcLoc, .implicit_function_note, kindName) + } + } } // Identify a best-effort variable declaration based on a defining SIL diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift index a802984455223..45122979f77f9 100644 --- a/SwiftCompilerSources/Sources/SIL/Function.swift +++ b/SwiftCompilerSources/Sources/SIL/Function.swift @@ -267,6 +267,18 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash return StringRef(bridged: bridged.getAccessorName()).string } + public var isInitializer: Bool { + return bridged.isInitializer() + } + + public var isDeinitializer: Bool { + return bridged.isDeinitializer() + } + + public var isImplicit: Bool { + return bridged.isImplicit() + } + /// True, if the function runs with a swift 5.1 runtime. /// Note that this is function specific, because inlinable functions are de-serialized /// in a client module, which might be compiled with a different deployment target. diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index b2f29be6beff1..0b744c0debd19 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -1240,6 +1240,8 @@ NOTE(lifetime_outside_scope_use, none, NOTE(lifetime_outside_scope_escape, none, "this use causes the lifetime-dependent value to escape", ()) +NOTE(implicit_function_note, none, "error in compiler-generated '%0'", (StringRef)) + ERROR(noncopyable_shared_case_block_unimplemented, none, "matching a non-'Copyable' value using a case label that has multiple patterns is not implemented", ()) diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 4384c1132fcff..7b1e63f25570c 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -509,6 +509,9 @@ struct BridgedFunction { BridgedOwnedString getDebugDescription() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedLocation getLocation() const; BRIDGED_INLINE bool isAccessor() const; + BRIDGED_INLINE bool isInitializer() const; + BRIDGED_INLINE bool isDeinitializer() const; + BRIDGED_INLINE bool isImplicit() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getAccessorName() const; BRIDGED_INLINE bool hasOwnership() const; BRIDGED_INLINE bool hasLoweredAddresses() const; diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index e5c031d7fbf45..44ed0dbf7b94c 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -701,6 +701,21 @@ BridgedStringRef BridgedFunction::getAccessorName() const { return accessorKindName(accessorDecl->getAccessorKind()); } +bool BridgedFunction::isInitializer() const { + return getFunction()->getDeclRef().isConstructor(); +} + +bool BridgedFunction::isDeinitializer() const { + return getFunction()->getDeclRef().isDestructor(); +} + +bool BridgedFunction::isImplicit() const { + if (auto *funcDecl = getFunction()->getDeclRef().getAbstractFunctionDecl()) { + return funcDecl->isImplicit(); + } + return false; +} + bool BridgedFunction::hasOwnership() const { return getFunction()->hasOwnership(); } bool BridgedFunction::hasLoweredAddresses() const { return getFunction()->getModule().useLoweredAddresses(); }