diff --git a/include/swift/AST/DiagnosticGroups.def b/include/swift/AST/DiagnosticGroups.def index 77829a0c71542..00212a0a5f518 100644 --- a/include/swift/AST/DiagnosticGroups.def +++ b/include/swift/AST/DiagnosticGroups.def @@ -72,6 +72,7 @@ GROUP(TemporaryPointers, "temporary-pointers") GROUP(TrailingClosureMatching, "trailing-closure-matching") GROUP(UnknownWarningGroup, "unknown-warning-group") GROUP(CompilationCaching, "compilation-caching") +GROUP(WeakMutability, "weak-mutability") #define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS #include "swift/AST/DefineDiagnosticGroupsMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index d0ae00504ae86..f6a9b20a5e079 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7414,6 +7414,14 @@ WARNING(variable_tuple_elt_never_mutated, none, "variable %0 was never mutated; " "consider changing the pattern to 'case (..., let %1, ...)'", (Identifier, StringRef)) +GROUPED_WARNING(weak_variable_never_mutated, WeakMutability, none, + "weak variable %0 was never mutated; " + "consider %select{removing 'var' to make it|changing to 'let'}1 constant", + (Identifier, bool)) +GROUPED_WARNING(weak_variable_tuple_elt_never_mutated, WeakMutability, none, + "weak variable %0 was never mutated; " + "consider changing the pattern to 'case (..., let %1, ...)'", + (Identifier, StringRef)) WARNING(variable_never_read, none, "variable %0 was written to, but never read", (Identifier)) diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index ecdc13cfd0043..01e66e1eb1324 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -713,7 +713,12 @@ class alignas(1 << PatternAlignInBits) StmtConditionElement { /// or `let self = self` condition. /// - If `requiresCaptureListRef` is `true`, additionally requires that the /// RHS of the self condition references a var defined in a capture list. - bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const; + /// - If `requireLoadExpr` is `true`, additionally requires that the RHS of + /// the self condition is a `LoadExpr`. + /// TODO: Remove `requireLoadExpr` after full-on of the ImmutableWeakCaptures + /// feature + bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false, + bool requireLoadExpr = false) const; SourceLoc getStartLoc() const; SourceLoc getEndLoc() const; @@ -822,7 +827,8 @@ class LabeledConditionalStmt : public LabeledStmt { /// or `let self = self` condition. /// - If `requiresCaptureListRef` is `true`, additionally requires that the /// RHS of the self condition references a var defined in a capture list. - bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false) const; + bool rebindsSelf(ASTContext &Ctx, bool requiresCaptureListRef = false, + bool requireLoadExpr = false) const; static bool classof(const Stmt *S) { return S->getKind() >= StmtKind::First_LabeledConditionalStmt && diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 07dd05eda36c3..8b7f9cc0bfa75 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -296,6 +296,7 @@ UPCOMING_FEATURE(InternalImportsByDefault, 409, 7) MIGRATABLE_UPCOMING_FEATURE(MemberImportVisibility, 444, 7) MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7) MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7) +UPCOMING_FEATURE(ImmutableWeakCaptures, 481, 7) // Optional language features / modes diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 02e23fd9b26d4..85136687ead44 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1373,8 +1373,11 @@ CaptureListEntry CaptureListEntry::createParsed( SourceRange ownershipRange, Identifier name, SourceLoc nameLoc, SourceLoc equalLoc, Expr *initializer, DeclContext *DC) { + bool forceVar = ownershipKind == ReferenceOwnership::Weak && + !Ctx.LangOpts.hasFeature(Feature::ImmutableWeakCaptures); + auto introducer = forceVar ? VarDecl::Introducer::Var : VarDecl::Introducer::Let; auto *VD = - new (Ctx) VarDecl(/*isStatic==*/false, VarDecl::Introducer::Let, nameLoc, name, DC); + new (Ctx) VarDecl(/*isStatic==*/false, introducer, nameLoc, name, DC); if (ownershipKind != ReferenceOwnership::Strong) VD->getAttrs().add( diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index b32d11e1d2351..ff155a5b09803 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -441,6 +441,7 @@ UNINTERESTING_FEATURE(BuiltinSelect) UNINTERESTING_FEATURE(BuiltinInterleave) UNINTERESTING_FEATURE(BuiltinVectorsExternC) UNINTERESTING_FEATURE(AddressOfProperty2) +UNINTERESTING_FEATURE(ImmutableWeakCaptures) // ---------------------------------------------------------------------------- // MARK: - FeatureSet diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index d2a7289d2ee8d..5810226fcff89 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -515,9 +515,11 @@ void LabeledConditionalStmt::setCond(StmtCondition e) { /// - If `requiresCaptureListRef` is `true`, additionally requires that the /// RHS of the self condition references a var defined in a capture list. bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx, - bool requiresCaptureListRef) const { - return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef](const auto &cond) { - return cond.rebindsSelf(Ctx, requiresCaptureListRef); + bool requiresCaptureListRef, + bool requireLoadExpr) const { + return llvm::any_of(getCond(), [&Ctx, requiresCaptureListRef, + requireLoadExpr](const auto &cond) { + return cond.rebindsSelf(Ctx, requiresCaptureListRef, requireLoadExpr); }); } @@ -526,7 +528,8 @@ bool LabeledConditionalStmt::rebindsSelf(ASTContext &Ctx, /// - If `requiresCaptureListRef` is `true`, additionally requires that the /// RHS of the self condition references a var defined in a capture list. bool StmtConditionElement::rebindsSelf(ASTContext &Ctx, - bool requiresCaptureListRef) const { + bool requiresCaptureListRef, + bool requireLoadExpr) const { auto pattern = getPatternOrNull(); if (!pattern) { return false; @@ -554,6 +557,10 @@ bool StmtConditionElement::rebindsSelf(ASTContext &Ctx, return false; } + if (requireLoadExpr && !isa(exprToCheckForDRE)) { + return false; + } + if (auto *load = dyn_cast(exprToCheckForDRE)) { exprToCheckForDRE = load->getSubExpr(); } diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index 3824e50e2c96e..eb655a7d984bd 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -170,6 +170,15 @@ CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture, return CaptureKind::StorageAddress; } + // Reference storage types can appear in a capture list, which means + // we might allocate boxes to store the captures. However, those boxes + // have the same lifetime as the closure itself, so we must capture + // the box itself and not the payload, even if the closure is noescape, + // otherwise they will be destroyed when the closure is formed. + if (var->getInterfaceType()->is()) { + return CaptureKind::Box; + } + // For 'let' constants if (!var->supportsMutation()) { assert(getTypeProperties( diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 53ecf77936725..bec232181616c 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -1781,23 +1781,34 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker { return false; } - // Require that the RHS of the `let self = self` condition - // refers to a variable defined in a capture list. - // This lets us reject invalid examples like: - // - // var `self` = self ?? .somethingElse - // guard let self = self else { return } - // method() // <- implicit self is not allowed - // - // In 5.10, instead of this check, compiler was checking that RHS of the - // self binding is loaded from a mutable variable. This is incorrect, but - // before SE-0481 compiler was trying to maintain this behavior in Swift 5 - // mode for source compatibility. After SE-0481 this does not work - // anymore, because even in Swift 5 mode `weak self` capture is not mutable. - // So we have to introduce a breaking change as part of the SE-0481, and use - // proper check for capture list even in Swift 5 mode. - // - return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true); + if (Ctx.LangOpts.hasFeature(Feature::ImmutableWeakCaptures)) { + // Require that the RHS of the `let self = self` condition + // refers to a variable defined in a capture list. + // This lets us reject invalid examples like: + // + // var `self` = self ?? .somethingElse + // guard let self = self else { return } + // method() // <- implicit self is not allowed + // + // In 5.10, instead of this check, compiler was checking that RHS of the + // self binding is loaded from a mutable variable. This is incorrect, but + // before immutable weak captures compiler was trying to maintain this + // behavior in Swift 5 mode for source compatibility. With immutable weak + // captures this does not work anymore, because even in Swift 5 mode there + // is no `LoadExpr` to use. + // + return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ true); + } else { + // Require `LoadExpr`s when validating the self binding. + // This lets us reject invalid examples like: + // + // let `self` = self ?? .somethingElse + // guard let self = self else { return } + // method() // <- implicit self is not allowed + // + return conditionalStmt->rebindsSelf(Ctx, /*requiresCaptureListRef*/ false, + /*requireLoadExpr*/ true); + } } static bool @@ -4093,6 +4104,14 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { access &= ~RK_Written; } + // If this variable has WeakStorageType, then it can be mutated in ways we + // don't know. + if (var->getInterfaceType()->is() && + (access & RK_CaptureList) && + !DC->getASTContext().LangOpts.hasFeature( + Feature::ImmutableWeakCaptures)) + access |= RK_Written; + // Diagnose variables that were never used (other than their // initialization). // @@ -4263,6 +4282,8 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { if (isUsedInInactive(var)) continue; + bool isWeak = var->getInterfaceType()->is(); + // If this is a parameter explicitly marked 'var', remove it. if (FixItLoc.isInvalid()) { bool suggestCaseLet = false; @@ -4273,10 +4294,14 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { suggestCaseLet = isa(stmt); } if (suggestCaseLet) - Diags.diagnose(var->getLoc(), diag::variable_tuple_elt_never_mutated, + Diags.diagnose(var->getLoc(), + isWeak ? diag::weak_variable_tuple_elt_never_mutated + : diag::variable_tuple_elt_never_mutated, var->getName(), var->getNameStr()); else - Diags.diagnose(var->getLoc(), diag::variable_never_mutated, + Diags.diagnose(var->getLoc(), + isWeak ? diag::weak_variable_never_mutated + : diag::variable_never_mutated, var->getName(), true); } @@ -4289,7 +4314,9 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { suggestLet = !isa(stmt); } - auto diag = Diags.diagnose(var->getLoc(), diag::variable_never_mutated, + auto diag = Diags.diagnose(var->getLoc(), + isWeak ? diag::weak_variable_never_mutated + : diag::variable_never_mutated, var->getName(), suggestLet); if (suggestLet) diff --git a/test/Concurrency/weak_ref_sendability.swift b/test/Concurrency/weak_ref_sendability.swift index 6b91bf7defe3f..f0c6f9abdc5c4 100644 --- a/test/Concurrency/weak_ref_sendability.swift +++ b/test/Concurrency/weak_ref_sendability.swift @@ -1,16 +1,19 @@ -// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix old- %s -o /dev/null +// RUN: %target-swift-frontend -emit-sil -swift-version 6 -target %target-swift-5.1-abi-triple -verify -verify-additional-prefix new- -enable-upcoming-feature ImmutableWeakCaptures %s -o /dev/null // This test validates the behavior of transfer non sendable around ownership // constructs like non copyable types, consuming/borrowing parameters, and inout // parameters. // REQUIRES: concurrency +// REQUIRES: swift_feature_ImmutableWeakCaptures final class S: Sendable { func foo() {} } -// expected-note@+1 12{{class 'NS' does not conform to the 'Sendable' protocol}} +// expected-old-note@+2 13{{class 'NS' does not conform to the 'Sendable' protocol}} +// expected-new-note@+1 12{{class 'NS' does not conform to the 'Sendable' protocol}} final class NS { func bar() {} } @@ -19,8 +22,10 @@ func getS() -> S { S() } func getNS() -> NS { NS() } final class CheckOptionality1: Sendable { - // expected-error@+2 {{'weak' variable should have optional type 'S?'}} - // expected-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}} + // expected-old-error@+4 {{'weak' variable should have optional type 'S?'}} + // expected-old-error@+3 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}} + // expected-new-error@+2 {{'weak' variable should have optional type 'S?'}} + // expected-new-error@+1 {{stored property 'x' of 'Sendable'-conforming class 'CheckOptionality1' is mutable}} weak var x: S = getS() } @@ -93,7 +98,7 @@ final class CheckSendability12: Sendable { func checkWeakCapture1(_ strongRef: S) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}} + // expected-warning@+1 {{weak variable 'weakRef' was never mutated; consider changing to 'let' constant}} weak var weakRef: S? = strongRef return { // expected-error@+1 {{reference to captured var 'weakRef' in concurrently-executing code}} @@ -113,13 +118,13 @@ func checkWeakCapture3(_ strongRef: S) -> @Sendable () -> Void { // TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed // See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910 weakRef?.foo() - // expected-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}} weakRef = nil } } func checkWeakCapture4(_ strongRef: NS) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'weakRef' was never mutated; consider changing to 'let' constant}} + // expected-warning@+1 {{weak variable 'weakRef' was never mutated; consider changing to 'let' constant}} weak var weakRef: NS? = strongRef return { // expected-error@+2 {{capture of 'weakRef' with non-Sendable type 'NS?' in a '@Sendable' closure}} @@ -138,10 +143,11 @@ func checkWeakCapture5(_ strongRef: NS) -> @Sendable () -> Void { func checkWeakCapture6(_ strongRef: NS) -> @Sendable () -> Void { return { [weak weakRef = strongRef] in + // expected-old-error@+3 {{capture of 'weakRef' with non-Sendable type 'NS?' in a '@Sendable' closure}} // For some reason the next error masks this error. // This case is split into two, to verify that when unmasked error is triggered. weakRef?.bar() - // expected-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'weakRef' is an immutable capture}} weakRef = nil } } @@ -154,10 +160,12 @@ func checkWeakCapture7(_ strongRef: NS) -> @Sendable () -> Void { } func checkUnownedCapture1(_ strongRef: S) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} unowned var unownedRef: S = strongRef return { - // expected-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}} + // expected-old-error@+2 {{reference to captured var 'unownedRef' in concurrently-executing code}} + // expected-new-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}} unownedRef.foo() } } @@ -171,14 +179,18 @@ func checkUnownedCapture2(_ strongRef: S) -> @Sendable () -> Void { func checkUnownedCapture3(_ strongRef: S) -> @Sendable () -> Void { return { [unowned unownedRef = strongRef] in + // TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed + // See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910 unownedRef.foo() - // expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} unownedRef = strongRef } } func checkUnownedCapture4(_ strongRef: NS) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} unowned var unownedRef: NS = strongRef return { // expected-error@+2 {{capture of 'unownedRef' with non-Sendable type 'NS' in a '@Sendable' closure}} @@ -200,7 +212,8 @@ func checkUnownedCapture6(_ strongRef: NS) -> @Sendable () -> Void { // For some reason the next error masks this error. // This case is split into two, to verify that when unmasked error is triggered. unownedRef.bar() - // expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} unownedRef = strongRef } } @@ -213,10 +226,12 @@ func checkUnownedCapture7(_ strongRef: NS) -> @Sendable () -> Void { } func checkUnsafeCapture1(_ strongRef: S) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} unowned(unsafe) var unownedRef: S = strongRef return { - // expected-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}} + // expected-old-error@+2 {{reference to captured var 'unownedRef' in concurrently-executing code}} + // expected-new-error@+1 {{reference to captured var 'unownedRef' in concurrently-executing code}} unownedRef.foo() } } @@ -230,14 +245,18 @@ func checkUnsafeCapture2(_ strongRef: S) -> @Sendable () -> Void { func checkUnsafeCapture3(_ strongRef: S) -> @Sendable () -> Void { return { [unowned(unsafe) unownedRef = strongRef] in + // TODO: Add expected old error, when https://github.com/swiftlang/swift/issues/80014 is fixed + // See also https://forums.swift.org/t/lets-debug-missing-rbi-data-race-diagnostics/78910 unownedRef.foo() - // expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} unownedRef = strongRef } } func checkUnsafeCapture4(_ strongRef: NS) -> @Sendable () -> Void { - // expected-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-old-warning@+2 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} + // expected-new-warning@+1 {{variable 'unownedRef' was never mutated; consider changing to 'let' constant}} unowned(unsafe) var unownedRef: NS = strongRef return { // expected-error@+2 {{capture of 'unownedRef' with non-Sendable type 'NS' in a '@Sendable' closure}} @@ -259,7 +278,8 @@ func checkUnsafeCapture6(_ strongRef: NS) -> @Sendable () -> Void { // For some reason the next error masks this error. // This case is split into two, to verify that when unmasked error is triggered. unownedRef.bar() - // expected-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-old-error@+2 {{cannot assign to value: 'unownedRef' is an immutable capture}} + // expected-new-error@+1 {{cannot assign to value: 'unownedRef' is an immutable capture}} unownedRef = strongRef } } diff --git a/test/DebugInfo/WeakCapture.swift b/test/DebugInfo/WeakCapture.swift index b3c86fdd54c42..d67839d5053b6 100644 --- a/test/DebugInfo/WeakCapture.swift +++ b/test/DebugInfo/WeakCapture.swift @@ -1,4 +1,8 @@ // RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -enable-upcoming-feature ImmutableWeakCaptures -emit-ir -g -o - | %FileCheck %s + +// REQUIRES: swift_feature_ImmutableWeakCaptures + class A { init(handler: (() -> ())) { } } diff --git a/test/DebugInfo/guard-let-scope4.swift b/test/DebugInfo/guard-let-scope4.swift index 5578f22f04d2a..22f36d691dddb 100644 --- a/test/DebugInfo/guard-let-scope4.swift +++ b/test/DebugInfo/guard-let-scope4.swift @@ -1,14 +1,14 @@ // RUN: %target-swift-frontend -g -Xllvm -sil-print-types -emit-sil %s -parse-as-library -module-name a | %FileCheck %s +// RUN: %target-swift-frontend -g -Xllvm -sil-print-types -emit-sil %s -parse-as-library -module-name a -enable-upcoming-feature ImmutableWeakCaptures | %FileCheck %s --check-prefixes=CHECK,CHECK-HAS-WEAK-LET +// REQUIRES: swift_feature_ImmutableWeakCaptures open class C { - public func fun() {} - public func run() { { [weak self] in guard let self else { fatalError("cannot happen") } // CHECK: sil_scope [[LAMBDA:[0-9]+]] { loc "{{.*}}":6:5 // CHECK: sil_scope [[BODY:[0-9]+]] { loc "{{.*}}":6:19 parent [[LAMBDA]] // CHECK: sil_scope [[LET:[0-9]+]] { loc "{{.*}}":7:7 parent [[BODY]] - // CHECK: sil_scope [[TMP:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]] + // CHECK-HAS-WEAK-LET: sil_scope [[TMP:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]] // CHECK: sil_scope [[GUARD:[0-9]+]] { loc "{{.*}}":7:17 parent [[LET]] // CHECK: debug_value {{.*}} : $C, let, name "self", {{.*}}, scope [[GUARD]] // CHECK: function_ref {{.*}}3fun{{.*}}, scope [[GUARD]] @@ -16,4 +16,8 @@ open class C { self.fun() }() } + public func fun() {} } + + + diff --git a/test/DebugInfo/weak-self-capture.swift b/test/DebugInfo/weak-self-capture.swift index 600ddbff0bb54..0daf9a8309480 100644 --- a/test/DebugInfo/weak-self-capture.swift +++ b/test/DebugInfo/weak-self-capture.swift @@ -1,4 +1,8 @@ // RUN: %target-swift-frontend %s -emit-ir -g -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -enable-upcoming-feature ImmutableWeakCaptures -emit-ir -g -o - | %FileCheck %s + +// REQUIRES: swift_feature_ImmutableWeakCaptures + public class ClosureMaker { var a : Int diff --git a/test/Interpreter/weak.swift b/test/Interpreter/weak.swift index 1bb85df5ad85e..7390809fde835 100644 --- a/test/Interpreter/weak.swift +++ b/test/Interpreter/weak.swift @@ -1,5 +1,8 @@ // RUN: %target-run-simple-swift | %FileCheck %s +// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-feature -Xfrontend ImmutableWeakCaptures) | %FileCheck %s --check-prefixes=CHECK + // REQUIRES: executable_test +// REQUIRES: swift_feature_ImmutableWeakCaptures protocol Protocol : class { func noop() diff --git a/test/Interpreter/weak_objc.swift b/test/Interpreter/weak_objc.swift index 08131601a32ea..72ccead84d643 100644 --- a/test/Interpreter/weak_objc.swift +++ b/test/Interpreter/weak_objc.swift @@ -1,8 +1,14 @@ // RUN: %target-build-swift %s -Xfrontend -disable-objc-attr-requires-foundation-module -o %t-main // RUN: %target-codesign %t-main // RUN: %target-run %t-main | %FileCheck %s + +// RUN: %target-build-swift %s -Xfrontend -disable-objc-attr-requires-foundation-module -enable-upcoming-feature ImmutableWeakCaptures -o %t-main-weak-let +// RUN: %target-codesign %t-main-weak-let +// RUN: %target-run %t-main-weak-let | %FileCheck %s --check-prefixes=CHECK,CHECK-WEAK-LET + // REQUIRES: executable_test // REQUIRES: objc_interop +// REQUIRES: swift_feature_ImmutableWeakCaptures import Foundation @@ -49,27 +55,27 @@ func testObjCClass() { testObjCClass() func testObjCWeakLet() { - print("testObjCWeakLet") // CHECK: testObjCWeakLet + print("testObjCWeakLet") // CHECK-WEAK-LET: testObjCWeakLet - var c : ObjCClassBase = ObjCClass() // CHECK: ObjCClass Created + var c : ObjCClassBase = ObjCClass() // CHECK-WEAK-LET: ObjCClass Created weak let w : ObjCClassBase? = c - printState(w) // CHECK-NEXT: is present - c = ObjCClassBase() // CHECK-NEXT: ObjCClass Destroyed - printState(w) // CHECK-NEXT: is nil + printState(w) // CHECK-WEAK-LET-NEXT: is present + c = ObjCClassBase() // CHECK-WEAK-LET-NEXT: ObjCClass Destroyed + printState(w) // CHECK-WEAK-LET-NEXT: is nil } testObjCWeakLet() func testObjCWeakLetCapture() { - print("testObjCWeakLetCapture") // CHECK: testObjCWeakLetCapture + print("testObjCWeakLetCapture") // CHECK-WEAK-LET: testObjCWeakLetCapture - var c : ObjCClassBase = ObjCClass() // CHECK: ObjCClass Created + var c : ObjCClassBase = ObjCClass() // CHECK-WEAK-LET: ObjCClass Created let closure: () -> ObjCClassBase? = { [weak c] in c } - printState(closure()) // CHECK-NEXT: is present - printState(closure()) // CHECK-NEXT: is present - c = ObjCClassBase() // CHECK-NEXT: ObjCClass Destroyed - printState(closure()) // CHECK-NEXT: is nil - printState(closure()) // CHECK-NEXT: is nil + printState(closure()) // CHECK-WEAK-LET-NEXT: is present + printState(closure()) // CHECK-WEAK-LET-NEXT: is present + c = ObjCClassBase() // CHECK-WEAK-LET-NEXT: ObjCClass Destroyed + printState(closure()) // CHECK-WEAK-LET-NEXT: is nil + printState(closure()) // CHECK-WEAK-LET-NEXT: is nil } testObjCWeakLetCapture() diff --git a/test/SILGen/capture-transitive.swift b/test/SILGen/capture-transitive.swift index 39ca3e0fe88c1..fb90b7516f93d 100644 --- a/test/SILGen/capture-transitive.swift +++ b/test/SILGen/capture-transitive.swift @@ -1,4 +1,7 @@ -// RUN: %target-swift-emit-silgen %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s | %FileCheck %s --check-prefixes=CHECK,CHECK-NO-WEAK-LET +// RUN: %target-swift-emit-silgen -enable-upcoming-feature ImmutableWeakCaptures %s | %FileCheck %s --check-prefixes=CHECK,CHECK-HAS-WEAK-LET + +// REQUIRES: swift_feature_ImmutableWeakCaptures // https://github.com/apple/swift/issues/50924 @@ -31,7 +34,7 @@ class C { func returnsSelf1() -> Self { return { [weak self] in self?.f(); return .init() }() - // CHECK-LABEL: sil private [ossa] @{{.*}}returnsSelf{{.*}} : $@convention(thin) (@in_guaranteed @sil_weak Optional, @thick @dynamic_self C.Type) -> @owned C { + // CHECK-LABEL: sil private [ossa] @{{.*}}returnsSelf{{.*}} : $@convention(thin) (@guaranteed { var @sil_weak Optional }, @thick @dynamic_self C.Type) -> @owned C } func returnsSelf2() -> Self { diff --git a/test/SILGen/capture_order.swift b/test/SILGen/capture_order.swift index 7081bcbcbca2f..1e5e08d7f4b08 100644 --- a/test/SILGen/capture_order.swift +++ b/test/SILGen/capture_order.swift @@ -1,4 +1,6 @@ -// RUN: %target-swift-emit-silgen %s -verify +// RUN: %target-swift-emit-silgen -enable-upcoming-feature ImmutableWeakCaptures %s -verify + +// REQUIRES: swift_feature_ImmutableWeakCaptures /// We emit an invalid forward capture as an 'undef'; make sure /// we cover the various possible cases. diff --git a/test/SILGen/dynamic_self.swift b/test/SILGen/dynamic_self.swift index 287bd0e098b11..c437432dd4204 100644 --- a/test/SILGen/dynamic_self.swift +++ b/test/SILGen/dynamic_self.swift @@ -1,10 +1,12 @@ -// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 4 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s -// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 4 -O %s -disable-objc-attr-requires-foundation-module -enable-objc-interop -// RUN: %target-swift-emit-ir -swift-version 4 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop +// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 4 -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s +// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 4 -O -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop +// RUN: %target-swift-emit-ir -swift-version 4 -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop -// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s -// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 5 -O %s -disable-objc-attr-requires-foundation-module -enable-objc-interop -// RUN: %target-swift-emit-ir -swift-version 5 %s -disable-objc-attr-requires-foundation-module -enable-objc-interop +// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop | %FileCheck %s +// RUN: %target-swift-emit-sil -Xllvm -sil-print-types -swift-version 5 -O -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop +// RUN: %target-swift-emit-ir -swift-version 5 -enable-upcoming-feature ImmutableWeakCaptures %s -disable-objc-attr-requires-foundation-module -enable-objc-interop + +// REQUIRES: swift_feature_ImmutableWeakCaptures protocol P { func f() -> Self @@ -239,12 +241,10 @@ class Z { // CHECK: [[WEAK_SELF:%.*]] = alloc_box ${ var @sil_weak Optional } // CHECK: [[WEAK_SELF_LIFETIME:%.*]] = begin_borrow [lexical] [var_decl] [[WEAK_SELF]] - // CHECK: [[WEAK_SELF_ADDR:%.*]] = project_box [[WEAK_SELF_LIFETIME]] : ${ var @sil_weak Optional }, 0 - // CHECK: [[FN:%.*]] = function_ref @$s12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU1_ : $@convention(thin) (@in_guaranteed @sil_weak Optional, @thick @dynamic_self Z.Type) -> () - // CHECK: [[WEAK_SELF_COPY:%.*]] = alloc_stack $@sil_weak Optional - // CHECK: copy_addr [[WEAK_SELF_ADDR]] to [init] [[WEAK_SELF_COPY]] : $*@sil_weak Optional + // CHECK: [[FN:%.*]] = function_ref @$s12dynamic_self1ZC23testDynamicSelfCaptures1xACXDSi_tFyycfU1_ : $@convention(thin) (@guaranteed { var @sil_weak Optional }, @thick @dynamic_self Z.Type) -> () + // CHECK: [[WEAK_SELF_COPY:%.*]] = copy_value [[WEAK_SELF_LIFETIME]] : ${ var @sil_weak Optional } // CHECK-NEXT: [[DYNAMIC_SELF:%.*]] = metatype $@thick @dynamic_self Z.Type - // CHECK: partial_apply [callee_guaranteed] [[FN]]([[WEAK_SELF_COPY]], [[DYNAMIC_SELF]]) : $@convention(thin) (@in_guaranteed @sil_weak Optional, @thick @dynamic_self Z.Type) -> () + // CHECK: partial_apply [callee_guaranteed] [[FN]]([[WEAK_SELF_COPY]], [[DYNAMIC_SELF]]) : $@convention(thin) (@guaranteed { var @sil_weak Optional }, @thick @dynamic_self Z.Type) -> () let fn3 = { [weak self] in _ = self @@ -427,7 +427,7 @@ class Derived : Base { class Generic { // Examples where we have to add a special argument to capture Self's metadata func t1() -> Self { - // CHECK-LABEL: sil private [ossa] @$s12dynamic_self7GenericC2t1ACyxGXDyFAEXDSgycfU_ : $@convention(thin) (@in_guaranteed @sil_weak Optional>, @thick @dynamic_self Generic.Type) -> @owned Optional> + // CHECK-LABEL: sil private [ossa] @$s12dynamic_self7GenericC2t1ACyxGXDyFAEXDSgycfU_ : $@convention(thin) (@guaranteed <τ_0_0> { var @sil_weak Optional> } , @thick @dynamic_self Generic.Type) -> @owned Optional> _ = {[weak self] in self } return self } diff --git a/test/SILGen/unowned-class-bound-generic-parameter.swift b/test/SILGen/unowned-class-bound-generic-parameter.swift index 144592fa639f7..f2755390982a4 100644 --- a/test/SILGen/unowned-class-bound-generic-parameter.swift +++ b/test/SILGen/unowned-class-bound-generic-parameter.swift @@ -8,7 +8,7 @@ func makeGenericClosureWithUnknownClass(t: T) where T : ClassProtocol { _ = { [unowned t] in _ = t } } -// CHECK-LABEL: sil private [ossa] @$s4main34makeGenericClosureWithUnknownClass1tyx_tAA0G8ProtocolRzlFyycfU_ : $@convention(thin) (@in_guaranteed @sil_unowned T) -> () { +// CHECK-LABEL: sil private [ossa] @$s4main34makeGenericClosureWithUnknownClass1tyx_tAA0G8ProtocolRzlFyycfU_ : $@convention(thin) (@guaranteed <τ_0_0 where τ_0_0 : ClassProtocol> { var @sil_unowned τ_0_0 } ) -> () { func makeGenericClosureWithNativeClass1(t: T) where T : BaseClass { _ = { [unowned t] in _ = t } diff --git a/test/SILGen/weak.swift b/test/SILGen/weak.swift index f03d4622ce985..0e3a6f5f9276a 100644 --- a/test/SILGen/weak.swift +++ b/test/SILGen/weak.swift @@ -1,4 +1,3 @@ - // RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -module-name weak -Xllvm -sil-full-demangle %s | %FileCheck %s class C { diff --git a/test/SILOptimizer/definite_init_diagnostics.swift b/test/SILOptimizer/definite_init_diagnostics.swift index 4983a2c9435d3..7de0b0b56a3e2 100644 --- a/test/SILOptimizer/definite_init_diagnostics.swift +++ b/test/SILOptimizer/definite_init_diagnostics.swift @@ -103,7 +103,7 @@ func test2() { // Weak - // expected-warning @+1 {{variable 'w1' was never mutated; consider changing to 'let' constant}} {{8-11=let}} + // expected-warning@+1 {{weak variable 'w1' was never mutated; consider changing to 'let' constant}} {{8-11=let}} weak var w1 : SomeClass? _ = w1 // ok: default-initialized diff --git a/test/Sema/diag_unowned_immediate_deallocation.swift b/test/Sema/diag_unowned_immediate_deallocation.swift index 5a1f8ec1935d6..315a23c9e989c 100644 --- a/test/Sema/diag_unowned_immediate_deallocation.swift +++ b/test/Sema/diag_unowned_immediate_deallocation.swift @@ -1,4 +1,6 @@ -// RUN: %target-typecheck-verify-swift -module-name ModuleName +// RUN: %target-typecheck-verify-swift -module-name ModuleName -enable-upcoming-feature ImmutableWeakCaptures + +// REQUIRES: swift_feature_ImmutableWeakCaptures protocol ClassProtocol : class { init() diff --git a/test/decl/var/properties.swift b/test/decl/var/properties.swift index 5996cd555da3d..783dfb6cd38ac 100644 --- a/test/decl/var/properties.swift +++ b/test/decl/var/properties.swift @@ -114,10 +114,11 @@ var x15: Int { // For the purpose of this test we need to use an attribute that cannot be // applied to the getter. weak - var foo: SomeClass? = SomeClass() // expected-warning {{variable 'foo' was never used; consider replacing with '_' or removing it}} - // expected-warning@-1 {{instance will be immediately deallocated because variable 'foo' is 'weak'}} - // expected-note@-2 {{a strong reference is required to prevent the instance from being deallocated}} - // expected-note@-3 {{'foo' declared here}} + var foo: SomeClass? = SomeClass() + // expected-warning@-1 {{variable 'foo' was never used; consider replacing with '_' or removing it}} + // expected-warning@-2 {{instance will be immediately deallocated because variable 'foo' is 'weak'}} + // expected-note@-3 {{a strong reference is required to prevent the instance from being deallocated}} + // expected-note@-4 {{'foo' declared here}} return 0 } diff --git a/test/decl/var/variables.swift b/test/decl/var/variables.swift index a108f75d6f1c7..f6f2d88a6d7f5 100644 --- a/test/decl/var/variables.swift +++ b/test/decl/var/variables.swift @@ -87,6 +87,7 @@ var shouldWarnWithoutSugar = (arrayOfEmptyTuples as Array<()>) // expected-warni class SomeClass {} + weak let V = SomeClass() // ok since SE-0481 // expected-warning@-1 {{instance will be immediately deallocated because variable 'V' is 'weak'}} // expected-note@-2 {{'V' declared here}} diff --git a/test/expr/closure/closures.swift b/test/expr/closure/closures.swift index 72bf38a208057..8e13cfd346726 100644 --- a/test/expr/closure/closures.swift +++ b/test/expr/closure/closures.swift @@ -1,4 +1,7 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking +// RUN: %target-typecheck-verify-swift -disable-availability-checking -verify-additional-prefix no-weak-let- +// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-upcoming-feature ImmutableWeakCaptures -verify-additional-prefix has-weak-let- + +// REQUIRES: swift_feature_ImmutableWeakCaptures var func6 : (_ fn : (Int,Int) -> Int) -> () var func6a : ((Int, Int) -> Int) -> () @@ -262,12 +265,29 @@ class ExplicitSelfRequiredTest { // because its `sawError` flag is set to true. To preserve the "capture 'y' was never used" warnings // above, we put these cases in their own method. func weakSelfError() { - doVoidStuff({ [weak self] in x += 1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} - doVoidStuffNonEscaping({ [weak self] in x += 1 }) // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} - doStuff({ [weak self] in x+1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} - doVoidStuff({ [weak self] in _ = method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} - doVoidStuffNonEscaping({ [weak self] in _ = method() }) // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} - doStuff({ [weak self] in method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-warning {{capture 'self' was never used}} + doVoidStuff({ [weak self] in x += 1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} + + doVoidStuffNonEscaping({ [weak self] in x += 1 }) // expected-warning {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} + + doStuff({ [weak self] in x+1 }) // expected-error {{reference to property 'x' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} + + doVoidStuff({ [weak self] in _ = method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} + + doVoidStuffNonEscaping({ [weak self] in _ = method() }) // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} + + doStuff({ [weak self] in method() }) // expected-error {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-warning@-1 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@-2 {{capture 'self' was never used}} } } @@ -374,7 +394,8 @@ extension SomeClass { //expected-error@-3{{reference to property 'in' in closure requires explicit use of 'self' to make capture semantics explicit}} //expected-note@-4{{reference 'self.' explicitly}} - // expected-warning @+1 {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} doStuff { [weak self&field] in 42 } // expected-error {{expected ']' at end of capture list}} } @@ -1522,22 +1543,30 @@ final class AutoclosureTests { withEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } - - doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}} + + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + doVoidStuff { [weak self] in withNonEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } - - doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}} + + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + doVoidStuff { [weak self] in withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } - - doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}} + + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + doVoidStuff { [weak self] in doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} withNonEscapingAutoclosure(bar()) // expected-error {{all to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } } - - doVoidStuff { [weak self] in // expected-warning {{capture 'self' was never used}} + + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + doVoidStuff { [weak self] in doVoidStuff { withEscapingAutoclosure(bar()) // expected-error {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} expected-note {{reference 'self.' explicitly}} } @@ -1604,7 +1633,13 @@ final class AutoclosureTests { let someOptional: Self? = Self() var `self` = self ?? someOptional // expected-warning {{'self' was never mutated; consider changing to 'let' constant}} guard let self = self else { return } - method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} +#if hasFeature(ImmutableWeakCaptures) + method() // expected-has-weak-let-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} +#else + // This is not supposed to be permitted, but has been allowed since Swift 5.8, + // so we have to continue allowing it to maintain source compatibility. + method() +#endif } doVoidStuff { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} @@ -1770,13 +1805,17 @@ class rdar129475277 { func method() {} func test1() { - takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + takesEscapingWithAllowedImplicitSelf { [weak self] in takesEscapingWithAllowedImplicitSelf { method() // expected-warning {{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}} } } - takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + takesEscapingWithAllowedImplicitSelf { [weak self] in takesEscapingWithAllowedImplicitSelf { doVoidStuffNonEscaping { withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} @@ -1784,7 +1823,9 @@ class rdar129475277 { } } - takesEscapingWithAllowedImplicitSelf { [weak self] in // expected-warning {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + takesEscapingWithAllowedImplicitSelf { [weak self] in withNonEscapingAutoclosure(bar()) // expected-warning {{call to method 'bar' in closure requires explicit use of 'self' to make capture semantics explicit}} } } @@ -1817,7 +1858,9 @@ class TestExtensionOnOptionalSelf { extension TestExtensionOnOptionalSelf? { func foo() { - _ = { [weak self] in // expected-warning {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + _ = { [weak self] in foo() // expected-error {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} } @@ -1825,7 +1868,9 @@ extension TestExtensionOnOptionalSelf? { foo() } - _ = { [weak self] in // expected-warning {{capture 'self' was never used}} + // expected-no-weak-let-warning@+2 {{variable 'self' was written to, but never read}} + // expected-has-weak-let-warning@+1 {{capture 'self' was never used}} + _ = { [weak self] in _ = { foo() } diff --git a/test/expr/closure/closures_swift6.swift b/test/expr/closure/closures_swift6.swift index d1234eec05094..18859b75848f1 100644 --- a/test/expr/closure/closures_swift6.swift +++ b/test/expr/closure/closures_swift6.swift @@ -1,4 +1,12 @@ -// RUN: %target-typecheck-verify-swift -swift-version 6 +// There seems to be a minor bug in the diagnostic of the self-capture. +// Diagnostic algorithm does not @lvalue DeclRefExpr wrapped into LoadExpr, +// and enabling ImmutableWeakCaptures removes the LoadExpr. +// As a result, diagnostic messages change slightly. + +// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix no-weak-let- +// RUN: %target-typecheck-verify-swift -swift-version 6 -verify-additional-prefix has-weak-let- -enable-upcoming-feature ImmutableWeakCaptures + +// REQUIRES: swift_feature_ImmutableWeakCaptures func doStuff(_ fn : @escaping () -> Int) {} func doVoidStuff(_ fn : @escaping () -> ()) {} @@ -936,7 +944,8 @@ class TestExtensionOnOptionalSelf { extension TestExtensionOnOptionalSelf? { func foo() { _ = { [weak self] in - // expected-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-error@+2 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} + // expected-has-weak-let-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} foo() } @@ -947,9 +956,10 @@ extension TestExtensionOnOptionalSelf? { } _ = { [weak self] in - _ = { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - // expected-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} - // expected-note@+1 {{reference 'self.' explicitly}} + _ = { // expected-has-weak-let-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} + // expected-no-weak-let-error@+3 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} + // expected-has-weak-let-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-has-weak-let-note@+1 {{reference 'self.' explicitly}} foo() self.foo() self?.bar() @@ -970,7 +980,8 @@ extension TestExtensionOnOptionalSelf? { extension TestExtensionOnOptionalSelf { func foo() { _ = { [weak self] in - // expected-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-no-weak-let-error@+2 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} + // expected-has-weak-let-error@+1 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} foo() self.foo() self?.bar() @@ -982,9 +993,10 @@ extension TestExtensionOnOptionalSelf { } _ = { [weak self] in - _ = { // expected-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} - // expected-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} - // expected-note@+1 {{reference 'self.' explicitly}} + _ = { // expected-has-weak-let-note {{capture 'self' explicitly to enable implicit 'self' in this closure}} + // expected-no-weak-let-error@+3 {{implicit use of 'self' in closure; use 'self.' to make capture semantics explicit}} + // expected-has-weak-let-error@+2 {{call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit}} + // expected-has-weak-let-note@+1 {{reference 'self.' explicitly}} foo() self.foo() } diff --git a/test/expr/closure/implicit_weak_capture.swift b/test/expr/closure/implicit_weak_capture.swift index 08475c21d0eeb..870d90505e013 100644 --- a/test/expr/closure/implicit_weak_capture.swift +++ b/test/expr/closure/implicit_weak_capture.swift @@ -1,7 +1,9 @@ // RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -swift-version 6) +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -swift-version 6 -enable-upcoming-feature ImmutableWeakCaptures) // REQUIRES: concurrency // REQUIRES: executable_test +// REQUIRES: swift_feature_ImmutableWeakCaptures // rdar://102155748 // UNSUPPORTED: back_deployment_runtime diff --git a/test/stdlib/WeakMirror.swift b/test/stdlib/WeakMirror.swift index 7a1e165273326..baefe1451b718 100644 --- a/test/stdlib/WeakMirror.swift +++ b/test/stdlib/WeakMirror.swift @@ -14,9 +14,9 @@ // RUN: if [ %target-runtime == "objc" ]; \ // RUN: then \ // RUN: %target-clang %S/Inputs/Mirror/Mirror.mm -c -o %t/Mirror.mm.o -g && \ -// RUN: %target-build-swift -Xfrontend -disable-access-control %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \ +// RUN: %target-build-swift -Xfrontend -disable-access-control -Xfrontend -enable-experimental-feature -Xfrontend ImmutableWeakCaptures %s -I %S/Inputs/Mirror/ -Xlinker %t/Mirror.mm.o -o %t/Mirror; \ // RUN: else \ -// RUN: %target-build-swift %s -Xfrontend -disable-access-control -o %t/Mirror; \ +// RUN: %target-build-swift %s -Xfrontend -disable-access-control -Xfrontend -enable-experimental-feature -Xfrontend ImmutableWeakCaptures -o %t/Mirror; \ // RUN: fi // RUN: %target-codesign %t/Mirror // RUN: %target-run %t/Mirror @@ -24,6 +24,7 @@ // REQUIRES: executable_test // REQUIRES: shell // REQUIRES: reflection +// REQUIRES: swift_feature_ImmutableWeakCaptures import StdlibUnittest