diff --git a/lib/FrontendTool/LoadedModuleTrace.cpp b/lib/FrontendTool/LoadedModuleTrace.cpp index 827c9578f4d..0c7600d516c 100644 --- a/lib/FrontendTool/LoadedModuleTrace.cpp +++ b/lib/FrontendTool/LoadedModuleTrace.cpp @@ -65,6 +65,8 @@ struct LoadedModuleTraceFormat { unsigned Version; Identifier Name; std::string Arch; + std::string LanguageMode; + std::vector EnabledLanguageFeatures; bool StrictMemorySafety; std::vector SwiftModules; std::vector SwiftMacros; @@ -107,6 +109,11 @@ template <> struct ObjectTraits { out.mapRequired("arch", contents.Arch); + out.mapRequired("languageMode", contents.LanguageMode); + + out.mapRequired("enabledLanguageFeatures", + contents.EnabledLanguageFeatures); + out.mapRequired("strictMemorySafety", contents.StrictMemorySafety); // The 'swiftmodules' key is kept for backwards compatibility. @@ -723,6 +730,38 @@ computeSwiftMacroTraceInfo(ASTContext &ctx, const DependencyTracker &depTracker, }); } +static void computeEnabledFeatures(ASTContext &ctx, + std::vector &enabledFeatures) { + struct FeatureAndName { + Feature feature; + StringRef name; + }; + + static const FeatureAndName features[] = { +#define FEATURE_ENTRY(FeatureName) {Feature::FeatureName, #FeatureName}, +#define LANGUAGE_FEATURE(FeatureName, SENumber, Version) +#define EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \ + FEATURE_ENTRY(FeatureName) +#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \ + FEATURE_ENTRY(FeatureName) +#define OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Version) \ + FEATURE_ENTRY(FeatureName) +#include "swift/Basic/Features.def" + }; + + for (auto &featureAndName : features) { + if (ctx.LangOpts.hasFeature(featureAndName.feature)) + enabledFeatures.push_back(featureAndName.name); + } + + // FIXME: It would be nice if the features were added in sorted order instead. + // However, std::sort is not constexpr until C++20. + std::sort(enabledFeatures.begin(), enabledFeatures.end(), + [](const StringRef &lhs, const StringRef &rhs) -> bool { + return lhs.compare(rhs) < 0; + }); +} + // [NOTE: Bailing-vs-crashing-in-trace-emission] There are certain edge cases // in trace emission where an invariant that you think should hold does not hold // in practice. For example, sometimes we have seen modules without any @@ -785,12 +824,18 @@ bool swift::emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule, std::vector swiftMacros; computeSwiftMacroTraceInfo(ctxt, *depTracker, swiftMacros); + std::vector enabledFeatures; + computeEnabledFeatures(ctxt, enabledFeatures); + LoadedModuleTraceFormat trace = { /*version=*/LoadedModuleTraceFormat::CurrentVersion, /*name=*/mainModule->getName(), /*arch=*/ctxt.LangOpts.Target.getArchName().str(), + ctxt.LangOpts.EffectiveLanguageVersion.asAPINotesVersionString(), + enabledFeatures, mainModule ? mainModule->strictMemorySafety() : false, - swiftModules, swiftMacros}; + swiftModules, + swiftMacros}; // raw_fd_ostream is unbuffered, and we may have multiple processes writing, // so first write to memory and then dump the buffer to the trace file. diff --git a/test/Driver/loaded_module_trace.swift b/test/Driver/loaded_module_trace.swift index d38d90a09c8..b3fd4fd5f2b 100644 --- a/test/Driver/loaded_module_trace.swift +++ b/test/Driver/loaded_module_trace.swift @@ -12,6 +12,7 @@ // CHECK: "version":2 // CHECK: "name":"loaded_module_trace" // CHECK: "arch":"{{[^"]*}}" +// CHECK: "languageMode":"4" // CHECK: "strictMemorySafety":false // CHECK: "swiftmodules":[ // CHECK-DAG: "{{[^"]*\\[/\\]}}Module2.swiftmodule" diff --git a/test/Driver/loaded_module_trace_enabled_features.swift b/test/Driver/loaded_module_trace_enabled_features.swift new file mode 100644 index 00000000000..58554936564 --- /dev/null +++ b/test/Driver/loaded_module_trace_enabled_features.swift @@ -0,0 +1,83 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -swift-version 4 \ +// RUN: -emit-loaded-module-trace-path %t/swift4.trace.json +// RUN: %FileCheck -check-prefix=CHECK-SWIFT4 %s < %t/swift4.trace.json + +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -swift-version 5 \ +// RUN: -emit-loaded-module-trace-path %t/swift5.trace.json +// RUN: %FileCheck -check-prefix=CHECK-SWIFT5 %s < %t/swift5.trace.json + +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -swift-version 5 \ +// RUN: -emit-loaded-module-trace-path %t/swift5_and_features.trace.json \ +// RUN: -enable-experimental-feature ParserValidation \ +// RUN: -enable-upcoming-feature RegionBasedIsolation \ +// RUN: -strict-memory-safety +// RUN: %FileCheck -check-prefix=CHECK-SWIFT5-PLUS %s < %t/swift5_and_features.trace.json + +// RUN: %target-swift-frontend %s -emit-module -o /dev/null -swift-version 6 \ +// RUN: -emit-loaded-module-trace-path %t/swift6.trace.json +// RUN: %FileCheck -check-prefix=CHECK-SWIFT6 %s < %t/swift6.trace.json + +// NOTE: The matching of the enabledLanguageFeatures lists below is +// intentionally inexact. There are few experimental features (ParserRoundTrip, +// ParserValidation) that are enabled by default in asserts compilers but +// otherwise disabled, so the enabled feature lists will sometimes contain +// additional entries. + +// REQUIRES: swift_feature_ParserValidation +// REQUIRES: swift_feature_RegionBasedIsolation + +// CHECK-SWIFT4: { +// CHECK-SWIFT4: "version":2 +// CHECK-SWIFT4: "arch":"{{[^"]*}}" +// CHECK-SWIFT4: "languageMode":"4" +// CHECK-SWIFT4: "enabledLanguageFeatures":[ +// CHECK-SWIFT4: ] +// CHECK-SWIFT4: "strictMemorySafety":false + +// CHECK-SWIFT5: { +// CHECK-SWIFT5: "version":2 +// CHECK-SWIFT5: "arch":"{{[^"]*}}" +// CHECK-SWIFT5: "languageMode":"5" +// CHECK-SWIFT5: "enabledLanguageFeatures":[ +// CHECK-SWIFT5: "NonfrozenEnumExhaustivity" +// CHECK-SWIFT5: ] +// CHECK-SWIFT5: "strictMemorySafety":false + +// CHECK-SWIFT5-PLUS: { +// CHECK-SWIFT5-PLUS: "version":2 +// CHECK-SWIFT5-PLUS: "arch":"{{[^"]*}}" +// CHECK-SWIFT5-PLUS: "languageMode":"5" +// CHECK-SWIFT5-PLUS: "enabledLanguageFeatures":[ +// CHECK-SWIFT5-PLUS: "NonfrozenEnumExhaustivity", +// CHECK-SWIFT5-PLUS: "ParserValidation", +// CHECK-SWIFT5-PLUS: "RegionBasedIsolation", +// CHECK-SWIFT5-PLUS: "StrictMemorySafety" +// CHECK-SWIFT5-PLUS: ] +// CHECK-SWIFT5-PLUS: "strictMemorySafety":true + +// CHECK-SWIFT6: { +// CHECK-SWIFT6: "version":2 +// CHECK-SWIFT6: "arch":"{{[^"]*}}" +// CHECK-SWIFT6: "languageMode":"6" +// CHECK-SWIFT6: "enabledLanguageFeatures":[ +// CHECK-SWIFT6: "BareSlashRegexLiterals", +// CHECK-SWIFT6: "ConciseMagicFile", +// CHECK-SWIFT6: "DeprecateApplicationMain", +// CHECK-SWIFT6: "DisableOutwardActorInference", +// CHECK-SWIFT6: "DynamicActorIsolation", +// CHECK-SWIFT6: "ForwardTrailingClosures", +// CHECK-SWIFT6: "GlobalActorIsolatedTypesUsability", +// CHECK-SWIFT6: "GlobalConcurrency", +// CHECK-SWIFT6: "ImplicitOpenExistentials", +// CHECK-SWIFT6: "ImportObjcForwardDeclarations", +// CHECK-SWIFT6: "InferSendableFromCaptures", +// CHECK-SWIFT6: "IsolatedDefaultValues", +// CHECK-SWIFT6: "NonfrozenEnumExhaustivity", +// CHECK-SWIFT6: "RegionBasedIsolation", +// CHECK-SWIFT6: "StrictConcurrency" +// CHECK-SWIFT6: ] +// CHECK-SWIFT6: "strictMemorySafety":false + +import Swift diff --git a/test/Driver/loaded_module_trace_multifile.swift b/test/Driver/loaded_module_trace_multifile.swift index 9c5fb94e563..36f947ff8f7 100644 --- a/test/Driver/loaded_module_trace_multifile.swift +++ b/test/Driver/loaded_module_trace_multifile.swift @@ -14,6 +14,9 @@ // CHECK: "version":2 // CHECK: "name":"loaded_module_trace_multifile" // CHECK: "arch":"{{[^"]*}}" +// CHECK: "languageMode":"4" +// CHECK: "enabledLanguageFeatures":[ +// CHECK: ] // CHECK: "swiftmodules":[ // CHECK-DAG: "{{[^"]*\\[/\\]}}Module2.swiftmodule" // CHECK-DAG: "{{[^"]*\\[/\\]}}Swift.swiftmodule{{(\\[/\\][^"]+[.]swiftmodule)?}}"