From 108132252fcc0df03058918d359874fed1a7f261 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 2 May 2025 13:55:43 -0700 Subject: [PATCH] [Macros] Apply nonisolated conformances transform to macro-expanded code Macros provide an option (on by default) to infer 'nonisolated' on conformances that are introduced in macro expansions. However, if we are dealing with a macro that was built prior to the addition of this support, we apply this transform on the compiler side. Part of rdar://150419628 --- .../Sources/MacroEvaluation/Macros.swift | 30 +++++++++++++++++-- .../Sources/MacroEvaluation/PluginHost.swift | 1 + test/Macros/macro_plugin_server.swift | 4 +-- test/Macros/macro_plugin_server_mod.swift | 6 ++-- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/ASTGen/Sources/MacroEvaluation/Macros.swift b/lib/ASTGen/Sources/MacroEvaluation/Macros.swift index 21c42fbbcbc89..b9f950562a59e 100644 --- a/lib/ASTGen/Sources/MacroEvaluation/Macros.swift +++ b/lib/ASTGen/Sources/MacroEvaluation/Macros.swift @@ -419,6 +419,32 @@ func makeExpansionOutputResult( return 0 } +/// Adjust the expanded source code with any transformations that the compiler +/// needs to apply. +/// +/// At present, this is only used to apply transformations that we want the +/// compiler plugin to perform, but if it doesn't know how, we do it here. +/// The only transformation in this category is the inference of nonisolated +/// on protocol conformances. +fileprivate func adjustExpandedSource( + _ expandedSource: String?, + plugin: CompilerPlugin +) -> String? { + guard let expandedSource else { + return nil + } + + // If the plugin can infer nonisolated conformances, we don't have to. + if let capability = plugin.capability, + capability.features.contains(.inferNonisolatedConformances) { + return expandedSource + } + + // Infer nonisolated conformances. + let sourceFile = Parser.parse(source: expandedSource) + return sourceFile.inferNonisolatedConformances().description +} + @_cdecl("swift_Macros_expandFreestandingMacro") @usableFromInline func expandFreestandingMacro( @@ -534,8 +560,8 @@ func expandFreestandingMacroImpl( diagEngine.add(exportedSourceFile: sourceFilePtr) diagEngine.emit(diagnostics, messageSuffix: " (from macro '\(macroName)')") } - return expandedSource + return adjustExpandedSource(expandedSource, plugin: macro.plugin) } catch let error { let srcMgr = SourceManager(cxxDiagnosticEngine: diagEnginePtr) srcMgr.insert(sourceFilePtr) @@ -767,8 +793,8 @@ func expandAttachedMacroImpl( } diagEngine.emit(diagnostics, messageSuffix: " (from macro '\(macroName)')") } - return expandedSource + return adjustExpandedSource(expandedSource, plugin: macro.plugin) } catch let error { let srcMgr = SourceManager(cxxDiagnosticEngine: diagEnginePtr) srcMgr.insert(customAttrSourceFilePtr) diff --git a/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift b/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift index 5e134f64fea68..f67f8d084b6fd 100644 --- a/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift +++ b/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift @@ -93,6 +93,7 @@ struct CompilerPlugin { struct Capability { enum Feature: String { case loadPluginLibrary = "load-plugin-library" + case inferNonisolatedConformances = "infer-nonisolated-conformances" } var protocolVersion: Int diff --git a/test/Macros/macro_plugin_server.swift b/test/Macros/macro_plugin_server.swift index c222f7dada18a..cb05a4afd28b4 100644 --- a/test/Macros/macro_plugin_server.swift +++ b/test/Macros/macro_plugin_server.swift @@ -66,7 +66,7 @@ // CHECK-DIAGS: loaded macro implementation module 'MacroDefinition' from compiler plugin server // CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}} -// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library","infer-nonisolated-conformances"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} // CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}MacroDefinition.{{dylib|so|dll}}","moduleName":"MacroDefinition"}} // CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} // CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}} @@ -77,7 +77,7 @@ // ^ This crashes the plugin server. // CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}} -// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} +// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library","infer-nonisolated-conformances"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} // CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}MacroDefinition.{{dylib|so|dll}}","moduleName":"MacroDefinition"}} // CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} // CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}} diff --git a/test/Macros/macro_plugin_server_mod.swift b/test/Macros/macro_plugin_server_mod.swift index 8755f5440f215..a77e98a0bd8c5 100644 --- a/test/Macros/macro_plugin_server_mod.swift +++ b/test/Macros/macro_plugin_server_mod.swift @@ -47,17 +47,17 @@ // RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt // CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}} -// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library","infer-nonisolated-conformances"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} // CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}CrashOnLoad.{{.*}}","moduleName":"CrashOnLoad"}} // CHECK-NEXT: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}} -// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} +// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library","infer-nonisolated-conformances"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} // CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros{{.*}},"moduleName":"EvilMacros"}} // CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} // CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"{{.*}}","lexicalContext":{{.*}},"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"}{{.*}} // CHECK-NEXT: ->(plugin:[[#PID3:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}} -// CHECK-NEXT: <-(plugin:[[#PID3]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} +// CHECK-NEXT: <-(plugin:[[#PID3]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library","infer-nonisolated-conformances"],"protocolVersion":[[#PROTOCOL_VERSION]]}}} // CHECK-NEXT: ->(plugin:[[#PID3]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros{{.*}}","moduleName":"EvilMacros"}} // CHECK-NEXT: <-(plugin:[[#PID3]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} // CHECK-NEXT: ->(plugin:[[#PID3]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}MacroDefinition{{.*}}","moduleName":"MacroDefinition"}}