[Macros] Feed the static build configuration into macro expansions

Thread the static build configuration (formed from language options) in
to the macro plugin handler, which will serialize it for use in the
macro implementation. test this with a simple macro that checks
whether a particular custom configuration (set via `-D`) is enabled or
not.

This required some re-layering, sinking the logic for building a
StaticBuildConfiguration from language options down into a new
swiftBasicSwift library, which sits on top of the C++ swiftBasic and
provides Swift functionality for it. That can be used by the C++
swiftAST to cache the StaticBuildConfiguration on the ASTContext,
making it available for other parts of ASTGen.
This commit is contained in:
Doug Gregor
2025-09-29 17:07:43 -07:00
parent ae8f9d8234
commit 3082b04b75
27 changed files with 432 additions and 180 deletions

View File

@@ -194,115 +194,6 @@ BridgedDeclNameLoc_createParsed(BridgedASTContext cContext,
swift::SourceLoc moduleSelectorLoc,
swift::SourceLoc baseNameLoc);
//===----------------------------------------------------------------------===//
// MARK: LangOptions
//===----------------------------------------------------------------------===//
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedEndianness : size_t {
EndianLittle,
EndianBig,
};
class BridgedLangOptions {
const swift::LangOptions * _Nonnull LangOpts;
public:
SWIFT_UNAVAILABLE("Use init(raw:) instead")
BRIDGED_INLINE BridgedLangOptions(const swift::LangOptions &langOpts);
SWIFT_UNAVAILABLE("Use '.raw' instead")
BRIDGED_INLINE const swift::LangOptions &unbridged() const;
SWIFT_COMPUTED_PROPERTY
const void *_Nonnull getRaw() const { return LangOpts; }
SWIFT_COMPUTED_PROPERTY
unsigned getMajorLanguageVersion() const;
SWIFT_COMPUTED_PROPERTY
unsigned getTargetPointerBitWidth() const;
SWIFT_COMPUTED_PROPERTY
BridgedEndianness getTargetEndianness() const;
SWIFT_COMPUTED_PROPERTY
bool getAttachCommentsToDecls() const;
};
/// Key used when enumerating build configuration entries to the
/// StaticBuildConfiguration initializer for an ASTContext.
enum ENUM_EXTENSIBILITY_ATTR(closed) BuildConfigurationKey : size_t {
BCKCustomCondition,
BCKFeature,
BCKAttribute,
BCKTargetOSName,
BCKTargetArchitecture,
BCKTargetEnvironment,
BCKTargetRuntime,
BCKTargetPointerAuthenticationScheme,
BCKTargetObjectFileFormat
};
SWIFT_NAME("BridgedLangOptions.hasFeature(self:_:)")
bool BridgedLangOptions_hasFeature(BridgedLangOptions cLangOpts,
BridgedFeature feature);
SWIFT_NAME("BridgedLangOptions.customConditionSet(self:_:)")
bool BridgedLangOptions_customConditionSet(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.hasFeatureNamed(self:_:)")
bool BridgedLangOptions_hasFeatureNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.hasAttributeNamed(self:_:)")
bool BridgedLangOptions_hasAttributeNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetOS(self:_:)")
bool BridgedLangOptions_isActiveTargetOS(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetArchitecture(self:_:)")
bool BridgedLangOptions_isActiveTargetArchitecture(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetEnvironment(self:_:)")
bool BridgedLangOptions_isActiveTargetEnvironment(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetRuntime(self:_:)")
bool BridgedLangOptions_isActiveTargetRuntime(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetPtrAuth(self:_:)")
bool BridgedLangOptions_isActiveTargetPtrAuth(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.getTargetAtomicBitWidths(self:_:)")
SwiftInt BridgedLangOptions_getTargetAtomicBitWidths(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
SWIFT_NAME("BridgedLangOptions.getLanguageVersion(self:_:)")
SwiftInt BridgedLangOptions_getLanguageVersion(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
SWIFT_NAME("BridgedLangOptions.getCompilerVersion(self:_:)")
SwiftInt BridgedLangOptions_getCompilerVersion(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
/* Deallocate an array of Swift int values that was allocated in C++. */
void deallocateIntBuffer(SwiftInt * _Nullable cComponents);
/// Enumerate all of the key/value pairs for the build configuration by calling
/// the given callback for each one.
SWIFT_NAME("BridgedLangOptions.enumerateBuildConfigurationEntries(self:callbackContext:callback:)")
void BridgedLangOptions_enumerateBuildConfigurationEntries(
BridgedLangOptions cLangOpts,
void * _Nonnull callbackContext,
void (* _Nonnull callback)(
BridgedLangOptions cLangOpts, void * _Nonnull callbackContext,
BuildConfigurationKey key, BridgedStringRef value));
//===----------------------------------------------------------------------===//
// MARK: ASTContext
@@ -326,6 +217,9 @@ public:
SWIFT_COMPUTED_PROPERTY
BridgedAvailabilityMacroMap getAvailabilityMacroMap() const;
SWIFT_COMPUTED_PROPERTY
BridgedDiagnosticEngine getDiags() const;
};
#define IDENTIFIER_WITH_NAME(Name, _) \
@@ -360,6 +254,10 @@ BridgedASTContext_getDollarIdentifier(BridgedASTContext cContext, size_t idx);
SWIFT_NAME("getter:BridgedASTContext.langOpts(self:)")
BridgedLangOptions BridgedASTContext_langOpts(BridgedASTContext cContext);
SWIFT_NAME("BridgedLangOptions.hasAttributeNamed(self:_:)")
bool BridgedLangOptions_hasAttributeNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedCanImportVersion : size_t {
CanImportUnversioned,
CanImportVersion,
@@ -374,6 +272,9 @@ bool BridgedASTContext_canImport(BridgedASTContext cContext,
const SwiftInt *_Nullable versionComponents,
SwiftInt numVersionComponents);
SWIFT_NAME("getter:BridgedASTContext.staticBuildConfigurationPtr(self:)")
void * _Nonnull BridgedASTContext_staticBuildConfiguration(BridgedASTContext cContext);
//===----------------------------------------------------------------------===//
// MARK: AST nodes
//===----------------------------------------------------------------------===//

View File

@@ -84,6 +84,10 @@ struct ASTContext::GlobalCache {
const NormalProtocolConformance *,
std::vector<ConformanceIsolationError>
> conformanceIsolationErrors;
/// The static build configuration. This points to an instance of the Swift
/// StaticBuildConfiguration.
void *StaticBuildConfiguration = nullptr;
};
} // end namespace

View File

@@ -61,6 +61,7 @@ class VersionTuple;
} // end namespace llvm
namespace swift {
class LangOptions;
class SourceLoc;
class SourceRange;
class CharSourceRange;
@@ -451,6 +452,112 @@ struct BridgedSwiftClosure {
BRIDGED_INLINE void operator()(const void *_Nullable);
};
//===----------------------------------------------------------------------===//
// MARK: LangOptions
//===----------------------------------------------------------------------===//
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedEndianness : size_t {
EndianLittle,
EndianBig,
};
class BridgedLangOptions {
const swift::LangOptions * _Nonnull LangOpts;
public:
SWIFT_UNAVAILABLE("Use init(raw:) instead")
BRIDGED_INLINE BridgedLangOptions(const swift::LangOptions &langOpts);
SWIFT_UNAVAILABLE("Use '.raw' instead")
BRIDGED_INLINE const swift::LangOptions &unbridged() const;
SWIFT_COMPUTED_PROPERTY
const void *_Nonnull getRaw() const { return LangOpts; }
SWIFT_COMPUTED_PROPERTY
unsigned getMajorLanguageVersion() const;
SWIFT_COMPUTED_PROPERTY
unsigned getTargetPointerBitWidth() const;
SWIFT_COMPUTED_PROPERTY
BridgedEndianness getTargetEndianness() const;
SWIFT_COMPUTED_PROPERTY
bool getAttachCommentsToDecls() const;
};
/// Key used when enumerating build configuration entries to the
/// StaticBuildConfiguration initializer for an ASTContext.
enum ENUM_EXTENSIBILITY_ATTR(closed) BuildConfigurationKey : size_t {
BCKCustomCondition,
BCKFeature,
BCKAttribute,
BCKTargetOSName,
BCKTargetArchitecture,
BCKTargetEnvironment,
BCKTargetRuntime,
BCKTargetPointerAuthenticationScheme,
BCKTargetObjectFileFormat
};
SWIFT_NAME("BridgedLangOptions.hasFeature(self:_:)")
bool BridgedLangOptions_hasFeature(BridgedLangOptions cLangOpts,
BridgedFeature feature);
SWIFT_NAME("BridgedLangOptions.customConditionSet(self:_:)")
bool BridgedLangOptions_customConditionSet(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.hasFeatureNamed(self:_:)")
bool BridgedLangOptions_hasFeatureNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetOS(self:_:)")
bool BridgedLangOptions_isActiveTargetOS(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetArchitecture(self:_:)")
bool BridgedLangOptions_isActiveTargetArchitecture(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetEnvironment(self:_:)")
bool BridgedLangOptions_isActiveTargetEnvironment(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetRuntime(self:_:)")
bool BridgedLangOptions_isActiveTargetRuntime(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.isActiveTargetPtrAuth(self:_:)")
bool BridgedLangOptions_isActiveTargetPtrAuth(BridgedLangOptions cLangOpts,
BridgedStringRef cName);
SWIFT_NAME("BridgedLangOptions.getTargetAtomicBitWidths(self:_:)")
SwiftInt BridgedLangOptions_getTargetAtomicBitWidths(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
SWIFT_NAME("BridgedLangOptions.getLanguageVersion(self:_:)")
SwiftInt BridgedLangOptions_getLanguageVersion(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
SWIFT_NAME("BridgedLangOptions.getCompilerVersion(self:_:)")
SwiftInt BridgedLangOptions_getCompilerVersion(BridgedLangOptions cLangOpts,
SwiftInt* _Nullable * _Nonnull cComponents);
/* Deallocate an array of Swift int values that was allocated in C++. */
void deallocateIntBuffer(SwiftInt * _Nullable cComponents);
/// Enumerate all of the key/value pairs for the build configuration by calling
/// the given callback for each one.
SWIFT_NAME("BridgedLangOptions.enumerateBuildConfigurationEntries(self:callbackContext:callback:)")
void BridgedLangOptions_enumerateBuildConfigurationEntries(
BridgedLangOptions cLangOpts,
void * _Nonnull callbackContext,
void (* _Nonnull callback)(
BridgedLangOptions cLangOpts, void * _Nonnull callbackContext,
BuildConfigurationKey key, BridgedStringRef value));
SWIFT_END_NULLABILITY_ANNOTATIONS
#ifndef PURE_BRIDGING_MODE

View File

@@ -0,0 +1,32 @@
//===--- BasicSwift.h -------------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 - 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BRIDGING_BASICSWIFT_H
#define SWIFT_BRIDGING_BASICSWIFT_H
#include "swift/Basic/BasicBridging.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Create a new static build configuration for the given language options.
void * _Nonnull swift_Basic_createStaticBuildConfiguration(BridgedLangOptions cLangOpts);
/// Free the given static build configuration.
void swift_Basic_freeStaticBuildConfiguration(void * _Nonnull staticBuildConfiguration);
#ifdef __cplusplus
}
#endif
#endif // SWIFT_BRIDGING_BASICSWIFT_H

View File

@@ -14,6 +14,7 @@
#define SWIFT_BRIDGING_MACROS_H
#include "swift/Basic/BasicBridging.h"
#include "swift/AST/ASTBridging.h"
#ifdef __cplusplus
extern "C" {
@@ -40,13 +41,13 @@ void swift_Macros_freeExpansionReplacements(
ptrdiff_t *_Nullable replacementsPtr, ptrdiff_t numReplacements);
ptrdiff_t swift_Macros_expandFreestandingMacro(
void *_Nonnull diagEngine, const void *_Nonnull macro,
BridgedASTContext cContext, const void *_Nonnull macro,
const char *_Nonnull discriminator, uint8_t rawMacroRole,
void *_Nonnull sourceFile, const void *_Nullable sourceLocation,
BridgedStringRef *_Nonnull evaluatedSourceOut);
ptrdiff_t swift_Macros_expandAttachedMacro(
void *_Nonnull diagEngine, const void *_Nonnull macro,
BridgedASTContext cContext, const void *_Nonnull macro,
const char *_Nonnull discriminator, const char *_Nonnull qualifiedType,
const char *_Nonnull conformances, uint8_t rawMacroRole,
void *_Nonnull customAttrSourceFile,

View File

@@ -13,7 +13,9 @@
#include "swift/AST/ASTBridging.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTContextGlobalCache.h"
#include "swift/AST/AvailabilitySpec.h"
#include "swift/Bridging/BasicSwift.h"
using namespace swift;
@@ -44,6 +46,10 @@ unsigned BridgedASTContext::getMajorLanguageVersion() const {
return unbridged().LangOpts.EffectiveLanguageVersion[0];
}
BridgedDiagnosticEngine BridgedASTContext::getDiags() const {
return &unbridged().Diags;
}
bool BridgedASTContext_canImport(BridgedASTContext cContext,
BridgedStringRef importPath,
SourceLoc canImportLoc,
@@ -82,3 +88,22 @@ bool BridgedASTContext_canImport(BridgedASTContext cContext,
BridgedAvailabilityMacroMap BridgedASTContext::getAvailabilityMacroMap() const {
return &unbridged().getAvailabilityMacroMap();
}
bool BridgedLangOptions_hasAttributeNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName) {
return hasAttribute(cLangOpts.unbridged(), cName.unbridged());
}
void *BridgedASTContext_staticBuildConfiguration(BridgedASTContext cContext) {
ASTContext &ctx = cContext.unbridged();
void *staticBuildConfiguration = ctx.getGlobalCache().StaticBuildConfiguration;
if (!staticBuildConfiguration) {
staticBuildConfiguration =
swift_Basic_createStaticBuildConfiguration(ctx.LangOpts);
ctx.addCleanup([staticBuildConfiguration] {
swift_Basic_freeStaticBuildConfiguration(staticBuildConfiguration);
});
}
return staticBuildConfiguration;
}

View File

@@ -7,7 +7,6 @@ target_sources(swiftAST PRIVATE
DiagnosticsBridging.cpp
ExprBridging.cpp
GenericsBridging.cpp
LangOptionsBridging.cpp
MiscBridging.cpp
PatternBridging.cpp
PluginBridging.cpp

View File

@@ -180,7 +180,7 @@ target_link_libraries(swiftAST
if (SWIFT_BUILD_SWIFT_SYNTAX)
target_link_libraries(swiftAST
PRIVATE swiftASTGen)
PRIVATE swiftASTGen swiftBasicSwift)
endif()
set_swift_llvm_is_available(swiftAST)

View File

@@ -126,21 +126,6 @@ extension BridgedLabeledStmtInfo: /*@retroactive*/ Swift.ExpressibleByNilLiteral
}
}
extension String {
init(bridged: BridgedStringRef) {
self.init(
decoding: UnsafeBufferPointer(start: bridged.data, count: bridged.count),
as: UTF8.self
)
}
public mutating func withBridgedString<R>(_ body: (BridgedStringRef) throws -> R) rethrows -> R {
try withUTF8 { buffer in
try body(BridgedStringRef(data: buffer.baseAddress, count: buffer.count))
}
}
}
extension SyntaxText {
var bridged: BridgedStringRef {
BridgedStringRef(data: self.baseAddress, count: self.count)

View File

@@ -20,7 +20,6 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
Regex.swift
SourceFile.swift
StableHasher.swift
StaticBuildConfiguration+ASTContext.swift
Stmts.swift
TypeAttrs.swift
Types.swift
@@ -38,4 +37,5 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP
_CompilerSwiftParser
_CompilerSwiftParserDiagnostics
_CompilerSwiftDiagnostics
swiftBasicSwift
)

View File

@@ -10,12 +10,23 @@
//
//===----------------------------------------------------------------------===//
import BasicBridging
import ASTBridging
import swiftBasicSwift
import SwiftDiagnostics
@_spi(Compiler) import SwiftIfConfig
@_spi(ExperimentalLanguageFeatures) import SwiftParser
@_spi(ExperimentalLanguageFeatures) import SwiftSyntax
extension BridgedASTContext {
/// Retrieve the (cached) static build configuration for this ASTContext.
public var staticBuildConfiguration: StaticBuildConfiguration {
staticBuildConfigurationPtr.assumingMemoryBound(
to: StaticBuildConfiguration.self
).pointee
}
}
/// A build configuration that uses the compiler's ASTContext to answer
/// queries.
struct CompilerBuildConfiguration: BuildConfiguration {

View File

@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
import ASTBridging
import swiftBasicSwift
import SwiftDiagnostics
@_spi(Compiler) import SwiftParser
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax

View File

@@ -0,0 +1,11 @@
add_pure_swift_host_library(swiftBasicSwift STATIC CXX_INTEROP
StaticBuildConfiguration+LangOptions.swift
String+BridgedString.swift
DEPENDENCIES
swiftBasic
SWIFT_DEPENDENCIES
_CompilerSwiftCompilerPluginMessageHandling
_CompilerSwiftSyntax
_CompilerSwiftIfConfig
)

View File

@@ -131,3 +131,19 @@ public func printStaticBuildConfiguration(
return result ?? BridgedStringRef()
}
@_cdecl("swift_Basic_createStaticBuildConfiguration")
public func createStaticBuildConfiguration(
cLangOpts: BridgedLangOptions
) -> UnsafeMutableRawPointer {
let storage = UnsafeMutablePointer<StaticBuildConfiguration>.allocate(capacity: 1)
storage.initialize(to: StaticBuildConfiguration(langOptions: cLangOpts))
return UnsafeMutableRawPointer(storage)
}
/// Free the given static build configuration.
@_cdecl("swift_Basic_freeStaticBuildConfiguration")
public func freeStaticBuildConfiguration(pointer: UnsafeMutableRawPointer) {
pointer.assumingMemoryBound(to: StaticBuildConfiguration.self)
.deinitialize(count: 1).deallocate()
}

View File

@@ -0,0 +1,28 @@
//===--- String+BridgedString.swift ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import BasicBridging
extension String {
public init(bridged: BridgedStringRef) {
self.init(
decoding: UnsafeBufferPointer(start: bridged.data, count: bridged.count),
as: UTF8.self
)
}
public mutating func withBridgedString<R>(_ body: (BridgedStringRef) throws -> R) rethrows -> R {
try withUTF8 { buffer in
try body(BridgedStringRef(data: buffer.baseAddress, count: buffer.count))
}
}
}

View File

@@ -1,3 +1,4 @@
add_subdirectory(BasicSwift)
add_subdirectory(ASTGen)
add_subdirectory(MacroEvaluation)
add_subdirectory(SwiftIDEUtilsBridging)

View File

@@ -14,6 +14,7 @@ import ASTBridging
import BasicBridging
@_spi(PluginMessage) @_spi(ExperimentalLanguageFeature) import SwiftCompilerPluginMessageHandling
import SwiftDiagnostics
import SwiftIfConfig
import SwiftParser
import SwiftSyntax
@_spi(ExperimentalLanguageFeature) @_spi(Compiler) import SwiftSyntaxMacroExpansion
@@ -419,7 +420,7 @@ func makeExpansionOutputResult(
@_cdecl("swift_Macros_expandFreestandingMacro")
@usableFromInline
func expandFreestandingMacro(
diagEnginePtr: UnsafeMutableRawPointer,
cContext: BridgedASTContext,
macroPtr: UnsafeRawPointer,
discriminatorText: UnsafePointer<CChar>,
rawMacroRole: UInt8,
@@ -461,7 +462,7 @@ func expandFreestandingMacro(
let expandedSource: String? = expandFreestandingMacroImpl(
macroPtr: macroPtr,
macroRole: macroRole,
diagEnginePtr: diagEnginePtr,
cContext: cContext,
expansionSyntax: expansion,
sourceFilePtr: sourceFilePtr,
discriminator: discriminator
@@ -476,7 +477,7 @@ func expandFreestandingMacro(
func expandFreestandingMacroImpl(
macroPtr: UnsafeRawPointer,
macroRole: MacroRole,
diagEnginePtr: UnsafeMutableRawPointer,
cContext: BridgedASTContext,
expansionSyntax: FreestandingMacroExpansionSyntax,
sourceFilePtr: UnsafePointer<ExportedSourceFile>,
discriminator: String
@@ -505,14 +506,15 @@ func expandFreestandingMacroImpl(
}
// Send the message.
let message = HostToPluginMessage.expandFreestandingMacro(
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
macroRole: pluginMacroRole,
discriminator: discriminator,
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!,
lexicalContext: pluginLexicalContext(of: expansionSyntax)
)
do {
let message = HostToPluginMessage.expandFreestandingMacro(
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
macroRole: pluginMacroRole,
discriminator: discriminator,
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!,
lexicalContext: pluginLexicalContext(of: expansionSyntax),
staticBuildConfiguration: try cContext.staticBuildConfiguration.asJSON
)
let result = try macro.plugin.sendMessageAndWait(message)
let expandedSource: String?
let diagnostics: [PluginMessage.Diagnostic]
@@ -527,14 +529,14 @@ func expandFreestandingMacroImpl(
// Process the result.
if !diagnostics.isEmpty {
let diagEngine = PluginDiagnosticsEngine(cxxDiagnosticEngine: diagEnginePtr)
let diagEngine = PluginDiagnosticsEngine(cContext: cContext)
diagEngine.add(exportedSourceFile: sourceFilePtr)
diagEngine.emit(diagnostics, messageSuffix: " (from macro '\(macroName)')")
}
return expandedSource
} catch let error {
let srcMgr = SourceManager(cxxDiagnosticEngine: diagEnginePtr)
let srcMgr = SourceManager(cContext: cContext)
srcMgr.insert(sourceFilePtr)
srcMgr.diagnose(
diagnostic: .init(
@@ -552,7 +554,7 @@ func expandFreestandingMacroImpl(
@_cdecl("swift_Macros_expandAttachedMacro")
@usableFromInline
func expandAttachedMacro(
diagEnginePtr: UnsafeMutableRawPointer,
cContext: BridgedASTContext,
macroPtr: UnsafeRawPointer,
discriminatorText: UnsafePointer<CChar>,
qualifiedTypeText: UnsafePointer<CChar>,
@@ -610,7 +612,7 @@ func expandAttachedMacro(
let conformanceList = String(cString: conformanceListText)
let expandedSource: String? = expandAttachedMacroImpl(
diagEnginePtr: diagEnginePtr,
cContext: cContext,
macroPtr: macroPtr,
rawMacroRole: rawMacroRole,
discriminator: discriminator,
@@ -645,7 +647,7 @@ private func pluginLexicalContext(of node: some SyntaxProtocol) -> [PluginMessag
}
func expandAttachedMacroImpl(
diagEnginePtr: UnsafeMutableRawPointer,
cContext: BridgedASTContext,
macroPtr: UnsafeRawPointer,
rawMacroRole: UInt8,
discriminator: String,
@@ -718,18 +720,19 @@ func expandAttachedMacroImpl(
// Send the message.
let message = HostToPluginMessage.expandAttachedMacro(
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
macroRole: macroRole,
discriminator: discriminator,
attributeSyntax: customAttributeSyntax,
declSyntax: declSyntax,
parentDeclSyntax: parentDeclSyntax,
extendedTypeSyntax: extendedTypeSyntax,
conformanceListSyntax: conformanceListSyntax,
lexicalContext: pluginLexicalContext(of: declarationNode)
)
do {
let message = HostToPluginMessage.expandAttachedMacro(
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
macroRole: macroRole,
discriminator: discriminator,
attributeSyntax: customAttributeSyntax,
declSyntax: declSyntax,
parentDeclSyntax: parentDeclSyntax,
extendedTypeSyntax: extendedTypeSyntax,
conformanceListSyntax: conformanceListSyntax,
lexicalContext: pluginLexicalContext(of: declarationNode),
staticBuildConfiguration: try cContext.staticBuildConfiguration.asJSON
)
let expandedSource: String?
let diagnostics: [PluginMessage.Diagnostic]
switch try macro.plugin.sendMessageAndWait(message) {
@@ -756,7 +759,7 @@ func expandAttachedMacroImpl(
// Process the result.
if !diagnostics.isEmpty {
let diagEngine = PluginDiagnosticsEngine(cxxDiagnosticEngine: diagEnginePtr)
let diagEngine = PluginDiagnosticsEngine(cContext: cContext)
diagEngine.add(exportedSourceFile: customAttrSourceFilePtr)
diagEngine.add(exportedSourceFile: declarationSourceFilePtr)
if let parentDeclSourceFilePtr = parentDeclSourceFilePtr {
@@ -767,7 +770,7 @@ func expandAttachedMacroImpl(
return expandedSource
} catch let error {
let srcMgr = SourceManager(cxxDiagnosticEngine: diagEnginePtr)
let srcMgr = SourceManager(cContext: cContext)
srcMgr.insert(customAttrSourceFilePtr)
srcMgr.insert(declarationSourceFilePtr)
if let parentDeclSourceFilePtr = parentDeclSourceFilePtr {
@@ -787,3 +790,11 @@ func expandAttachedMacroImpl(
}
}
extension StaticBuildConfiguration {
/// Form the JSON representation of this static build configuration.
var asJSON: String {
get throws {
try String(decoding: JSON.encode(self), as: UTF8.self)
}
}
}

View File

@@ -201,8 +201,8 @@ class PluginDiagnosticsEngine {
private let bridgedDiagEngine: BridgedDiagnosticEngine
private var exportedSourceFileByName: [String: UnsafePointer<ExportedSourceFile>] = [:]
init(cxxDiagnosticEngine: UnsafeMutableRawPointer) {
self.bridgedDiagEngine = BridgedDiagnosticEngine(raw: cxxDiagnosticEngine)
init(cContext: BridgedASTContext) {
self.bridgedDiagEngine = cContext.diags
}
/// Failable convenience initializer for optional cxx engine pointer.

View File

@@ -23,6 +23,10 @@ class SourceManager {
self.bridgedDiagEngine = BridgedDiagnosticEngine(raw: cxxDiagnosticEngine)
}
init(cContext: BridgedASTContext) {
self.bridgedDiagEngine = cContext.diags
}
/// The bridged diagnostic engine (just the wrapped C++ `DiagnosticEngine`).
let bridgedDiagEngine: BridgedDiagnosticEngine

View File

@@ -59,6 +59,7 @@ add_swift_host_library(swiftBasic STATIC
ParseableOutput.cpp
JSONSerialization.cpp
LangOptions.cpp
LangOptionsBridging.cpp
LoadDynamicLibrary.cpp
Located.cpp
Mangler.cpp

View File

@@ -37,11 +37,6 @@ bool BridgedLangOptions_hasFeatureNamed(BridgedLangOptions cLangOpts,
return cLangOpts.unbridged().hasFeature(cName.unbridged());
}
bool BridgedLangOptions_hasAttributeNamed(BridgedLangOptions cLangOpts,
BridgedStringRef cName) {
return hasAttribute(cLangOpts.unbridged(), cName.unbridged());
}
bool BridgedLangOptions_isActiveTargetOS(BridgedLangOptions cLangOpts,
BridgedStringRef cName) {
return cLangOpts.unbridged().checkPlatformCondition(
@@ -121,6 +116,90 @@ SwiftInt BridgedLangOptions_getTargetAtomicBitWidths(
cElements);
}
namespace {
/// Describe behaviors that should prevent an attribute from being shown.
///
/// This is DeclAttrBehaviors, but with irrelevent values set to zero.
enum DeclAttrBehaviorsNotShown : uint64_t {
/// Whether this attribute is only valid when concurrency is enabled.
ConcurrencyOnly = 0,
/// True if multiple instances of this attribute are allowed on a single
/// declaration.
AllowMultipleAttributes = 0,
/// True if this is a decl modifier - i.e., that it should not be spelled
/// with an @.
DeclModifier = 1ull << 2,
/// True if this is a long attribute that should be printed on its own line.
///
/// Currently has no effect on DeclModifier attributes.
LongAttribute = 0,
/// True if this shouldn't be serialized.
NotSerialized = 0,
/// True if this attribute is only valid when parsing a .sil file.
SILOnly = 1ull << 5,
/// The attribute should be reported by parser as unknown.
RejectByParser = 1ull << 6,
/// Whether client code cannot use the attribute. Hides it in code completion.
UserInaccessible = 1ull << 7,
/// Whether adding this attribute can break API
APIBreakingToAdd = 0,
/// Whether removing this attribute can break API
APIBreakingToRemove = 0,
/// Whether adding this attribute can break ABI
ABIBreakingToAdd = 0,
/// Whether removing this attribute can break ABI
ABIBreakingToRemove = 0,
/// The opposite of APIBreakingToAdd
APIStableToAdd = 0,
/// The opposite of APIBreakingToRemove
APIStableToRemove = 0,
/// The opposite of ABIBreakingToAdd
ABIStableToAdd = 0,
/// The opposite of ABIBreakingToRemove
ABIStableToRemove = 0,
/// Attribute should not be used in an \c \@abi attribute. Use for
/// attributes which cannot affect mangled names, even indirectly, and
/// which either don't affect ABI or where ABI-only declarations get their
/// behavior from their API counterpart.
ForbiddenInABIAttr = 0,
/// Attribute can be used without restrictions in an \c \@abi attribute.
/// Use for attributes which affect mangled names but otherwise don't alter
/// the ABI, or ones where the \c ABIDeclChecker manually implements
/// special checking logic (e.g. because several different attributes
/// contribute to the same aspect of ABI in some complicated way).
UnconstrainedInABIAttr = 0,
/// Attribute can be used in an \c \@abi attribute, but must match
/// equivalent on API decl. Use for attributes which affect both mangled
/// names and other parts of the ABI such that the declaration can only be
/// valid if they match.
EquivalentInABIAttr = 0,
/// Use for attributes which are \em only valid on declarations that cannot
/// have an \c @abi attribute, such as \c ImportDecl .
UnreachableInABIAttr = 0,
};
}
void BridgedLangOptions_enumerateBuildConfigurationEntries(
BridgedLangOptions cLangOpts,
void * _Nonnull callbackContext,
@@ -143,13 +222,13 @@ void BridgedLangOptions_enumerateBuildConfigurationEntries(
// Enumerate attributes that are available.
#define DECL_ATTR(SPELLING, CLASS, REQUIREMENTS, BEHAVIORS, CODE) \
if (hasAttribute(langOpts, #SPELLING)) \
if ((BEHAVIORS) == 0) \
callback(cLangOpts, callbackContext, BCKAttribute, StringRef(#SPELLING));
#include "swift/AST/DeclAttr.def"
#define SIL_TYPE_ATTR(X, C)
#define TYPE_ATTR(SPELLING, CLASS) \
if (hasAttribute(langOpts, #SPELLING)) \
callback(cLangOpts, callbackContext, BCKAttribute, StringRef(#SPELLING));
callback(cLangOpts, callbackContext, BCKAttribute, StringRef(#SPELLING));
#include "swift/AST/TypeAttr.def"
// Deal with all of the target platform/architecture information.

View File

@@ -1217,7 +1217,7 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion,
BridgedStringRef evaluatedSourceOut{nullptr, 0};
assert(!externalDef.isError());
swift_Macros_expandFreestandingMacro(
&ctx.Diags, externalDef.get(), discriminator->c_str(),
ctx, externalDef.get(), discriminator->c_str(),
getRawMacroRole(macroRole), astGenSourceFile,
expansion->getSourceRange().Start.getOpaquePointerValue(),
&evaluatedSourceOut);
@@ -1574,7 +1574,7 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo,
BridgedStringRef evaluatedSourceOut{nullptr, 0};
assert(!externalDef.isError());
swift_Macros_expandAttachedMacro(
&ctx.Diags, externalDef.get(), discriminator->c_str(),
ctx, externalDef.get(), discriminator->c_str(),
extendedType.c_str(), conformanceList.c_str(), getRawMacroRole(role),
astGenAttrSourceFile, attr->AtLoc.getOpaquePointerValue(),
astGenDeclSourceFile, startLoc.getOpaquePointerValue(),
@@ -1717,7 +1717,7 @@ static SourceFile *evaluateAttachedMacro(MacroDecl *macro,
BridgedStringRef evaluatedSourceOut{nullptr, 0};
assert(!externalDef.isError());
swift_Macros_expandAttachedMacro(
&ctx.Diags, externalDef.get(), discriminator->c_str(),
ctx, externalDef.get(), discriminator->c_str(),
"", "", getRawMacroRole(role),
astGenAttrSourceFile, attr->AtLoc.getOpaquePointerValue(),
astGenClosureSourceFile, startLoc.getOpaquePointerValue(),

View File

@@ -2980,3 +2980,21 @@ public struct BigEndianAccessorMacro: AccessorMacro {
]
}
}
public struct CustomConditionCheckMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
guard let firstElement = node.arguments.first,
let stringLiteral = firstElement.expression
.as(StringLiteralExprSyntax.self),
stringLiteral.segments.count == 1,
case let .stringSegment(conditionName)? = stringLiteral.segments.first else {
throw CustomError.message("macro requires a string literal containing the name of a custom condition")
}
let isSet = try context.buildConfiguration?.isCustomConditionSet(name: conditionName.content.text) ?? false
return "\(literal: isSet)"
}
}

View File

@@ -0,0 +1,17 @@
// REQUIRES: swift_swift_parser, executable_test
// 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
// Execution testing
// RUN: %target-build-swift -swift-version 5 -g -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -Xfrontend -emit-dependencies-path -Xfrontend %t/main.d -Xfrontend -emit-reference-dependencies-path -Xfrontend %t/main.swiftdeps -DDEBUG
// RUN: %target-codesign %t/main
// RUN: %target-run %t/main | %FileCheck %s
@freestanding(expression) macro isCustomConditionSet(_ name: String) -> Bool = #externalMacro(module: "MacroDefinition", type: "CustomConditionCheckMacro")
// CHECK: Release = false
print("Release = \(#isCustomConditionSet("RELEASE"))")
// CHECK: Debug = true
print("Debug = \(#isCustomConditionSet("DEBUG"))")

View File

@@ -30,9 +30,9 @@
// CHECK: ->(plugin:[[#PID:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
// CHECK: <-(plugin:[[#PID]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}func test{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testString","typeName":"TestStringMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":5,"offset":301},"source":"#testString(123)"}}}
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}func test{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testString","typeName":"TestStringMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":5,"offset":301},"source":"#testString(123)"}}}
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"\"123\"\n + \"foo \""}}
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testStringWithError","typeName":"TestStringWithErrorMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":6,"offset":336},"source":"#testStringWithError(321)"}}}
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testStringWithError","typeName":"TestStringWithErrorMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":6,"offset":336},"source":"#testStringWithError(321)"}}}
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[],"message":"message from plugin","notes":[],"position":{"fileName":"{{.*}}test.swift","offset":336},"severity":"error"}],"expandedSource":"\"bar\""}}
//--- test.swift

View File

@@ -18,14 +18,14 @@
// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":7,"offset":[[#]]},"source":"#fooMacro(1)"}}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":7,"offset":[[#]]},"source":"#fooMacro(1)"}}}
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"invalidResponse":{}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":9,"offset":[[#]]},"source":"#fooMacro(2)"}}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":9,"offset":[[#]]},"source":"#fooMacro(2)"}}}
// ^ This messages causes the mock plugin exit because there's no matching expected message.
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":11,"offset":[[#]]},"source":"#fooMacro(3)"}}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":11,"offset":[[#]]},"source":"#fooMacro(3)"}}}
// CHECK-NEXT: <-(plugin:[[#PID2:]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"3.description"}}
//--- test.swift

View File

@@ -71,9 +71,9 @@
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(a + b, \"a + b\")"}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
// ^ This crashes the plugin server.
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
@@ -82,12 +82,12 @@
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(b + a, \"b + a\")"}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{({.+})}},"source":"#missing()"}}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{{({.+})}},"source":"#missing()"}}}
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[{{{.*}}}],"message":"type 'MacroDefinition.TypeDoesNotExist' could not be found in library plugin '{{.*}}MacroDefinition.{{dylib|so|dll}}'","notes":[],"position":{{{.*}}},"severity":"error"}]}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"notMacro","typeName":"NotMacroStruct"},"macroRole":"expression","syntax":{"kind":"expression","location":{{({.+})}},"source":"#notMacro()"}}}
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"notMacro","typeName":"NotMacroStruct"},"macroRole":"expression","staticBuildConfiguration"{{.*}},"syntax":{"kind":"expression","location":{{({.+})}},"source":"#notMacro()"}}}
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[{{{.*}}}],"message":"type 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '{{.*}}MacroDefinition.{{dylib|so|dll}}'","notes":[],"position":{{{.*}}},"severity":"error"}]}}
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")