diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ef4f58b3a76e6..c3761464f9008 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -390,6 +390,17 @@ namespace swift { return limitBehaviorUntilSwiftVersion(limit, languageMode); } + /// Limit the diagnostic behavior to warning until the next future + /// language mode. + /// + /// This should be preferred over passing the next major version to + /// `warnUntilSwiftVersion` to make it easier to find and update clients + /// when a new language mode is introduced. + /// + /// This helps stage in fixes for stricter diagnostics as warnings + /// until the next major language version. + InFlightDiagnostic &warnUntilFutureSwiftVersion(); + /// Limit the diagnostic behavior to warning until the specified version. /// /// This helps stage in fixes for stricter diagnostics as warnings diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 5579cf818cdd7..2d052da7ce819 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -267,7 +267,7 @@ class alignas(8) Expr : public ASTAllocated { Kind : 2 ); - SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1, /// True if closure parameters were synthesized from anonymous closure /// variables. HasAnonymousClosureVars : 1, @@ -295,7 +295,12 @@ class alignas(8) Expr : public ASTAllocated { /// isolation checks when it either specifies or inherits isolation /// and was passed as an argument to a function that is not fully /// concurrency checked. - RequiresDynamicIsolationChecking : 1 + RequiresDynamicIsolationChecking : 1, + + /// Whether this closure was type-checked as an argument to a macro. This + /// is only populated after type-checking, and only exists for diagnostic + /// logic. Do not add more uses of this. + IsMacroArgument : 1 ); SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16, @@ -4316,6 +4321,7 @@ class ClosureExpr : public AbstractClosureExpr { Bits.ClosureExpr.IsPassedToSendingParameter = false; Bits.ClosureExpr.NoGlobalActorAttribute = false; Bits.ClosureExpr.RequiresDynamicIsolationChecking = false; + Bits.ClosureExpr.IsMacroArgument = false; } SourceRange getSourceRange() const; @@ -4394,6 +4400,17 @@ class ClosureExpr : public AbstractClosureExpr { Bits.ClosureExpr.RequiresDynamicIsolationChecking = value; } + /// Whether this closure was type-checked as an argument to a macro. This + /// is only populated after type-checking, and only exists for diagnostic + /// logic. Do not add more uses of this. + bool isMacroArgument() const { + return Bits.ClosureExpr.IsMacroArgument; + } + + void setIsMacroArgument(bool value = true) { + Bits.ClosureExpr.IsMacroArgument = value; + } + /// Determine whether this closure expression has an /// explicitly-specified result type. bool hasExplicitResultType() const { return ArrowLoc.isValid(); } diff --git a/include/swift/Basic/Version.h b/include/swift/Basic/Version.h index 092a4e626e518..a97ef7eec93b2 100644 --- a/include/swift/Basic/Version.h +++ b/include/swift/Basic/Version.h @@ -131,6 +131,13 @@ class Version { /// SWIFT_VERSION_MINOR. static Version getCurrentLanguageVersion(); + /// Returns a major version to represent the next future language mode. This + /// exists to make it easier to find and update clients when a new language + /// mode is added. + static constexpr unsigned getFutureMajorLanguageVersion() { + return 7; + } + // List of backward-compatibility versions that we permit passing as // -swift-version static std::array getValidEffectiveVersions() { diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 5e8c5054a8461..7ac3e7166d441 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -452,7 +452,7 @@ InFlightDiagnostic::limitBehaviorUntilSwiftVersion( // version. We do this before limiting the behavior, because // wrapIn will result in the behavior of the wrapping diagnostic. if (limit >= DiagnosticBehavior::Warning) { - if (majorVersion > 6) { + if (majorVersion >= version::Version::getFutureMajorLanguageVersion()) { wrapIn(diag::error_in_a_future_swift_lang_mode); } else { wrapIn(diag::error_in_swift_lang_mode, majorVersion); @@ -472,6 +472,11 @@ InFlightDiagnostic::limitBehaviorUntilSwiftVersion( return *this; } +InFlightDiagnostic &InFlightDiagnostic::warnUntilFutureSwiftVersion() { + using namespace version; + return warnUntilSwiftVersion(Version::getFutureMajorLanguageVersion()); +} + InFlightDiagnostic & InFlightDiagnostic::warnUntilSwiftVersion(unsigned majorVersion) { return limitBehaviorUntilSwiftVersion(DiagnosticBehavior::Warning, diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 94085bf601654..13eb04be0db84 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -181,16 +181,19 @@ std::optional Version::getEffectiveLanguageVersion() const { static_assert(SWIFT_VERSION_MAJOR == 6, "getCurrentLanguageVersion is no longer correct here"); return Version::getCurrentLanguageVersion(); - case 7: - // Allow version '7' in asserts compilers *only* so that we can start - // testing changes planned for after Swift 6. Note that it's still not - // listed in `Version::getValidEffectiveVersions()`. - // FIXME: When Swift 7 becomes real, remove 'REQUIRES: swift7' from tests - // using '-swift-version 7'. + + // FIXME: When Swift 7 becomes real, remove 'REQUIRES: swift7' from tests + // using '-swift-version 7'. + + case Version::getFutureMajorLanguageVersion(): + // Allow the future language mode version in asserts compilers *only* so + // that we can start testing changes planned for after the current latest + // language mode. Note that it'll not be listed in + // `Version::getValidEffectiveVersions()`. #ifdef NDEBUG LLVM_FALLTHROUGH; #else - return Version{7}; + return Version{Version::getFutureMajorLanguageVersion()}; #endif default: return std::nullopt; diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c8e910c4661ee..56bfa85819ded 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5612,6 +5612,18 @@ namespace { E->setMacroRef(macroRef); E->setType(expandedType); + auto fnType = + simplifyType(overload.adjustedOpenedType)->castTo(); + + auto newArgs = coerceCallArguments( + E->getArgs(), fnType, macroRef, /*applyExpr=*/nullptr, + cs.getConstraintLocator(E, ConstraintLocator::ApplyArgument), + solution.getAppliedPropertyWrappers(E)); + if (!newArgs) + return nullptr; + + E->setArgs(newArgs); + // FIXME: Expansion should be lazy. // i.e. 'ExpandMacroExpansionExprRequest' should be sinked into // 'getRewritten()', and performed on-demand. Unfortunately that requires @@ -6073,13 +6085,15 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee, static void applyContextualClosureFlags(Expr *expr, bool implicitSelfCapture, bool inheritActorContext, bool isPassedToSendingParameter, - bool requiresDynamicIsolationChecking) { + bool requiresDynamicIsolationChecking, + bool isMacroArg) { if (auto closure = dyn_cast(expr)) { closure->setAllowsImplicitSelfCapture(implicitSelfCapture); closure->setInheritsActorContext(inheritActorContext); closure->setIsPassedToSendingParameter(isPassedToSendingParameter); closure->setRequiresDynamicIsolationChecking( requiresDynamicIsolationChecking); + closure->setIsMacroArgument(isMacroArg); return; } @@ -6087,14 +6101,16 @@ static void applyContextualClosureFlags(Expr *expr, bool implicitSelfCapture, applyContextualClosureFlags(captureList->getClosureBody(), implicitSelfCapture, inheritActorContext, isPassedToSendingParameter, - requiresDynamicIsolationChecking); + requiresDynamicIsolationChecking, + isMacroArg); } if (auto identity = dyn_cast(expr)) { applyContextualClosureFlags(identity->getSubExpr(), implicitSelfCapture, inheritActorContext, isPassedToSendingParameter, - requiresDynamicIsolationChecking); + requiresDynamicIsolationChecking, + isMacroArg); } } @@ -6219,7 +6235,8 @@ ArgumentList *ExprRewriter::coerceCallArguments( }(); auto applyFlagsToArgument = [¶mInfo, - &closuresRequireDynamicIsolationChecking]( + &closuresRequireDynamicIsolationChecking, + &locator]( unsigned paramIdx, Expr *argument) { if (!isClosureLiteralExpr(argument)) return; @@ -6227,11 +6244,13 @@ ArgumentList *ExprRewriter::coerceCallArguments( bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx); bool inheritsActorContext = paramInfo.inheritsActorContext(paramIdx); bool isPassedToSendingParameter = paramInfo.isSendingParameter(paramIdx); + bool isMacroArg = isExpr(locator.getAnchor()); applyContextualClosureFlags(argument, isImplicitSelfCapture, inheritsActorContext, isPassedToSendingParameter, - closuresRequireDynamicIsolationChecking); + closuresRequireDynamicIsolationChecking, + isMacroArg); }; // Quickly test if any further fix-ups for the argument types are necessary. diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 5f8180a96f144..640c220e34ef7 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -2240,11 +2240,12 @@ class ImplicitSelfUsageChecker : public BaseDiagnosticWalker { invalidImplicitSelfShouldOnlyWarn510(base, closure)) { warnUntilVersion.emplace(6); } - // Prior to Swift 7, downgrade to a warning if we're in a macro to preserve - // compatibility with the Swift 6 diagnostic behavior where we previously - // skipped diagnosing. - if (!Ctx.isSwiftVersionAtLeast(7) && isInMacro()) - warnUntilVersion.emplace(7); + // Prior to the next language mode, downgrade to a warning if we're in a + // macro to preserve compatibility with the Swift 6 diagnostic behavior + // where we previously skipped diagnosing. + auto futureVersion = version::Version::getFutureMajorLanguageVersion(); + if (!Ctx.isSwiftVersionAtLeast(futureVersion) && isInMacro()) + warnUntilVersion.emplace(futureVersion); auto diag = Ctx.Diags.diagnose(loc, ID, std::move(Args)...); if (warnUntilVersion) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 656db55f364ef..ff551cd7cb23d 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1260,7 +1260,7 @@ void AttributeChecker::visitAccessControlAttr(AccessControlAttr *attr) { diagnose(attr->getLocation(), diag::access_control_non_objc_open_member, VD) .fixItReplace(attr->getRange(), "public") - .warnUntilSwiftVersion(7); + .warnUntilFutureSwiftVersion(); } } } diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index b2f9c34dd5f13..03cffcf61d3c9 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -276,16 +276,18 @@ static bool shouldAllowReferenceToUnavailableInSwiftDeclaration( return false; } -// Utility function to help determine if noasync diagnostics are still -// appropriate even if a `DeclContext` returns `false` from `isAsyncContext()`. -static bool shouldTreatDeclContextAsAsyncForDiagnostics(const DeclContext *DC) { - if (auto *D = DC->getAsDecl()) - if (auto *FD = dyn_cast(D)) +/// Retrieve the innermost DeclContext that should be consulted for noasync +/// checking. +static const DeclContext * +getInnermostDeclContextForNoAsync(const DeclContext *DC) { + if (auto *D = DC->getAsDecl()) { + if (auto *FD = dyn_cast(D)) { if (FD->isDeferBody()) // If this is a defer body, we should delegate to its parent. - return shouldTreatDeclContextAsAsyncForDiagnostics(DC->getParent()); - - return DC->isAsyncContext(); + return getInnermostDeclContextForNoAsync(DC->getParent()); + } + } + return DC; } /// A class that walks the AST to find the innermost (i.e., deepest) node that @@ -2758,7 +2760,8 @@ static bool diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R, const Expr *call, const ExportContext &Where) { // If we are not in an (effective) async context, don't check it - if (!shouldTreatDeclContextAsAsyncForDiagnostics(Where.getDeclContext())) + auto *noAsyncDC = getInnermostDeclContextForNoAsync(Where.getDeclContext()); + if (!noAsyncDC->isAsyncContext()) return false; ASTContext &ctx = Where.getDeclContext()->getASTContext(); @@ -2774,14 +2777,27 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R, } } + // In Swift 6 we previously didn't coerce macro arguments to parameter types, + // so closure arguments may be treated as async in cases where they weren't in + // Swift 6. As such we need to warn if the use is within a closure macro + // argument until the next language mode. + auto shouldWarnUntilFutureVersion = [&]() { + auto *CE = dyn_cast(noAsyncDC); + return CE && CE->isMacroArgument(); + }; + // @available(noasync) spelling if (auto attr = D->getNoAsyncAttr()) { SourceLoc diagLoc = call ? call->getLoc() : R.Start; auto diag = ctx.Diags.diagnose(diagLoc, diag::async_unavailable_decl, D, attr->getMessage()); - diag.warnUntilSwiftVersion(6); - diag.limitBehaviorWithPreconcurrency(DiagnosticBehavior::Warning, - D->preconcurrency()); + if (D->preconcurrency()) { + diag.limitBehavior(DiagnosticBehavior::Warning); + } else if (shouldWarnUntilFutureVersion()) { + diag.warnUntilFutureSwiftVersion(); + } else { + diag.warnUntilSwiftVersion(6); + } if (!attr->getRename().empty()) { fixItAvailableAttrRename(diag, R, D, attr->getRename(), call); @@ -2797,10 +2813,16 @@ diagnoseDeclAsyncAvailability(const ValueDecl *D, SourceRange R, // @_unavailableFromAsync spelling const UnavailableFromAsyncAttr *attr = D->getAttrs().getAttribute(); - SourceLoc diagLoc = call ? call->getLoc() : R.Start; - ctx.Diags - .diagnose(diagLoc, diag::async_unavailable_decl, D, attr->Message) - .warnUntilSwiftVersion(6); + { + SourceLoc diagLoc = call ? call->getLoc() : R.Start; + auto diag = ctx.Diags.diagnose(diagLoc, diag::async_unavailable_decl, D, + attr->Message); + if (shouldWarnUntilFutureVersion()) { + diag.warnUntilFutureSwiftVersion(); + } else { + diag.warnUntilSwiftVersion(6); + } + } D->diagnose(diag::decl_declared_here, D); return true; } diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 019c98dbc7f32..174cc5cd4722c 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -2675,7 +2675,7 @@ namespace { fromType, toType); if (downgradeToWarning) - diag.warnUntilSwiftVersion(7); + diag.warnUntilFutureSwiftVersion(); } for (auto type : nonSendableTypes) { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 2206251616367..3ac509fd88d92 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5185,7 +5185,8 @@ static bool diagnoseTypeWitnessAvailability( return false; // In Swift 6 and earlier type witness availability diagnostics are warnings. - const unsigned warnBeforeVersion = 7; + using namespace version; + const unsigned warnBeforeVersion = Version::getFutureMajorLanguageVersion(); bool shouldError = ctx.LangOpts.EffectiveLanguageVersion.isVersionAtLeast(warnBeforeVersion); diff --git a/test/Macros/issue-80835.swift b/test/Macros/issue-80835.swift new file mode 100644 index 0000000000000..863e988ea6e34 --- /dev/null +++ b/test/Macros/issue-80835.swift @@ -0,0 +1,84 @@ +// RUN: %empty-directory(%t) +// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift + +// RUN: %target-typecheck-verify-swift -swift-version 6 -load-plugin-library %t/%target-library-name(MacroDefinition) -verify-additional-prefix swift6- +// RUN: %target-typecheck-verify-swift -swift-version 7 -load-plugin-library %t/%target-library-name(MacroDefinition) -verify-additional-prefix swift7- + +// REQUIRES: swift_swift_parser +// REQUIRES: swift7 + +// https://github.com/swiftlang/swift/issues/80835 + +@available(*, noasync) +func noasyncFn() {} + +@_unavailableFromAsync +func unavailableFromAsyncFn() {} // expected-note {{'unavailableFromAsyncFn()' declared here}} + +@freestanding(expression) +macro asyncMacro(_ fn: () async -> Void) = #externalMacro(module: "MacroDefinition", type: "GenericToVoidMacro") + +@freestanding(declaration) +macro asyncMacroDecl(_ fn: () async -> Void) = #externalMacro(module: "MacroDefinition", type: "EmptyDeclarationMacro") + +@attached(peer) +macro AsyncMacro(_ fn: () async -> Void) = #externalMacro(module: "MacroDefinition", type: "WrapperMacro") + +func takesAsyncFn(_ fn: () async -> Void) {} + +#asyncMacro { + defer { + noasyncFn() + // expected-swift7-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} + } + noasyncFn() + // expected-swift7-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} + + unavailableFromAsyncFn() + // expected-swift7-error@-1 {{global function 'unavailableFromAsyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'unavailableFromAsyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} + + // This was always an error. + let _: () async -> Void = { + noasyncFn() + // expected-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + } +} + +// This was always an error. +takesAsyncFn { + noasyncFn() + // expected-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} +} + +#asyncMacroDecl { + noasyncFn() + // expected-swift7-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} +} + +typealias Magic = T + +// expected-swift7-error@+2 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} +// expected-swift6-warning@+1 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} +@AsyncMacro({ noasyncFn() }) +func foo() { + #asyncMacro(({ + noasyncFn() + // expected-swift7-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} + })) + + #asyncMacroDecl(({ + noasyncFn() + // expected-swift7-error@-1 {{global function 'noasyncFn' is unavailable from asynchronous contexts}} + // expected-swift6-warning@-2 {{global function 'noasyncFn' is unavailable from asynchronous contexts; this will be an error in a future Swift language mode}} + })) + + // This was never treated as async. + #asyncMacro({ + noasyncFn() + } as Magic) +} diff --git a/test/Macros/macro_expand.swift b/test/Macros/macro_expand.swift index e961b08b960c2..f861863a8fb9c 100644 --- a/test/Macros/macro_expand.swift +++ b/test/Macros/macro_expand.swift @@ -667,6 +667,28 @@ func testLocalAccessorMacroWithAutoclosure() { takesAutoclosure(1) } +@propertyWrapper +struct SomePropertyWrapper { + var wrappedValue: T + init(wrappedValue: T) { + self.wrappedValue = wrappedValue + } + init(projectedValue: Self) { + self = projectedValue + } + var projectedValue: Self { self } +} + +// Property wrappers on macros probably aren't all that useful, but make sure +// we don't crash. +@freestanding(expression) +macro hasPropertyWrapperParam(@SomePropertyWrapper x: Int) = #externalMacro(module: "MacroDefinition", type: "GenericToVoidMacro") + +func testPropertyWrapperMacro() { + #hasPropertyWrapperParam(x: 0) + #hasPropertyWrapperParam($x: .init(wrappedValue: 0)) +} + #if TEST_DIAGNOSTICS @freestanding(expression) macro missingMacro() = #externalMacro(module: "MacroDefinition", type: "BluhBlah") diff --git a/test/Macros/macro_misc_diags.swift b/test/Macros/macro_misc_diags.swift index 3bd8fd8035b4b..4201c04639621 100644 --- a/test/Macros/macro_misc_diags.swift +++ b/test/Macros/macro_misc_diags.swift @@ -36,6 +36,32 @@ public struct TrailingClosureMacro: ExpressionMacro { } } +public struct CallClosureMacro: ExpressionMacro { + public static func expansion( + of macro: some FreestandingMacroExpansionSyntax, + in context: some MacroExpansionContext + ) -> ExprSyntax { + guard let argument = macro.trailingClosure else { + fatalError() + } + return "\(argument)()" + } +} + +public struct AddFunctionThatCallsClosureMacro: PeerMacro { + public static func expansion( + of node: AttributeSyntax, + providingPeersOf declaration: some DeclSyntaxProtocol, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + guard case .argumentList(let args) = node.arguments else { + fatalError() + } + let arg = args.first! + return ["func qux() { \(arg)() }"] + } +} + public struct MakeBinding : DeclarationMacro { static public func expansion( of node: some FreestandingMacroExpansionSyntax, @@ -64,6 +90,12 @@ macro identity(_ x: T) -> T = #externalMacro(module: "MacroPlugin", type: "Id @freestanding(expression) macro trailingClosure(_ x: T) -> T = #externalMacro(module: "MacroPlugin", type: "TrailingClosureMacro") +@freestanding(expression) +macro takesNonEscapingClosure(_ x: () -> Void) = #externalMacro(module: "MacroPlugin", type: "CallClosureMacro") + +@attached(peer, names: named(qux)) +macro AddFunctionThatCallsClosure(_ fn: () -> T) = #externalMacro(module: "MacroPlugin", type: "AddFunctionThatCallsClosureMacro") + @freestanding(declaration, names: named(x)) macro makeBinding(_ x: T) = #externalMacro(module: "MacroPlugin", type: "MakeBinding") @@ -160,3 +192,29 @@ class rdar138997009_Class { } } } + +// https://github.com/swiftlang/swift/issues/80561 +class TestNonEscaping { + func foo() {} + func bar() { + _ = #takesNonEscapingClosure { + foo() + } + _ = { + _ = #takesNonEscapingClosure { + foo() + // CHECK-DIAG: @__swiftmacro_6Client0017Clientswift_yEEFcfMX[[@LINE-3]]{{.*}}takesNonEscapingClosurefMf_.swift:2:9: error: call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit + // CHECK-DIAG: Client.swift:[[@LINE-2]]:9: warning: call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit; this will be an error in a future Swift language mode + } + } + + @AddFunctionThatCallsClosure({ foo() }) + func baz() {} + } + func qux() { + @AddFunctionThatCallsClosure({ _ = { foo() } }) + func baz() {} + // CHECK-DIAG: Client.swift:[[@LINE-2]]:42: warning: call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit; this will be an error in a future Swift language mode + // CHECK-DIAG: @__swiftmacro_6Client15TestNonEscapingC3quxyyF7baz_$l{{.*}}AddFunctionThatCallsClosurefMp_.swift:4:13: error: call to method 'foo' in closure requires explicit use of 'self' to make capture semantics explicit + } +}