diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 99f9d05e0eef3..ec88cb660a4f0 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -58,6 +58,7 @@ class IfConfigClauseRangeInfo; class GenericSignature; class GenericSignatureImpl; struct LabeledStmtInfo; +class LangOptions; class LayoutConstraint; class LayoutConstraintInfo; struct LifetimeDescriptor; @@ -82,6 +83,7 @@ enum class RequirementReprKind : unsigned; struct BridgedASTType; class BridgedCanType; class BridgedASTContext; +class BridgedLangOptions; struct BridgedSubstitutionMap; struct BridgedGenericSignature; struct BridgedConformance; @@ -192,15 +194,11 @@ BridgedDeclNameLoc_createParsed(BridgedASTContext cContext, swift::SourceLoc moduleSelectorLoc, swift::SourceLoc baseNameLoc); + //===----------------------------------------------------------------------===// // MARK: ASTContext //===----------------------------------------------------------------------===// -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedEndianness : size_t { - EndianLittle, - EndianBig, -}; - class BridgedASTContext { swift::ASTContext * _Nonnull Ctx; @@ -218,16 +216,10 @@ class BridgedASTContext { unsigned getMajorLanguageVersion() const; SWIFT_COMPUTED_PROPERTY - unsigned getLangOptsTargetPointerBitWidth() const; - - SWIFT_COMPUTED_PROPERTY - bool getLangOptsAttachCommentsToDecls() const; - - SWIFT_COMPUTED_PROPERTY - BridgedEndianness getLangOptsTargetEndianness() const; + BridgedAvailabilityMacroMap getAvailabilityMacroMap() const; SWIFT_COMPUTED_PROPERTY - BridgedAvailabilityMacroMap getAvailabilityMacroMap() const; + BridgedDiagnosticEngine getDiags() const; }; #define IDENTIFIER_WITH_NAME(Name, _) \ @@ -259,56 +251,12 @@ SWIFT_NAME("BridgedASTContext.getDollarIdentifier(self:_:)") swift::Identifier BridgedASTContext_getDollarIdentifier(BridgedASTContext cContext, size_t idx); -SWIFT_NAME("BridgedASTContext.langOptsHasFeature(self:_:)") -bool BridgedASTContext_langOptsHasFeature(BridgedASTContext cContext, - BridgedFeature feature); - -SWIFT_NAME("BridgedASTContext.langOptsCustomConditionSet(self:_:)") -bool BridgedASTContext_langOptsCustomConditionSet(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsHasFeatureNamed(self:_:)") -bool BridgedASTContext_langOptsHasFeatureNamed(BridgedASTContext cContext, - BridgedStringRef cName); +SWIFT_NAME("getter:BridgedASTContext.langOpts(self:)") +BridgedLangOptions BridgedASTContext_langOpts(BridgedASTContext cContext); -SWIFT_NAME("BridgedASTContext.langOptsHasAttributeNamed(self:_:)") -bool BridgedASTContext_langOptsHasAttributeNamed(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetOS(self:_:)") -bool BridgedASTContext_langOptsIsActiveTargetOS(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetArchitecture(self:_:)") -bool BridgedASTContext_langOptsIsActiveTargetArchitecture(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetEnvironment(self:_:)") -bool BridgedASTContext_langOptsIsActiveTargetEnvironment(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetRuntime(self:_:)") -bool BridgedASTContext_langOptsIsActiveTargetRuntime(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetPtrAuth(self:_:)") -bool BridgedASTContext_langOptsIsActiveTargetPtrAuth(BridgedASTContext cContext, - BridgedStringRef cName); - -SWIFT_NAME("BridgedASTContext.langOptsGetTargetAtomicBitWidths(self:_:)") -SwiftInt BridgedASTContext_langOptsGetTargetAtomicBitWidths(BridgedASTContext cContext, - SwiftInt* _Nullable * _Nonnull cComponents); - -SWIFT_NAME("BridgedASTContext.langOptsGetLanguageVersion(self:_:)") -SwiftInt BridgedASTContext_langOptsGetLanguageVersion(BridgedASTContext cContext, - SwiftInt* _Nullable * _Nonnull cComponents); - -SWIFT_NAME("BridgedASTContext.langOptsGetCompilerVersion(self:_:)") -SwiftInt BridgedASTContext_langOptsGetCompilerVersion(BridgedASTContext cContext, - SwiftInt* _Nullable * _Nonnull cComponents); - -/* Deallocate an array of Swift int values that was allocated in C++. */ -void deallocateIntBuffer(SwiftInt * _Nullable cComponents); +SWIFT_NAME("BridgedLangOptions.hasAttributeNamed(self:_:)") +bool BridgedLangOptions_hasAttributeNamed(BridgedLangOptions cLangOpts, + BridgedStringRef cName); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedCanImportVersion : size_t { CanImportUnversioned, @@ -324,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 //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 3d8d55b673c87..b71a98e3b140d 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -66,6 +66,17 @@ swift::DeclNameLoc BridgedDeclNameLoc::unbridged() const { return swift::DeclNameLoc(LocationInfo, NumArgumentLabels); } +//===----------------------------------------------------------------------===// +// MARK: BridgedLangOptions +//===----------------------------------------------------------------------===// + +BridgedLangOptions::BridgedLangOptions(const swift::LangOptions &langOpts) + : LangOpts(&langOpts) { } + +const swift::LangOptions &BridgedLangOptions::unbridged() const { + return *LangOpts; +} + //===----------------------------------------------------------------------===// // MARK: BridgedASTContext //===----------------------------------------------------------------------===// diff --git a/include/swift/AST/ASTContextGlobalCache.h b/include/swift/AST/ASTContextGlobalCache.h index a57e5bc249f66..e4aeb0415232f 100644 --- a/include/swift/AST/ASTContextGlobalCache.h +++ b/include/swift/AST/ASTContextGlobalCache.h @@ -84,6 +84,10 @@ struct ASTContext::GlobalCache { const NormalProtocolConformance *, std::vector > conformanceIsolationErrors; + + /// The static build configuration. This points to an instance of the Swift + /// StaticBuildConfiguration. + void *StaticBuildConfiguration = nullptr; }; } // end namespace diff --git a/include/swift/Basic/BasicBridging.h b/include/swift/Basic/BasicBridging.h index 0c7f3d20bab8d..f0b1073e51b0b 100644 --- a/include/swift/Basic/BasicBridging.h +++ b/include/swift/Basic/BasicBridging.h @@ -61,6 +61,7 @@ class VersionTuple; } // end namespace llvm namespace swift { +class LangOptions; class SourceLoc; class SourceRange; class CharSourceRange; @@ -451,6 +452,84 @@ 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.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 diff --git a/include/swift/Bridging/BasicSwift.h b/include/swift/Bridging/BasicSwift.h new file mode 100644 index 0000000000000..a2cb3f8fea606 --- /dev/null +++ b/include/swift/Bridging/BasicSwift.h @@ -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 diff --git a/include/swift/Bridging/MacroEvaluation.h b/include/swift/Bridging/MacroEvaluation.h index 1df6e130ee1db..650accc61122c 100644 --- a/include/swift/Bridging/MacroEvaluation.h +++ b/include/swift/Bridging/MacroEvaluation.h @@ -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, diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index fcd6324279222..68101735374a6 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -326,6 +326,10 @@ class FrontendOptions { /// exit. bool PrintTargetInfo = false; + /// Indicates that the frontend should print the static build configuration + /// information as JSON. + bool PrintBuildConfig = false; + /// Indicates that the frontend should print the supported features and then /// exit. bool PrintSupportedFeatures = false; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index e99cdc850671f..b25c87080876c 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1542,6 +1542,9 @@ def target_legacy_spelling : Joined<["--"], "target=">, def print_target_info : Flag<["-"], "print-target-info">, Flags<[FrontendOption]>, HelpText<"Print target information for the given target , such as x86_64-apple-macos10.9">, MetaVarName<"">; +def print_static_build_config : Flag<["-"], "print-static-build-config">, + Flags<[FrontendOption]>, + HelpText<"Print static build configuration that can be used to evaluate #ifs in Swift source code">; def print_supported_features : Flag<["-"], "print-supported-features">, Flags<[FrontendOption]>, diff --git a/lib/AST/Bridging/ASTContextBridging.cpp b/lib/AST/Bridging/ASTContextBridging.cpp index 36ef1677768e2..18eaf236ebc81 100644 --- a/lib/AST/Bridging/ASTContextBridging.cpp +++ b/lib/AST/Bridging/ASTContextBridging.cpp @@ -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; @@ -36,114 +38,16 @@ Identifier BridgedASTContext_getDollarIdentifier(BridgedASTContext cContext, return cContext.unbridged().getDollarIdentifier(idx); } -bool BridgedASTContext_langOptsHasFeature(BridgedASTContext cContext, - BridgedFeature feature) { - return cContext.unbridged().LangOpts.hasFeature((Feature)feature); +BridgedLangOptions BridgedASTContext_langOpts(BridgedASTContext cContext) { + return cContext.unbridged().LangOpts; } unsigned BridgedASTContext::getMajorLanguageVersion() const { return unbridged().LangOpts.EffectiveLanguageVersion[0]; } -bool BridgedASTContext_langOptsCustomConditionSet(BridgedASTContext cContext, - BridgedStringRef cName) { - ASTContext &ctx = cContext.unbridged(); - auto name = cName.unbridged(); - if (name.starts_with("$") && ctx.LangOpts.hasFeature(name.drop_front())) - return true; - - return ctx.LangOpts.isCustomConditionalCompilationFlagSet(name); -} - -bool BridgedASTContext_langOptsHasFeatureNamed(BridgedASTContext cContext, - BridgedStringRef cName) { - return cContext.unbridged().LangOpts.hasFeature(cName.unbridged()); -} - -bool BridgedASTContext_langOptsHasAttributeNamed(BridgedASTContext cContext, - BridgedStringRef cName) { - return hasAttribute(cContext.unbridged().LangOpts, cName.unbridged()); -} - -bool BridgedASTContext_langOptsIsActiveTargetOS(BridgedASTContext cContext, - BridgedStringRef cName) { - return cContext.unbridged().LangOpts.checkPlatformCondition( - PlatformConditionKind::OS, cName.unbridged()); -} - -bool BridgedASTContext_langOptsIsActiveTargetArchitecture( - BridgedASTContext cContext, BridgedStringRef cName) { - return cContext.unbridged().LangOpts.checkPlatformCondition( - PlatformConditionKind::Arch, cName.unbridged()); -} - -bool BridgedASTContext_langOptsIsActiveTargetEnvironment( - BridgedASTContext cContext, BridgedStringRef cName) { - return cContext.unbridged().LangOpts.checkPlatformCondition( - PlatformConditionKind::TargetEnvironment, cName.unbridged()); -} - -bool BridgedASTContext_langOptsIsActiveTargetRuntime(BridgedASTContext cContext, - BridgedStringRef cName) { - return cContext.unbridged().LangOpts.checkPlatformCondition( - PlatformConditionKind::Runtime, cName.unbridged()); -} - -bool BridgedASTContext_langOptsIsActiveTargetPtrAuth(BridgedASTContext cContext, - BridgedStringRef cName) { - return cContext.unbridged().LangOpts.checkPlatformCondition( - PlatformConditionKind::PtrAuth, cName.unbridged()); -} - -unsigned BridgedASTContext::getLangOptsTargetPointerBitWidth() const { - return unbridged().LangOpts.Target.isArch64Bit() ? 64 - : unbridged().LangOpts.Target.isArch32Bit() ? 32 - : unbridged().LangOpts.Target.isArch16Bit() ? 16 - : 0; -} - -bool BridgedASTContext::getLangOptsAttachCommentsToDecls() const { - return unbridged().LangOpts.AttachCommentsToDecls; -} - -BridgedEndianness BridgedASTContext::getLangOptsTargetEndianness() const { - return unbridged().LangOpts.Target.isLittleEndian() ? EndianLittle - : EndianBig; -} - -/// Convert an array of numbers into a form we can use in Swift. -namespace { -template -SwiftInt convertArray(const Arr &array, SwiftInt **cElements) { - SwiftInt numElements = array.size(); - *cElements = (SwiftInt *)malloc(sizeof(SwiftInt) * numElements); - for (SwiftInt i = 0; i != numElements; ++i) - (*cElements)[i] = array[i]; - return numElements; -} -} // namespace - -void deallocateIntBuffer(SwiftInt *_Nullable cComponents) { free(cComponents); } - -SwiftInt -BridgedASTContext_langOptsGetLanguageVersion(BridgedASTContext cContext, - SwiftInt **cComponents) { - auto theVersion = cContext.unbridged().LangOpts.EffectiveLanguageVersion; - return convertArray(theVersion, cComponents); -} - -SWIFT_NAME("BridgedASTContext.langOptsGetCompilerVersion(self:_:)") -SwiftInt -BridgedASTContext_langOptsGetCompilerVersion(BridgedASTContext cContext, - SwiftInt **cComponents) { - auto theVersion = version::Version::getCurrentLanguageVersion(); - return convertArray(theVersion, cComponents); -} - -SwiftInt BridgedASTContext_langOptsGetTargetAtomicBitWidths( - BridgedASTContext cContext, SwiftInt *_Nullable *_Nonnull cElements) { - return convertArray(cContext.unbridged().LangOpts.getAtomicBitWidthValues(), - cElements); +BridgedDiagnosticEngine BridgedASTContext::getDiags() const { + return &unbridged().Diags; } bool BridgedASTContext_canImport(BridgedASTContext cContext, @@ -184,3 +88,17 @@ bool BridgedASTContext_canImport(BridgedASTContext cContext, BridgedAvailabilityMacroMap BridgedASTContext::getAvailabilityMacroMap() const { return &unbridged().getAvailabilityMacroMap(); } + +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; +} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 586182c6cc9ce..17b748e1ee468 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -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) diff --git a/lib/ASTGen/Sources/ASTGen/Bridge.swift b/lib/ASTGen/Sources/ASTGen/Bridge.swift index 7846b5245d126..257a4cca8642b 100644 --- a/lib/ASTGen/Sources/ASTGen/Bridge.swift +++ b/lib/ASTGen/Sources/ASTGen/Bridge.swift @@ -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(_ 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) diff --git a/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift b/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift index 8dbe88d23359b..93b6c367d7fd9 100644 --- a/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift +++ b/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift @@ -76,7 +76,7 @@ extension ASTGenVisitor { let keypathExpr = self.generateObjCKeyPathExpr(freestandingMacroExpansion: node) return .generated(.expr(keypathExpr)) - case .assert where ctx.langOptsHasFeature(.StaticAssert): + case .assert where ctx.langOpts.hasFeature(.StaticAssert): let assertStmtOpt = self.generatePoundAssertStmt(freestandingMacroExpansion: node) return .generated(assertStmtOpt.map({ .stmt($0.asStmt) })) @@ -143,7 +143,7 @@ extension ASTGenVisitor { } func generatePoundAssertStmt(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedPoundAssertStmt? { - assert(self.ctx.langOptsHasFeature(.StaticAssert)) + assert(self.ctx.langOpts.hasFeature(.StaticAssert)) var args = node.arguments[...] let conditionExpr = self.generateConsumingAttrOption(args: &args, label: nil) { conditionNode in self.generate(expr: conditionNode) diff --git a/lib/ASTGen/Sources/ASTGen/CMakeLists.txt b/lib/ASTGen/Sources/ASTGen/CMakeLists.txt index 0094fbc0c3f28..678a23509cc43 100644 --- a/lib/ASTGen/Sources/ASTGen/CMakeLists.txt +++ b/lib/ASTGen/Sources/ASTGen/CMakeLists.txt @@ -27,6 +27,7 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP DEPENDENCIES swiftAST SWIFT_DEPENDENCIES + _CompilerSwiftCompilerPluginMessageHandling _CompilerRegexParser _CompilerSwiftSyntax _CompilerSwiftIfConfig @@ -36,4 +37,5 @@ add_pure_swift_host_library(swiftASTGen STATIC CXX_INTEROP _CompilerSwiftParser _CompilerSwiftParserDiagnostics _CompilerSwiftDiagnostics + swiftBasicSwift ) diff --git a/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift b/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift index 257b02362f8f1..3dbc62d4d760a 100644 --- a/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift +++ b/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift @@ -10,42 +10,46 @@ // //===----------------------------------------------------------------------===// +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 { let ctx: BridgedASTContext + let staticBuildConfiguration: StaticBuildConfiguration let sourceBuffer: UnsafeBufferPointer init(ctx: BridgedASTContext, sourceBuffer: UnsafeBufferPointer) { self.ctx = ctx + self.staticBuildConfiguration = ctx.staticBuildConfiguration self.sourceBuffer = sourceBuffer } - func isCustomConditionSet(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsCustomConditionSet(nameRef) - } + func isCustomConditionSet(name: String) -> Bool { + staticBuildConfiguration.isCustomConditionSet(name: name) } - func hasFeature(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsHasFeatureNamed(nameRef) - } + func hasFeature(name: String) -> Bool { + staticBuildConfiguration.hasFeature(name: name) } - func hasAttribute(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsHasAttributeNamed(nameRef) - } + func hasAttribute(name: String) -> Bool { + staticBuildConfiguration.hasAttribute(name: name) } func canImport( @@ -86,85 +90,50 @@ struct CompilerBuildConfiguration: BuildConfiguration { } } - func isActiveTargetOS(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsIsActiveTargetOS(nameRef) - } + func isActiveTargetOS(name: String) -> Bool { + staticBuildConfiguration.isActiveTargetOS(name: name) } - func isActiveTargetArchitecture(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsIsActiveTargetArchitecture(nameRef) - } + func isActiveTargetArchitecture(name: String) -> Bool { + staticBuildConfiguration.isActiveTargetArchitecture(name: name) } - func isActiveTargetEnvironment(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsIsActiveTargetEnvironment(nameRef) - } + func isActiveTargetEnvironment(name: String) -> Bool { + staticBuildConfiguration.isActiveTargetEnvironment(name: name) } func isActiveTargetRuntime(name: String) throws -> Bool { - var name = name - // Complain if the provided runtime isn't one of the known values. switch name { case "_Native", "_ObjC", "_multithreaded": break default: throw IfConfigError.unexpectedRuntimeCondition } - return name.withBridgedString { nameRef in - ctx.langOptsIsActiveTargetRuntime(nameRef) - } + return staticBuildConfiguration.isActiveTargetRuntime(name: name) } - - func isActiveTargetPointerAuthentication(name: String) throws -> Bool { - var name = name - return name.withBridgedString { nameRef in - ctx.langOptsIsActiveTargetPtrAuth(nameRef) - } + + func isActiveTargetPointerAuthentication(name: String) -> Bool { + staticBuildConfiguration.isActiveTargetPointerAuthentication(name: name) } var targetPointerBitWidth: Int { - Int(ctx.langOptsTargetPointerBitWidth) + staticBuildConfiguration.targetPointerBitWidth } var targetAtomicBitWidths: [Int] { - var bitWidthsBuf: UnsafeMutablePointer? = nil - let count = ctx.langOptsGetTargetAtomicBitWidths(&bitWidthsBuf) - let bitWidths = Array(UnsafeMutableBufferPointer(start: bitWidthsBuf, count: count)) - deallocateIntBuffer(bitWidthsBuf); - return bitWidths + staticBuildConfiguration.targetAtomicBitWidths } var endianness: Endianness { - switch ctx.langOptsTargetEndianness { - case .EndianBig: return .big - case .EndianLittle: return .little - } + staticBuildConfiguration.endianness } - var languageVersion: VersionTuple { - var componentsBuf: UnsafeMutablePointer? = nil - let count = ctx.langOptsGetLanguageVersion(&componentsBuf) - let version = VersionTuple( - components: Array(UnsafeMutableBufferPointer(start: componentsBuf, count: count)) - ) - deallocateIntBuffer(componentsBuf); - return version + var languageVersion: VersionTuple { + staticBuildConfiguration.languageVersion } - var compilerVersion: VersionTuple { - var componentsBuf: UnsafeMutablePointer? = nil - let count = ctx.langOptsGetCompilerVersion(&componentsBuf) - let version = VersionTuple( - components: Array(UnsafeMutableBufferPointer(start: componentsBuf, count: count)) - ) - deallocateIntBuffer(componentsBuf); - return version + var compilerVersion: VersionTuple { + staticBuildConfiguration.compilerVersion } } diff --git a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift index 50b26985daf02..d8f6c807c3940 100644 --- a/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift +++ b/lib/ASTGen/Sources/ASTGen/DeclAttrs.swift @@ -31,7 +31,7 @@ extension ASTGenVisitor { // Comments. COMMENT: if - self.ctx.langOptsAttachCommentsToDecls, + self.ctx.langOpts.attachCommentsToDecls, let firstTok = node.firstToken(viewMode: .sourceAccurate) { var pos = firstTok.position @@ -2228,7 +2228,7 @@ extension ASTGenVisitor { } func generateUnavailableInEmbeddedAttr(attribute node: AttributeSyntax) -> BridgedAvailableAttr? { - if ctx.langOptsHasFeature(.Embedded) { + if ctx.langOpts.hasFeature(.Embedded) { return BridgedAvailableAttr.createUnavailableInEmbedded( self.ctx, atLoc: self.generateSourceLoc(node.atSign), diff --git a/lib/ASTGen/Sources/ASTGen/Decls.swift b/lib/ASTGen/Sources/ASTGen/Decls.swift index 4fc9d279cdcd9..5d0b78fbc2ea7 100644 --- a/lib/ASTGen/Sources/ASTGen/Decls.swift +++ b/lib/ASTGen/Sources/ASTGen/Decls.swift @@ -396,10 +396,10 @@ extension ASTGenVisitor { case .`init`: return .Init case .read: - precondition(ctx.langOptsHasFeature(.CoroutineAccessors), "(compiler bug) 'read' accessor should only be parsed with 'CoroutineAccessors' feature") + precondition(ctx.langOpts.hasFeature(.CoroutineAccessors), "(compiler bug) 'read' accessor should only be parsed with 'CoroutineAccessors' feature") return .read case .modify: - precondition(ctx.langOptsHasFeature(.CoroutineAccessors), "(compiler bug) 'modify' accessor should only be parsed with 'CoroutineAccessors' feature") + precondition(ctx.langOpts.hasFeature(.CoroutineAccessors), "(compiler bug) 'modify' accessor should only be parsed with 'CoroutineAccessors' feature") return .modify default: self.diagnose(.unknownAccessorSpecifier(specifier)) diff --git a/lib/ASTGen/Sources/ASTGen/EmbeddedSupport.swift b/lib/ASTGen/Sources/ASTGen/EmbeddedSupport.swift index 3de35744eeb2f..0dfc9fa768fbe 100644 --- a/lib/ASTGen/Sources/ASTGen/EmbeddedSupport.swift +++ b/lib/ASTGen/Sources/ASTGen/EmbeddedSupport.swift @@ -68,26 +68,26 @@ struct EmbeddedBuildConfiguration: BuildConfiguration { self.configuration = .init(ctx: ctx, sourceBuffer: sourceBuffer) } - func isCustomConditionSet(name: String) throws -> Bool { + func isCustomConditionSet(name: String) -> Bool { // $Embedded is set when building Embedded Swift if name == "$Embedded" { return true } - return try configuration.isCustomConditionSet(name: name) + return configuration.isCustomConditionSet(name: name) } - func hasFeature(name: String) throws -> Bool { + func hasFeature(name: String) -> Bool { // The "Embedded" feature is set when building Embedded Swift. if name == "Embedded" { return true } - return try configuration.hasFeature(name: name) + return configuration.hasFeature(name: name) } - func hasAttribute(name: String) throws -> Bool { - return try configuration.hasAttribute(name: name) + func hasAttribute(name: String) -> Bool { + return configuration.hasAttribute(name: name) } func canImport( @@ -100,24 +100,24 @@ struct EmbeddedBuildConfiguration: BuildConfiguration { return false } - func isActiveTargetOS(name: String) throws -> Bool { - return try configuration.isActiveTargetOS(name: name) + func isActiveTargetOS(name: String) -> Bool { + return configuration.isActiveTargetOS(name: name) } - func isActiveTargetArchitecture(name: String) throws -> Bool { - return try configuration.isActiveTargetArchitecture(name: name) + func isActiveTargetArchitecture(name: String) -> Bool { + return configuration.isActiveTargetArchitecture(name: name) } - func isActiveTargetEnvironment(name: String) throws -> Bool { - return try configuration.isActiveTargetEnvironment(name: name) + func isActiveTargetEnvironment(name: String) -> Bool { + return configuration.isActiveTargetEnvironment(name: name) } func isActiveTargetRuntime(name: String) throws -> Bool { return try configuration.isActiveTargetRuntime(name: name) } - func isActiveTargetPointerAuthentication(name: String) throws -> Bool { - return try configuration.isActiveTargetPointerAuthentication(name: name) + func isActiveTargetPointerAuthentication(name: String) -> Bool { + return configuration.isActiveTargetPointerAuthentication(name: name) } var targetPointerBitWidth: Int { diff --git a/lib/ASTGen/Sources/ASTGen/Exprs.swift b/lib/ASTGen/Sources/ASTGen/Exprs.swift index bd69b2b3a6054..c30c23e06fc50 100644 --- a/lib/ASTGen/Sources/ASTGen/Exprs.swift +++ b/lib/ASTGen/Sources/ASTGen/Exprs.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import ASTBridging +import swiftBasicSwift import SwiftDiagnostics @_spi(Compiler) import SwiftParser @_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax diff --git a/lib/ASTGen/Sources/ASTGen/SourceFile.swift b/lib/ASTGen/Sources/ASTGen/SourceFile.swift index c9981bd320063..cfe23e0be7318 100644 --- a/lib/ASTGen/Sources/ASTGen/SourceFile.swift +++ b/lib/ASTGen/Sources/ASTGen/SourceFile.swift @@ -72,7 +72,7 @@ extension Parser.ExperimentalFeatures { guard let context = context else { return } func mapFeature(_ bridged: BridgedFeature, to feature: Self) { - if context.langOptsHasFeature(bridged) { + if context.langOpts.hasFeature(bridged) { insert(feature) } } diff --git a/lib/ASTGen/Sources/BasicSwift/CMakeLists.txt b/lib/ASTGen/Sources/BasicSwift/CMakeLists.txt new file mode 100644 index 0000000000000..beeb67ef70cc2 --- /dev/null +++ b/lib/ASTGen/Sources/BasicSwift/CMakeLists.txt @@ -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 +) diff --git a/lib/ASTGen/Sources/BasicSwift/StaticBuildConfiguration+LangOptions.swift b/lib/ASTGen/Sources/BasicSwift/StaticBuildConfiguration+LangOptions.swift new file mode 100644 index 0000000000000..7bdd51e6ae3f3 --- /dev/null +++ b/lib/ASTGen/Sources/BasicSwift/StaticBuildConfiguration+LangOptions.swift @@ -0,0 +1,149 @@ +//===--- StaticBuildConfiguration+ASTContext.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 ASTBridging +@_spi(PluginMessage) import SwiftCompilerPluginMessageHandling +import SwiftDiagnostics +@_spi(Compiler) import SwiftIfConfig +@_spi(ExperimentalLanguageFeatures) import SwiftParser +@_spi(ExperimentalLanguageFeatures) import SwiftSyntax + +extension StaticBuildConfiguration { + /// Configuration entries captured in the initializer from a bridged context. + private struct ConfigurationEntries { + var customConditions: Set = [] + var features: Set = [] + var attributes: Set = [] + var targetOSNames: Set = [] + var targetArchitectures: Set = [] + var targetEnvironments: Set = [] + var targetRuntimes: Set = [] + var targetPointerAuthenticationSchemes: Set = [] + var targetObjectFileFormats: Set = [] + } + + /// Initialize a static build configuration for the given language options. + init(langOptions: BridgedLangOptions) { + var entries = ConfigurationEntries() + + langOptions.enumerateBuildConfigurationEntries(callbackContext: &entries) { cContext, entries, key, value in + let entries = entries.assumingMemoryBound(to: ConfigurationEntries.self) + switch key { + case .BCKAttribute: + entries.pointee.attributes.insert(String(bridged: value)) + case .BCKCustomCondition: + entries.pointee.customConditions.insert(String(bridged: value)) + case .BCKFeature: + entries.pointee.features.insert(String(bridged: value)) + case .BCKTargetOSName: + entries.pointee.targetOSNames.insert(String(bridged: value)) + case .BCKTargetArchitecture: + entries.pointee.targetArchitectures.insert(String(bridged: value)) + case .BCKTargetEnvironment: + entries.pointee.targetEnvironments.insert(String(bridged: value)) + case .BCKTargetRuntime: + entries.pointee.targetRuntimes.insert(String(bridged: value)) + case .BCKTargetPointerAuthenticationScheme: + entries.pointee.targetPointerAuthenticationSchemes.insert(String(bridged: value)) + case .BCKTargetObjectFileFormat: + entries.pointee.targetObjectFileFormats.insert(String(bridged: value)) + } + } + + let targetPointerBitWidth = Int(langOptions.targetPointerBitWidth) + + // Atomic bit widths. + let targetAtomicBitWidths: [Int] + do { + var bitWidthsBuf: UnsafeMutablePointer? = nil + let bitWidthsCount = langOptions.getTargetAtomicBitWidths(&bitWidthsBuf) + targetAtomicBitWidths = Array(UnsafeMutableBufferPointer(start: bitWidthsBuf, count: bitWidthsCount)) + deallocateIntBuffer(bitWidthsBuf); + } + + let endianness: Endianness + switch langOptions.targetEndianness { + case .EndianBig: endianness = .big + case .EndianLittle: endianness = .little + } + + let languageVersion = getVersionTuple { langOptions.getLanguageVersion(&$0) } + let compilerVersion = getVersionTuple { langOptions.getCompilerVersion(&$0) } + self.init( + customConditions: entries.customConditions, + features: entries.features, + attributes: entries.attributes, + targetOSs: entries.targetOSNames, + targetArchitectures: entries.targetArchitectures, + targetEnvironments: entries.targetEnvironments, + targetRuntimes: entries.targetRuntimes, + targetPointerAuthenticationSchemes: entries.targetPointerAuthenticationSchemes, + targetObjectFileFormats: entries.targetObjectFileFormats, + targetPointerBitWidth: targetPointerBitWidth, + targetAtomicBitWidths: targetAtomicBitWidths, + endianness: endianness, + languageVersion: languageVersion, + compilerVersion: compilerVersion + ) + } +} + +/// Get a version tuple from C++. +private func getVersionTuple( + body: (inout UnsafeMutablePointer?) -> Int +) -> VersionTuple { + var componentsBuf: UnsafeMutablePointer? = nil + let count = body(&componentsBuf) + let version = VersionTuple( + components: Array(UnsafeMutableBufferPointer(start: componentsBuf, count: count)) + ) + deallocateIntBuffer(componentsBuf); + return version +} + +@_cdecl("swift_ASTGen_printStaticBuildConfiguration") +public func printStaticBuildConfiguration( + langOptions: BridgedLangOptions +) -> BridgedStringRef { + let config = StaticBuildConfiguration(langOptions: langOptions) + let result = try? JSON.encode(config).withUnsafeBufferPointer { buffer in + let ptr = UnsafeMutablePointer.allocate( + capacity: buffer.count + 1 + ) + if let baseAddress = buffer.baseAddress { + ptr.initialize(from: baseAddress, count: buffer.count) + } + + // null terminate, for client's convenience. + ptr[buffer.count] = 0 + + return BridgedStringRef(data: ptr, count: buffer.count) + } + + return result ?? BridgedStringRef() +} + +@_cdecl("swift_Basic_createStaticBuildConfiguration") +public func createStaticBuildConfiguration( + cLangOpts: BridgedLangOptions +) -> UnsafeMutableRawPointer { + let storage = UnsafeMutablePointer.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() +} diff --git a/lib/ASTGen/Sources/BasicSwift/String+BridgedString.swift b/lib/ASTGen/Sources/BasicSwift/String+BridgedString.swift new file mode 100644 index 0000000000000..ef7fcdb4e6e5b --- /dev/null +++ b/lib/ASTGen/Sources/BasicSwift/String+BridgedString.swift @@ -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(_ body: (BridgedStringRef) throws -> R) rethrows -> R { + try withUTF8 { buffer in + try body(BridgedStringRef(data: buffer.baseAddress, count: buffer.count)) + } + } +} diff --git a/lib/ASTGen/Sources/CMakeLists.txt b/lib/ASTGen/Sources/CMakeLists.txt index 57efe7eddacee..1e2f2816f2cbb 100644 --- a/lib/ASTGen/Sources/CMakeLists.txt +++ b/lib/ASTGen/Sources/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(BasicSwift) add_subdirectory(ASTGen) add_subdirectory(MacroEvaluation) add_subdirectory(SwiftIDEUtilsBridging) diff --git a/lib/ASTGen/Sources/MacroEvaluation/Macros.swift b/lib/ASTGen/Sources/MacroEvaluation/Macros.swift index 2845418be557a..91068283a0d0c 100644 --- a/lib/ASTGen/Sources/MacroEvaluation/Macros.swift +++ b/lib/ASTGen/Sources/MacroEvaluation/Macros.swift @@ -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, 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, 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, qualifiedTypeText: UnsafePointer, @@ -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) + } + } +} diff --git a/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift b/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift index f4d1b64f4bb19..85005e2f64fa9 100644 --- a/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift +++ b/lib/ASTGen/Sources/MacroEvaluation/PluginHost.swift @@ -201,8 +201,8 @@ class PluginDiagnosticsEngine { private let bridgedDiagEngine: BridgedDiagnosticEngine private var exportedSourceFileByName: [String: UnsafePointer] = [:] - init(cxxDiagnosticEngine: UnsafeMutableRawPointer) { - self.bridgedDiagEngine = BridgedDiagnosticEngine(raw: cxxDiagnosticEngine) + init(cContext: BridgedASTContext) { + self.bridgedDiagEngine = cContext.diags } /// Failable convenience initializer for optional cxx engine pointer. diff --git a/lib/ASTGen/Sources/MacroEvaluation/SourceManager.swift b/lib/ASTGen/Sources/MacroEvaluation/SourceManager.swift index df35475f5ae74..1011d2652419a 100644 --- a/lib/ASTGen/Sources/MacroEvaluation/SourceManager.swift +++ b/lib/ASTGen/Sources/MacroEvaluation/SourceManager.swift @@ -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 diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 8dea0082b88fe..b75e0c8377121 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -59,6 +59,7 @@ add_swift_host_library(swiftBasic STATIC ParseableOutput.cpp JSONSerialization.cpp LangOptions.cpp + LangOptionsBridging.cpp LoadDynamicLibrary.cpp Located.cpp Mangler.cpp diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 7d6e0a1eafceb..114b81a20ae53 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -252,6 +252,9 @@ LangOptions::getPlatformConditionValue(PlatformConditionKind Kind) const { bool LangOptions:: checkPlatformCondition(PlatformConditionKind Kind, StringRef Value) const { + // Note: BridgedASTContext_enumerateBuildConfigurationEntries has a redundant + // copy of these special cases. + // Check a special case that "macOS" is an alias of "OSX". if (Kind == PlatformConditionKind::OS && Value == "macOS") return checkPlatformCondition(Kind, "OSX"); diff --git a/lib/Basic/LangOptionsBridging.cpp b/lib/Basic/LangOptionsBridging.cpp new file mode 100644 index 0000000000000..5ccc2a8ea1df0 --- /dev/null +++ b/lib/Basic/LangOptionsBridging.cpp @@ -0,0 +1,265 @@ +//===--- Bridging/LangOptsBridging.cpp ------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/ASTBridging.h" + +#include "swift/Basic/LangOptions.h" + +using namespace swift; + +bool BridgedLangOptions_hasFeature(BridgedLangOptions cLangOpts, + BridgedFeature feature) { + return cLangOpts.unbridged().hasFeature((Feature)feature); +} + + +unsigned BridgedLangOptions::getTargetPointerBitWidth() const { + return unbridged().Target.isArch64Bit() ? 64 + : unbridged().Target.isArch32Bit() ? 32 + : unbridged().Target.isArch16Bit() ? 16 + : 0; +} + +BridgedEndianness BridgedLangOptions::getTargetEndianness() const { + return unbridged().Target.isLittleEndian() ? EndianLittle : EndianBig; +} + +bool BridgedLangOptions::getAttachCommentsToDecls() const { + return unbridged().AttachCommentsToDecls; +} + +/// Convert an array of numbers into a form we can use in Swift. +namespace { +template +SwiftInt convertArray(const Arr &array, SwiftInt **cElements) { + SwiftInt numElements = array.size(); + *cElements = (SwiftInt *)malloc(sizeof(SwiftInt) * numElements); + for (SwiftInt i = 0; i != numElements; ++i) + (*cElements)[i] = array[i]; + return numElements; +} +} // namespace + +void deallocateIntBuffer(SwiftInt *_Nullable cComponents) { free(cComponents); } + +SwiftInt +BridgedLangOptions_getLanguageVersion(BridgedLangOptions cLangOpts, + SwiftInt **cComponents) { + auto theVersion = cLangOpts.unbridged().EffectiveLanguageVersion; + return convertArray(theVersion, cComponents); +} + +SwiftInt +BridgedLangOptions_getCompilerVersion(BridgedLangOptions cLangOpts, + SwiftInt **cComponents) { + auto theVersion = version::Version::getCurrentLanguageVersion(); + return convertArray(theVersion, cComponents); +} + +SwiftInt BridgedLangOptions_getTargetAtomicBitWidths( + BridgedLangOptions cLangOpts, SwiftInt *_Nullable *_Nonnull cElements) { + return convertArray(cLangOpts.unbridged().getAtomicBitWidthValues(), + 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, + void (* _Nonnull callback)( + BridgedLangOptions cLangOpts, void * _Nonnull callbackContext, + BuildConfigurationKey key, BridgedStringRef value)) { + const LangOptions &langOpts = cLangOpts.unbridged(); + + // Enumerate custom conditions. + for (const auto &customCondition: langOpts.getCustomConditionalCompilationFlags()) { + callback(cLangOpts, callbackContext, BCKCustomCondition, + StringRef(customCondition)); + } + + // Enumerate features that are enabled. +#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \ + if (langOpts.hasFeature(Feature::FeatureName)) \ + callback(cLangOpts, callbackContext, BCKFeature, StringRef(#FeatureName)); +#include "swift/Basic/Features.def" + + // Enumerate attributes that are available. +#define DECL_ATTR(SPELLING, CLASS, REQUIREMENTS, BEHAVIORS, CODE) \ + 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) \ + callback(cLangOpts, callbackContext, BCKAttribute, StringRef(#SPELLING)); +#include "swift/AST/TypeAttr.def" + + // Deal with all of the target platform/architecture information. + for (const auto &[kind, value] : langOpts.getPlatformConditionValues()) { + switch (kind) { + case PlatformConditionKind::OS: + callback(cLangOpts, callbackContext, BCKTargetOSName, StringRef(value)); + + // Special case that macOS is an alias of OSX. + if (value == "OSX") { + callback(cLangOpts, callbackContext, BCKTargetOSName, + StringRef("macOS")); + } + break; + + case PlatformConditionKind::Arch: + callback(cLangOpts, callbackContext, BCKTargetArchitecture, StringRef(value)); + break; + + case PlatformConditionKind::Runtime: + callback(cLangOpts, callbackContext, BCKTargetRuntime, StringRef(value)); + break; + + case PlatformConditionKind::TargetEnvironment: + callback(cLangOpts, callbackContext, BCKTargetEnvironment, + StringRef(value)); + + // When compiling for iOS we consider "macCatalyst" to be a + // synonym of "macabi". This enables the use of + // #if targetEnvironment(macCatalyst) as a compilation + // condition for macCatalyst. + if (value == "macabi" && langOpts.Target.isiOS()) { + callback(cLangOpts, callbackContext, BCKTargetEnvironment, + StringRef("macCatalyst")); + } + break; + + case PlatformConditionKind::PtrAuth: + callback(cLangOpts, callbackContext, BCKTargetPointerAuthenticationScheme, + StringRef(value)); + break; + + case PlatformConditionKind::Endianness: + case PlatformConditionKind::PointerBitWidth: + case PlatformConditionKind::CanImport: + case PlatformConditionKind::HasAtomicBitWidth: + // Handled separately. + break; + } + } + + // Object file format. + llvm::Triple triple(langOpts.Target.getTriple()); + switch (triple.getObjectFormat()) { + case llvm::Triple::ObjectFormatType::COFF: + callback(cLangOpts, callbackContext, BCKTargetObjectFileFormat, + StringRef("COFF")); + break; + case llvm::Triple::ObjectFormatType::ELF: + callback(cLangOpts, callbackContext, BCKTargetObjectFileFormat, + StringRef("ELF")); + break; + case llvm::Triple::ObjectFormatType::MachO: + callback(cLangOpts, callbackContext, BCKTargetObjectFileFormat, + StringRef("MachO")); + break; + case llvm::Triple::ObjectFormatType::SPIRV: + callback(cLangOpts, callbackContext, BCKTargetObjectFileFormat, + StringRef("SPIRV")); + break; + case llvm::Triple::ObjectFormatType::Wasm: + callback(cLangOpts, callbackContext, BCKTargetObjectFileFormat, + StringRef("Wasm")); + break; + default: + // Ignore others. + break; + } +} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 60903dd63226d..fc81cd8dd8779 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1985,6 +1985,27 @@ bool Driver::handleImmediateArgs(const ArgList &Args, const ToolChain &TC) { return false; } + if (Args.hasArg(options::OPT_print_static_build_config)) { + SmallVector commandLine; + commandLine.push_back("-frontend"); + commandLine.push_back("-print-static-build-config"); + + std::string executable = getSwiftProgramPath(); + + // FIXME(https://github.com/apple/swift/issues/54554): This bypasses + // mechanisms like -v and -###. + sys::TaskQueue queue; + queue.addTask(executable.c_str(), commandLine); + queue.execute(nullptr, + [](sys::ProcessId PID, int returnCode, StringRef output, + StringRef errors, sys::TaskProcessInformation ProcInfo, + void *unused) -> sys::TaskFinishedResponse { + llvm::outs() << output; + llvm::errs() << errors; + return sys::TaskFinishedResponse::ContinueExecution; + }); + return false; + } return true; } diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 84a7045a7d184..8e20de012dea8 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -210,6 +210,10 @@ bool ArgsToFrontendOptionsConverter::convert( Opts.PrintTargetInfo = true; } + if (Args.hasArg(OPT_print_static_build_config)) { + Opts.PrintBuildConfig = true; + } + if (Args.hasArg(OPT_print_supported_features)) { Opts.PrintSupportedFeatures = true; } diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt index e21505a2d6c57..e5001cde931af 100644 --- a/lib/FrontendTool/CMakeLists.txt +++ b/lib/FrontendTool/CMakeLists.txt @@ -27,4 +27,9 @@ target_link_libraries(swiftFrontendTool PRIVATE swiftSILOptimizer swiftThreading) +if (SWIFT_BUILD_SWIFT_SYNTAX) + target_link_libraries(swiftFrontendTool PRIVATE + swiftASTGen) +endif() + set_swift_llvm_is_available(swiftFrontendTool) diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 7544562cfe3d3..de7f4ada33625 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -23,6 +23,7 @@ #include "swift/FrontendTool/FrontendTool.h" #include "Dependencies.h" #include "TBD.h" +#include "swift/AST/ASTBridging.h" #include "swift/AST/ASTDumper.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/AvailabilityScope.h" @@ -38,6 +39,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/TBDGenRequests.h" #include "swift/Basic/Assertions.h" +#include "swift/Basic/BasicBridging.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Edit.h" #include "swift/Basic/FileSystem.h" @@ -50,6 +52,7 @@ #include "swift/Basic/TargetInfo.h" #include "swift/Basic/UUID.h" #include "swift/Basic/Version.h" +#include "swift/Bridging/ASTGen.h" #include "swift/ConstExtract/ConstExtract.h" #include "swift/DependencyScan/ScanDependencies.h" #include "swift/Frontend/CachedDiagnostics.h" @@ -2255,6 +2258,14 @@ class PrettyStackTraceFrontend : public llvm::PrettyStackTraceEntry { }; }; +#if SWIFT_BUILD_SWIFT_SYNTAX +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" BridgedStringRef +swift_ASTGen_printStaticBuildConfiguration(BridgedLangOptions cLangOpts); +#pragma clang diagnostic pop +#endif + int swift::performFrontend(ArrayRef Args, const char *Argv0, void *MainAddr, FrontendObserver *observer) { @@ -2385,6 +2396,16 @@ int swift::performFrontend(ArrayRef Args, return finishDiagProcessing(0, /*verifierEnabled*/ false); } + if (Invocation.getFrontendOptions().PrintBuildConfig) { +#if SWIFT_BUILD_SWIFT_SYNTAX + auto resultText = + swift_ASTGen_printStaticBuildConfiguration(Invocation.getLangOptions()); + llvm::outs() << resultText.unbridged(); + swift_ASTGen_freeBridgedString(resultText); +#endif + return finishDiagProcessing(0, /*verifierEnabled*/ false); + } + if (Invocation.getFrontendOptions().PrintSupportedFeatures) { swift::features::printSupportedFeatures(llvm::outs()); return finishDiagProcessing(0, /*verifierEnabled*/ false); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index bac848bc387be..6ed62e2974084 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -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(), diff --git a/test/Frontend/print-static-build-config.swift b/test/Frontend/print-static-build-config.swift new file mode 100644 index 0000000000000..70ac0c9a12fb4 --- /dev/null +++ b/test/Frontend/print-static-build-config.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-frontend -print-static-build-config -DSOMETHING | %FileCheck %s +// REQUIRES: swift_swift_parser + +// CHECK: "attributes": +// CHECK-SAME: "escaping" + +// CHECK-SAME: "customConditions":["SOMETHING"] + +// CHECK-SAME: "features": +// CHECK-SAME: "AttachedMacros" diff --git a/test/Macros/Inputs/syntax_macro_definitions.swift b/test/Macros/Inputs/syntax_macro_definitions.swift index 7eee73fb6ca2b..2dc4a73c70047 100644 --- a/test/Macros/Inputs/syntax_macro_definitions.swift +++ b/test/Macros/Inputs/syntax_macro_definitions.swift @@ -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)" + } +} diff --git a/test/Macros/macro_build_config.swift b/test/Macros/macro_build_config.swift new file mode 100644 index 0000000000000..2a1083ef3fb9d --- /dev/null +++ b/test/Macros/macro_build_config.swift @@ -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"))") diff --git a/test/Macros/macro_plugin_basic.swift b/test/Macros/macro_plugin_basic.swift index 3208b0e73fed9..b85c90a7e89c8 100644 --- a/test/Macros/macro_plugin_basic.swift +++ b/test/Macros/macro_plugin_basic.swift @@ -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 diff --git a/test/Macros/macro_plugin_error.swift b/test/Macros/macro_plugin_error.swift index a4d6bd3865df3..becbcda13afcc 100644 --- a/test/Macros/macro_plugin_error.swift +++ b/test/Macros/macro_plugin_error.swift @@ -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 diff --git a/test/Macros/macro_plugin_server.swift b/test/Macros/macro_plugin_server.swift index 673bf64311f5b..fa9e20574aec6 100644 --- a/test/Macros/macro_plugin_server.swift +++ b/test/Macros/macro_plugin_server.swift @@ -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(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")