From b18734b5205c76c89d10b399344f0fd05b0b3765 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Fri, 21 Mar 2025 13:35:37 -0700 Subject: [PATCH 1/2] Add #_objectFileFormat compilation conditional --- include/swift/AST/ASTBridging.h | 3 ++ include/swift/AST/PlatformConditionKinds.def | 3 ++ lib/AST/Bridging/ASTContextBridging.cpp | 7 +++++ .../ASTGen/CompilerBuildConfiguration.swift | 7 +++++ lib/Basic/LangOptions.cpp | 31 ++++++++++++++++--- lib/Parse/ParseIfConfig.cpp | 4 ++- .../object_file_format.swift | 11 +++++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 test/Parse/ConditionalCompilation/object_file_format.swift diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index be5331dc56454..678c3186b3934 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -324,6 +324,9 @@ bool BridgedASTContext_langOptsAttachCommentsToDecls( SWIFT_NAME("getter:BridgedASTContext.langOptsTargetEndianness(self:)") BridgedEndianness BridgedASTContext_langOptsTargetEndianness(BridgedASTContext cContext); +SWIFT_NAME("BridgedASTContext.langOptsIsActiveTargetObjectFileFormat(self:_:)") +bool BridgedASTContext_langOptsIsActiveTargetObjectFileFormat(BridgedASTContext cContext, BridgedStringRef cName); + SWIFT_NAME("BridgedASTContext.langOptsGetLanguageVersion(self:_:)") SwiftInt BridgedASTContext_langOptsGetLanguageVersion(BridgedASTContext cContext, SwiftInt* _Nullable * _Nonnull cComponents); diff --git a/include/swift/AST/PlatformConditionKinds.def b/include/swift/AST/PlatformConditionKinds.def index bc980fd13f98b..300a5c20a1ed5 100644 --- a/include/swift/AST/PlatformConditionKinds.def +++ b/include/swift/AST/PlatformConditionKinds.def @@ -49,5 +49,8 @@ PLATFORM_CONDITION_(PtrAuth, "ptrauth") /// The active arch target's max atomic bit width. PLATFORM_CONDITION_(HasAtomicBitWidth, "hasAtomicBitWidth") +/// The active target's file format (Mach-O, ELF, COFF, WASM) +PLATFORM_CONDITION_(ObjectFileFormat, "objectFileFormat") + #undef PLATFORM_CONDITION #undef PLATFORM_CONDITION_ diff --git a/lib/AST/Bridging/ASTContextBridging.cpp b/lib/AST/Bridging/ASTContextBridging.cpp index 616497016015d..3e24d9b25b6ed 100644 --- a/lib/AST/Bridging/ASTContextBridging.cpp +++ b/lib/AST/Bridging/ASTContextBridging.cpp @@ -14,6 +14,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/AvailabilitySpec.h" +#include "llvm/Support/ErrorHandling.h" using namespace swift; @@ -109,6 +110,12 @@ BridgedASTContext_langOptsTargetEndianness(BridgedASTContext cContext) { : EndianBig; } +bool BridgedASTContext_langOptsIsActiveTargetObjectFileFormat( + BridgedASTContext cContext, BridgedStringRef cName) { + return cContext.unbridged().LangOpts.checkPlatformCondition( + PlatformConditionKind::ObjectFileFormat, cName.unbridged()); +} + /// Convert an array of numbers into a form we can use in Swift. namespace { template diff --git a/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift b/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift index 9f629af4b0346..beca03c7abef4 100644 --- a/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift +++ b/lib/ASTGen/Sources/ASTGen/CompilerBuildConfiguration.swift @@ -132,6 +132,13 @@ struct CompilerBuildConfiguration: BuildConfiguration { Int(ctx.langOptsTargetPointerBitWidth) } + func isActiveTargetObjectFileFormat(name: String) throws -> Bool { + var name = name + return name.withBridgedString { nameRef in + ctx.langOptsIsActiveTargetObjectFileFormat(nameRef) + } + } + var targetAtomicBitWidths: [Int] { var bitWidthsBuf: UnsafeMutablePointer? = nil let count = ctx.langOptsGetTargetAtomicBitWidths(&bitWidthsBuf) diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index a65755018c10e..a774b04f4199f 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -146,13 +146,20 @@ static const SupportedConditionalValue SupportedConditionalCompilationHasAtomicB "_128" }; +static const SupportedConditionalValue SupportedConditionalCompilationObjectFileFormats[] = { + "MachO", + "ELF", + "COFF", + "Wasm", +}; + static const PlatformConditionKind AllPublicPlatformConditionKinds[] = { #define PLATFORM_CONDITION(LABEL, IDENTIFIER) PlatformConditionKind::LABEL, #define PLATFORM_CONDITION_(LABEL, IDENTIFIER) #include "swift/AST/PlatformConditionKinds.def" }; -ArrayRef getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) { +static ArrayRef getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) { switch (Kind) { case PlatformConditionKind::OS: return SupportedConditionalCompilationOSs; @@ -172,12 +179,14 @@ ArrayRef getSupportedConditionalCompilationValues(con return SupportedConditionalCompilationPtrAuthSchemes; case PlatformConditionKind::HasAtomicBitWidth: return SupportedConditionalCompilationHasAtomicBitWidths; + case PlatformConditionKind::ObjectFileFormat: + return SupportedConditionalCompilationObjectFileFormats; } llvm_unreachable("Unhandled PlatformConditionKind in switch"); } -PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind, const StringRef &V, - std::vector &suggestedValues) { +static PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind, const StringRef &V, + std::vector &suggestedValues) { std::string lower = V.lower(); for (const PlatformConditionKind& candidateKind : AllPublicPlatformConditionKinds) { if (candidateKind != Kind) { @@ -196,8 +205,8 @@ PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind, return Kind; } -bool isMatching(PlatformConditionKind Kind, const StringRef &V, - PlatformConditionKind &suggestedKind, std::vector &suggestions) { +static bool isMatching(PlatformConditionKind Kind, const StringRef &V, + PlatformConditionKind &suggestedKind, std::vector &suggestions) { // Compare against known values, ignoring case to avoid penalizing // characters with incorrect case. unsigned minDistance = std::numeric_limits::max(); @@ -236,6 +245,7 @@ checkPlatformConditionSupported(PlatformConditionKind Kind, StringRef Value, case PlatformConditionKind::TargetEnvironment: case PlatformConditionKind::PtrAuth: case PlatformConditionKind::HasAtomicBitWidth: + case PlatformConditionKind::ObjectFileFormat: return isMatching(Kind, Value, suggestedKind, suggestedValues); case PlatformConditionKind::CanImport: // All importable names are valid. @@ -641,6 +651,17 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue(PlatformConditionKind::PointerBitWidth, "_64"); } + // Set the "_objectFileFormat" platform condition. + if (Target.isOSBinFormatMachO()) { + addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "MachO"); + } else if (Target.isOSBinFormatELF()) { + addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "ELF"); + } else if (Target.isOSBinFormatCOFF()) { + addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "COFF"); + } else if (Target.isOSBinFormatWasm()) { + addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "Wasm"); + } + // Set the "runtime" platform condition. addPlatformConditionValue(PlatformConditionKind::Runtime, EnableObjCInterop ? "_ObjC" : "_Native"); diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 4e05e078aee60..999599ef8fefe 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -385,7 +385,7 @@ class ValidateIfConfigCondition : return E; } - // ( 'os' | 'arch' | '_endian' | '_pointerBitWidth' | '_runtime' | '_hasAtomicBitWidth' ) '(' identifier ')'' + // ( 'os' | 'arch' | '_endian' | '_pointerBitWidth' | '_runtime' | '_hasAtomicBitWidth' | '_objectFileFormat' ) '(' identifier ')'' auto Kind = getPlatformConditionKind(*KindName); if (!Kind.has_value()) { D.diagnose(E->getLoc(), diag::unsupported_platform_condition_expression); @@ -429,6 +429,8 @@ class ValidateIfConfigCondition : DiagName = "pointer authentication scheme"; break; case PlatformConditionKind::HasAtomicBitWidth: DiagName = "has atomic bit width"; break; + case PlatformConditionKind::ObjectFileFormat: + DiagName = "object file format"; break; case PlatformConditionKind::Runtime: llvm_unreachable("handled above"); } diff --git a/test/Parse/ConditionalCompilation/object_file_format.swift b/test/Parse/ConditionalCompilation/object_file_format.swift new file mode 100644 index 0000000000000..1b8176a883c5a --- /dev/null +++ b/test/Parse/ConditionalCompilation/object_file_format.swift @@ -0,0 +1,11 @@ +// RUN: %swift -typecheck %s -verify -target arm64-apple-none-macho -parse-stdlib +// RUN: %swift -typecheck %s -verify -target arm64-apple-none-elf -parse-stdlib +// RUN: %swift -typecheck %s -verify -target wasm32-unknown-wasi -parse-stdlib +// RUN: %swift -typecheck %s -verify -target x86_64-unknown-windows-msvc -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target arm64-apple-macos + +#if _objectFileFormat(MachO) || _objectFileFormat(ELF) || _objectFileFormat(Wasm) || _objectFileFormat(COFF) +class C {} +var x = C() +#endif +var y = x From 65a496f9d2848100f69c3a9992c5d101d9a69fe9 Mon Sep 17 00:00:00 2001 From: Kuba Mracek Date: Mon, 24 Mar 2025 10:53:32 -0700 Subject: [PATCH 2/2] Emit an error for unsupported object file formats in the triple --- include/swift/AST/DiagnosticsFrontend.def | 3 +++ include/swift/Basic/LangOptions.h | 8 +++---- lib/Basic/LangOptions.cpp | 22 ++++++++++++++----- lib/Frontend/CompilerInvocation.cpp | 26 +++-------------------- unittests/Basic/CMakeLists.txt | 1 + 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 41736350078fa..6420206898b76 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -36,6 +36,9 @@ ERROR(error_unsupported_target_os, none, ERROR(error_unsupported_target_arch, none, "unsupported target architecture: '%0'", (StringRef)) +ERROR(error_unsupported_object_file_format, none, + "unsupported object file format: '%0'", (StringRef)) + WARNING(warning_upcoming_feature_on_by_default, none, "upcoming feature '%0' is already enabled as of Swift version %1", (StringRef, unsigned)) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 0ab9297ad68f6..cd9cde6cd0356 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -652,11 +652,9 @@ namespace swift { LangOptions(); /// Sets the target we are building for and updates platform conditions - /// to match. - /// - /// \returns A pair - the first element is true if the OS was invalid. - /// The second element is true if the Arch was invalid. - std::pair setTarget(llvm::Triple triple); + /// to match. Emits errors using `Diags` in case of an invalid OS, arch, + /// etc. + void setTarget(llvm::Triple triple, swift::DiagnosticEngine *Diags = nullptr); /// Returns the minimum platform version to which code will be deployed. /// diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index a774b04f4199f..f24b4cbbf9f2f 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -17,6 +17,7 @@ #include "swift/Basic/LangOptions.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Feature.h" #include "swift/Basic/FileTypes.h" @@ -489,7 +490,8 @@ static bool isMultiThreadedRuntime(llvm::Triple triple) { return true; } -std::pair LangOptions::setTarget(llvm::Triple triple) { +void LangOptions::setTarget(llvm::Triple triple, + swift::DiagnosticEngine *Diags) { clearAllPlatformConditionValues(); clearAtomicBitWidths(); @@ -574,6 +576,11 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { break; } + if (UnsupportedOS && Diags) { + Diags->diagnose(SourceLoc(), diag::error_unsupported_target_os, + Target.getOSName()); + } + bool UnsupportedArch = false; // Set the "arch" platform condition. @@ -632,8 +639,10 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { } } - if (UnsupportedOS || UnsupportedArch) - return { UnsupportedOS, UnsupportedArch }; + if (UnsupportedArch && Diags) { + Diags->diagnose(SourceLoc(), diag::error_unsupported_target_arch, + Target.getArchName()); + } // Set the "_endian" platform condition. if (Target.isLittleEndian()) { @@ -660,6 +669,11 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "COFF"); } else if (Target.isOSBinFormatWasm()) { addPlatformConditionValue(PlatformConditionKind::ObjectFileFormat, "Wasm"); + } else { + if (Diags) { + Diags->diagnose(SourceLoc(), diag::error_unsupported_object_file_format, + Target.getObjectFormatTypeName(Target.getObjectFormat())); + } } // Set the "runtime" platform condition. @@ -695,8 +709,6 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { // If you add anything to this list, change the default size of // PlatformConditionValues to not require an extra allocation // in the common case. - - return { false, false }; } llvm::StringRef swift::getPlaygroundOptionName(PlaygroundOption option) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b0eb075195a53..6afc1e748216c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -409,7 +409,7 @@ void CompilerInvocation::setTargetTriple(StringRef Triple) { } void CompilerInvocation::setTargetTriple(const llvm::Triple &Triple) { - LangOpts.setTarget(Triple); + LangOpts.setTarget(Triple, /*Diags*/nullptr); updateRuntimeLibraryPaths(SearchPathOpts, FrontendOpts, LangOpts); } @@ -1474,12 +1474,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.SkipNonExportableDecls = false; llvm::Triple Target = Opts.Target; - StringRef TargetArg; - std::string TargetArgScratch; - if (const Arg *A = Args.getLastArg(OPT_target)) { Target = llvm::Triple(A->getValue()); - TargetArg = A->getValue(); const bool targetNeedsRemapping = Target.isXROS(); if (targetNeedsRemapping && Target.getOSMajorVersion() == 0) { @@ -1506,8 +1502,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, if (tripleInfersSimulatorEnvironment(Target)) { // Set the simulator environment. Target.setEnvironment(llvm::Triple::EnvironmentType::Simulator); - TargetArgScratch = Target.str(); - TargetArg = TargetArgScratch; } } @@ -1562,21 +1556,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, // Must be processed after any other language options that could affect // platform conditions. - bool UnsupportedOS, UnsupportedArch; - std::tie(UnsupportedOS, UnsupportedArch) = Opts.setTarget(Target); - - SmallVector TargetComponents; - TargetArg.split(TargetComponents, "-"); - - if (UnsupportedArch) { - auto TargetArgArch = TargetComponents.size() ? TargetComponents[0] : ""; - Diags.diagnose(SourceLoc(), diag::error_unsupported_target_arch, TargetArgArch); - } - - if (UnsupportedOS) { - auto TargetArgOS = TargetComponents.size() > 2 ? TargetComponents[2] : ""; - Diags.diagnose(SourceLoc(), diag::error_unsupported_target_os, TargetArgOS); - } + Opts.setTarget(Target, &Diags); // First, set up default minimum inlining target versions. auto getDefaultMinimumInliningTargetVersion = @@ -1827,7 +1807,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.enableFeature(Feature::ParserValidation); } #endif - return HadError || UnsupportedOS || UnsupportedArch; + return HadError || Diags.hasFatalErrorOccurred(); } static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args, diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt index edad76cf3448d..770bf9b56a852 100644 --- a/unittests/Basic/CMakeLists.txt +++ b/unittests/Basic/CMakeLists.txt @@ -49,6 +49,7 @@ add_dependencies(SwiftBasicTests "${gyb_dependency_targets}") target_link_libraries(SwiftBasicTests PRIVATE swiftBasic + swiftFrontend swiftOption swiftThreading clangBasic