From c3c1e6df8df638632a054bf9df2f30751f2db759 Mon Sep 17 00:00:00 2001 From: LucianoAlmeida Date: Sun, 12 Sep 2021 21:56:54 -0300 Subject: [PATCH 01/24] [Benchmarks][stdlib] Adding an extra benchmark for set isDisjoint for disjoint sets of different size --- benchmark/single-source/SetTests.swift | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/benchmark/single-source/SetTests.swift b/benchmark/single-source/SetTests.swift index e3aff23ac9cd4..b23cd3ddcc2ec 100644 --- a/benchmark/single-source/SetTests.swift +++ b/benchmark/single-source/SetTests.swift @@ -25,11 +25,13 @@ let setAB = Set(0 ..< size) // 0 ..< 400 let setCD = Set(size ..< 2 * size) // 400 ..< 800 let setBC = Set(size - quarter ..< 2 * size - quarter) // 300 ..< 700 let setB = Set(size - quarter ..< size) // 300 ..< 400 +let setCDS = Set(size ..< (size + (size/4))) // 400 ..< 500 let setOAB = Set(setAB.map(Box.init)) let setOCD = Set(setCD.map(Box.init)) let setOBC = Set(setBC.map(Box.init)) let setOB = Set(setB.map(Box.init)) +let setOCDS = Set(setCDS.map(Box.init)) let countA = size - quarter // 300 let countB = quarter // 100 @@ -368,6 +370,16 @@ public let SetTests = [ runFunction: { n in run_SetIsDisjointBox(setOAB, setOCD, true, 50 * n) }, tags: [.validation, .api, .Set], setUpFunction: { blackHole([setOAB, setOCD]) }), + BenchmarkInfo( + name: "Set.isDisjoint.Smaller.Int0", + runFunction: { n in run_SetIsDisjointIntCommutative(setAB, setCDS, true, 50 * n) }, + tags: [.validation, .api, .Set], + setUpFunction: { blackHole([setAB, setCDS]) }), + BenchmarkInfo( + name: "Set.isDisjoint.Smaller.Box0", + runFunction: { n in run_SetIsDisjointBoxCommutative(setOAB, setOCDS, true, 50 * n) }, + tags: [.validation, .api, .Set], + setUpFunction: { blackHole([setOAB, setOCDS]) }), BenchmarkInfo( name: "Set.isDisjoint.Int25", runFunction: { n in run_SetIsDisjointInt(setB, setAB, false, 5000 * n) }, @@ -891,6 +903,22 @@ public func run_SetIsDisjointInt( } } +// Run isDisjoint Int switching the order of the two sets. +@inline(never) +public func run_SetIsDisjointIntCommutative( + _ a: Set, + _ b: Set, + _ r: Bool, + _ n: Int) { + for _ in 0 ..< n { + let isDisjointA = a.isDisjoint(with: identity(b)) + CheckResults(isDisjointA == r) + + let isDisjointB = b.isDisjoint(with: identity(a)) + CheckResults(isDisjointB == r) + } +} + @inline(never) public func run_SetIsDisjointSeqInt( _ a: Set, @@ -1091,6 +1119,22 @@ func run_SetIsDisjointBox( } } +// Run isDisjoint Box switching the order of the two sets. +@inline(never) +func run_SetIsDisjointBoxCommutative( + _ a: Set>, + _ b: Set>, + _ r: Bool, + _ n: Int) { + for _ in 0 ..< n { + let isDisjointA = a.isDisjoint(with: identity(b)) + CheckResults(isDisjointA == r) + + let isDisjointB = b.isDisjoint(with: identity(a)) + CheckResults(isDisjointB == r) + } +} + @inline(never) func run_SetIsDisjointSeqBox( _ a: Set>, From d002471784f911eef5dfcb9a1af36fe67e164bfa Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 10 Sep 2021 17:36:32 -0700 Subject: [PATCH 02/24] Added -enable-experimental-defined-lifetimes. The new flag will guard work on the experimental implementation of tracking lexical lifetimes in SIL. --- include/swift/Basic/LangOptions.h | 3 +++ include/swift/Option/FrontendOptions.td | 4 ++++ lib/Frontend/CompilerInvocation.cpp | 3 +++ 3 files changed, 10 insertions(+) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 8514f29952d36..4f45cb6137918 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -298,6 +298,9 @@ namespace swift { /// Enable experimental concurrency model. bool EnableExperimentalConcurrency = false; + /// Enable experimental support for emitting defined borrow scopes. + bool EnableExperimentalDefinedLifetimes = false; + /// Enable experimental support for named opaque result types, e.g. /// `func f() -> T`. bool EnableExperimentalNamedOpaqueTypes = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 7df8f37246a62..f1c0b21df5e20 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -243,6 +243,10 @@ def enable_experimental_concurrency : Flag<["-"], "enable-experimental-concurrency">, HelpText<"Enable experimental concurrency model">; +def enable_experimental_defined_lifetimes : + Flag<["-"], "enable-experimental-defined-lifetimes">, + HelpText<"Enable experimental defined lifetimes">; + def enable_experimental_distributed : Flag<["-"], "enable-experimental-distributed">, HelpText<"Enable experimental 'distributed' actors and functions">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 5140c051c961f..711738401acd1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -422,6 +422,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableExperimentalConcurrency |= Args.hasArg(OPT_enable_experimental_concurrency); + Opts.EnableExperimentalDefinedLifetimes |= + Args.hasArg(OPT_enable_experimental_defined_lifetimes); + Opts.EnableExperimentalNamedOpaqueTypes |= Args.hasArg(OPT_enable_experimental_named_opaque_types); From a0c47cb32eb1d5d5c40900f2456b3e95e17b5e52 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 13 Sep 2021 11:04:17 -0700 Subject: [PATCH 03/24] [SILGen] Emitted [defined] borrow scopes for lets. When -enable-experimental-defined-lifetimes is passed, SILGen emits lexical scopes for lets. --- lib/SILGen/SILGenDecl.cpp | 25 +++++++++++++--- test/SILGen/borrow.swift | 60 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index da61f262aea2c..4f1c060d56316 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -262,6 +262,10 @@ class DestroyLocalVariable : public Cleanup { void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { + SILValue val = SGF.VarLocs[Var].value; + if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes && + val->getOwnershipKind() != OwnershipKind::None) + SGF.B.createEndBorrow(l, val); SGF.destroyLocalVariable(l, Var); } @@ -528,13 +532,18 @@ class LetValueInitialization : public Initialization { // an argument, for example. if (value->getType().isAddress()) address = value; + SILLocation PrologueLoc(vd); + + if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes && + value->getOwnershipKind() != OwnershipKind::None) + value = SILValue( + SGF.B.createBeginBorrow(PrologueLoc, value, /*defined*/ true)); SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(value); // Emit a debug_value[_addr] instruction to record the start of this value's // lifetime, if permitted to do so. if (!EmitDebugValueOnInit) return; - SILLocation PrologueLoc(vd); PrologueLoc.markAsPrologue(); SILDebugVariable DbgVar(vd->isLet(), /*ArgNo=*/0); SGF.B.emitDebugDescription(PrologueLoc, value, DbgVar); @@ -1714,8 +1723,16 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) { // For 'let' bindings, we emit a release_value or destroy_addr, depending on // whether we have an address or not. SILValue Val = loc.value; - if (!Val->getType().isAddress()) - B.emitDestroyValueOperation(silLoc, Val); - else + if (!Val->getType().isAddress()) { + SILValue valueToBeDestroyed; + if (getASTContext().LangOpts.EnableExperimentalDefinedLifetimes && + Val->getOwnershipKind() != OwnershipKind::None) { + auto *inst = cast(Val.getDefiningInstruction()); + valueToBeDestroyed = inst->getOperand(); + } else { + valueToBeDestroyed = Val; + } + B.emitDestroyValueOperation(silLoc, valueToBeDestroyed); + } else B.createDestroyAddr(silLoc, Val); } diff --git a/test/SILGen/borrow.swift b/test/SILGen/borrow.swift index 6616d8d3fc4d9..a858ecd8176fe 100644 --- a/test/SILGen/borrow.swift +++ b/test/SILGen/borrow.swift @@ -1,5 +1,5 @@ -// RUN: %target-swift-emit-silgen -module-name borrow -parse-stdlib %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -enable-experimental-defined-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s import Swift @@ -8,9 +8,12 @@ final class D {} // Make sure that we insert the borrow for a ref_element_addr lvalue in the // proper place. final class C { + init() {} + init?(failably: ()) {} var d: D = D() } +func use(_ t: T) {} func useD(_ d: D) {} // CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () { @@ -33,3 +36,58 @@ func lvalueBorrowShouldBeAtEndOfFormalAccessScope() { var c = C() useD(c.d) } + +// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class +// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC +// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}}) +// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $C +// CHECK: end_borrow [[BORROW:%[^,]+]] +// CHECK-LABEL: } // end sil function 'defined_borrow_let_class' +@_silgen_name("defined_borrow_let_class") +func defined_borrow_let_class() { + let c = C() +} + +// CHECK-LABEL: sil hidden [ossa] @defined_borrow_if_let_class +// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC +// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}}) +// CHECK: switch_enum [[INSTANCE]] : $Optional, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}} +// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C): +// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $C +// CHECK: end_borrow [[BORROW]] : $C +// CHECK-LABEL: // end sil function 'defined_borrow_if_let_class' +@_silgen_name("defined_borrow_if_let_class") +func defined_borrow_if_let_class() { + if let c = C(failably: ()) { + use(()) + } +} + +struct S { + let c: C +} + +// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class_in_struct +// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC +// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}}) +// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $S +// CHECK: end_borrow [[BORROW:%[^,]+]] +// CHECK-LABEL: } // end sil function 'defined_borrow_let_class_in_struct' +@_silgen_name("defined_borrow_let_class_in_struct") +func defined_borrow_let_class_in_struct() { + let s = S(c: C()) +} + +enum E { + case e(C) +} + +// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class_in_enum +// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C +// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $E +// CHECK: end_borrow [[BORROW:%[^,]+]] +// CHECK-LABEL: } // end sil function 'defined_borrow_let_class_in_enum' +@_silgen_name("defined_borrow_let_class_in_enum") +func defined_borrow_let_class_in_enum() { + let s = E.e(C()) +} From 9ea48da9cc755e61c134efbc0502a64cbe613a98 Mon Sep 17 00:00:00 2001 From: Thomas <48776071+TotallyNotThomas@users.noreply.github.com> Date: Mon, 13 Sep 2021 20:45:24 +0100 Subject: [PATCH 04/24] Shouldn't this be labeled as a C++ file? --- stdlib/public/runtime/SwiftDtoa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/runtime/SwiftDtoa.cpp b/stdlib/public/runtime/SwiftDtoa.cpp index a1720157ee404..d1f3c1cb090e3 100644 --- a/stdlib/public/runtime/SwiftDtoa.cpp +++ b/stdlib/public/runtime/SwiftDtoa.cpp @@ -1,4 +1,4 @@ -//===--- SwiftDtoa.c ---------------------------------------------*- c -*-===// +//===--- SwiftDtoa.cpp ---------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // From ddf210b44919a3db9d38ced30f8eed6a80c82142 Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Mon, 13 Sep 2021 09:52:17 -0700 Subject: [PATCH 05/24] Disabling arm64e testing in two tests I wasn't aware that arm64e was a thing in open-source, but these two tests are failing on Apple Silicon both on the main branch and on the rebranch branch, so I'm disabling it for now. The failing tests are: - ModuleInterface/arm64e-fallback.swift - stdlib/Reflection_objc.swift --- test/ModuleInterface/arm64e-fallback.swift | 4 +++- test/stdlib/Reflection_objc.swift | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/test/ModuleInterface/arm64e-fallback.swift b/test/ModuleInterface/arm64e-fallback.swift index b7e448e2128c4..04bd82ef43175 100644 --- a/test/ModuleInterface/arm64e-fallback.swift +++ b/test/ModuleInterface/arm64e-fallback.swift @@ -11,7 +11,9 @@ // When run on arm64e, this tests that we build the same interface with // `#if _ptrauth(_arm64e)` on. // -// REQUIRES: CPU=arm64 || CPU=arm64e +// REQUIRES: CPU=arm64 +// Disabled arm64e for now since it isn't passing tests on apple silicon. +// XFAIL: CPU=arm64e import PtrAuthFramework // expected-remark{{rebuilding module 'PtrAuthFramework' from interface}} diff --git a/test/stdlib/Reflection_objc.swift b/test/stdlib/Reflection_objc.swift index 2e8d2fe437580..4733531e94283 100644 --- a/test/stdlib/Reflection_objc.swift +++ b/test/stdlib/Reflection_objc.swift @@ -12,6 +12,9 @@ // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime +// Disabled arm64e for now since it is failing +// XFAIL: CPU=arm64e + // // DO NOT add more tests to this file. Add them to test/1_stdlib/Runtime.swift. // From 3053e6de67a55bfb9294c2d60d38682e732e6be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20B=C3=BCgling?= Date: Mon, 13 Sep 2021 15:49:04 -0700 Subject: [PATCH 06/24] Fix TOC entry for Linux in GettingStarted The TOC was referencing a no longer existing "Ubuntu Linux" section. --- docs/HowToGuides/GettingStarted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/HowToGuides/GettingStarted.md b/docs/HowToGuides/GettingStarted.md index fa1a2137d3a92..1bbed24c00db4 100644 --- a/docs/HowToGuides/GettingStarted.md +++ b/docs/HowToGuides/GettingStarted.md @@ -16,7 +16,7 @@ toolchain as a one-off, there are a couple of differences: - [Troubleshooting cloning issues](#troubleshooting-cloning-issues) - [Installing dependencies](#installing-dependencies) - [macOS](#macOS) - - [Ubuntu Linux](#ubuntu-linux) + - [Linux](#linux) - [Building the project for the first time](#building-the-project-for-the-first-time) - [Spot check dependencies](#spot-check-dependencies) - [The roles of different tools](#the-roles-of-different-tools) From c38d1773d23fccb6fb3bc5d885d7aee2380cf4eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferri=C3=A8re?= Date: Tue, 1 Jun 2021 16:57:40 -0700 Subject: [PATCH 07/24] [Serialization] Restrict loading swiftmodule files to the builder's SDK Serialize the canonical name of the SDK used when building a swiftmodule file and use it to ensure that the swiftmodule file is loaded only with the same SDK. The SDK name must be passed down from the frontend. This will report unsupported configurations like: - Installing roots between incompatible SDKs without deleting the swiftmodule files. - Having multiple targets in the same project using different SDKs. - Loading a swiftmodule created with a newer SDK (and stdlib) with an older SDK. All of these lead to hard to investigate deserialization failures and this change should detect them early, before reaching a deserialization failure. rdar://78048939 --- include/swift/AST/DiagnosticsSema.def | 3 +++ include/swift/AST/SearchPathOptions.h | 4 ++++ include/swift/Basic/LangOptions.h | 3 +++ include/swift/Option/FrontendOptions.td | 3 +++ .../Serialization/SerializationOptions.h | 1 + include/swift/Serialization/Validation.h | 7 ++++++- lib/Frontend/CompilerInvocation.cpp | 5 +++++ lib/Frontend/Frontend.cpp | 1 + lib/Frontend/ModuleInterfaceBuilder.cpp | 2 ++ lib/Serialization/ModuleFile.cpp | 9 +++++++++ lib/Serialization/ModuleFileSharedCore.cpp | 5 +++++ lib/Serialization/ModuleFileSharedCore.h | 3 +++ lib/Serialization/ModuleFormat.h | 10 ++++++++-- lib/Serialization/Serialization.cpp | 5 +++++ lib/Serialization/SerializedModuleLoader.cpp | 7 +++++++ .../restrict-swiftmodule-to-sdk.swift | 20 +++++++++++++++++++ 16 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 test/Serialization/restrict-swiftmodule-to-sdk.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 5227dfa4e7c46..b3b32591277a5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -782,6 +782,9 @@ ERROR(serialization_name_mismatch_repl,none, ERROR(serialization_target_incompatible,Fatal, "module %0 was created for incompatible target %1: %2", (Identifier, StringRef, StringRef)) +ERROR(serialization_sdk_mismatch,Fatal, + "cannot load module %0 built with SDK '%1' when using SDK '%2': %3", + (Identifier, StringRef, StringRef, StringRef)) ERROR(serialization_target_incompatible_repl,none, "module %0 was created for incompatible target %1: %2", (Identifier, StringRef, StringRef)) diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index f873e82ada368..02f61eadfe59a 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -82,6 +82,10 @@ class SearchPathOptions { /// would for a non-system header. bool DisableModulesValidateSystemDependencies = false; + /// Enforce loading only serialized modules built with the same SDK + /// as the context loading it. + bool EnableSameSDKCheck = true; + /// A set of compiled modules that may be ready to use. std::vector CandidateCompiledModules; diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index f8d161d346e51..6d14419be809c 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -127,6 +127,9 @@ namespace swift { /// The target variant SDK version, if known. Optional VariantSDKVersion; + /// The SDK canonical name, if known. + std::string SDKName; + /// The alternate name to use for the entry point instead of main. std::string entryPointFunctionName = "main"; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 0097ea215f0ff..7ea2ec76be348 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -823,6 +823,9 @@ def target_sdk_version : Separate<["-"], "target-sdk-version">, def target_variant_sdk_version : Separate<["-"], "target-variant-sdk-version">, HelpText<"The version of target variant SDK used for compilation">; +def target_sdk_name : Separate<["-"], "target-sdk-name">, + HelpText<"Canonical name of the target SDK used for compilation">; + def extra_clang_options_only : Flag<["-"], "only-use-extra-clang-opts">, HelpText<"Options passed via -Xcc are sufficient for Clang configuration">; diff --git a/include/swift/Serialization/SerializationOptions.h b/include/swift/Serialization/SerializationOptions.h index 2b180591a19d7..8f19f7d9ed22d 100644 --- a/include/swift/Serialization/SerializationOptions.h +++ b/include/swift/Serialization/SerializationOptions.h @@ -35,6 +35,7 @@ namespace swift { bool SkipSymbolGraphInheritedDocs = true; bool IncludeSPISymbolsInSymbolGraph = false; llvm::VersionTuple UserModuleVersion; + std::string SDKName; StringRef GroupInfoPath; StringRef ImportedHeader; diff --git a/include/swift/Serialization/Validation.h b/include/swift/Serialization/Validation.h index e5564a139473d..a2ffe970ed987 100644 --- a/include/swift/Serialization/Validation.h +++ b/include/swift/Serialization/Validation.h @@ -66,7 +66,11 @@ enum class Status { TargetIncompatible, /// The module file was built for a target newer than the current target. - TargetTooNew + TargetTooNew, + + /// The module file was built with a different SDK than the one in use + /// to build the client. + SDKMismatch }; /// Returns true if the data looks like it contains a serialized AST. @@ -80,6 +84,7 @@ struct ValidationInfo { StringRef miscVersion = {}; version::Version compatibilityVersion = {}; llvm::VersionTuple userModuleVersion; + StringRef sdkName = {}; size_t bytes = 0; Status status = Status::Malformed; }; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a854fc85e2dec..4c740f3cb4a00 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -774,6 +774,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, } } + // Get the SDK name. + if (Arg *A = Args.getLastArg(options::OPT_target_sdk_name)) { + Opts.SDKName = A->getValue(); + } + if (const Arg *A = Args.getLastArg(OPT_entry_point_function_name)) { Opts.entryPointFunctionName = A->getValue(); } diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index de292051246f9..685974fb55471 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -150,6 +150,7 @@ SerializationOptions CompilerInvocation::computeSerializationOptions( serializationOpts.ExtraClangOptions = getClangImporterOptions().ExtraArgs; serializationOpts.PublicDependentLibraries = getIRGenOptions().PublicLinkLibraries; + serializationOpts.SDKName = getLangOptions().SDKName; if (opts.EmitSymbolGraph) { if (!opts.SymbolGraphOutputDir.empty()) { diff --git a/lib/Frontend/ModuleInterfaceBuilder.cpp b/lib/Frontend/ModuleInterfaceBuilder.cpp index 4c8a3e18579da..19a3240826c5b 100644 --- a/lib/Frontend/ModuleInterfaceBuilder.cpp +++ b/lib/Frontend/ModuleInterfaceBuilder.cpp @@ -257,6 +257,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal( if (!getRelativeDepPath(InPath, SDKPath)) SerializationOpts.ModuleInterface = InPath; + SerializationOpts.SDKName = SubInstance.getASTContext().LangOpts.SDKName; + SmallVector Deps; bool serializeHashes = FEOpts.SerializeModuleInterfaceDependencyHashes; if (collectDepsForSerialization(SubInstance, Deps, serializeHashes)) { diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index 1d2aeeb027679..38990f4b4e4c5 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -149,6 +149,15 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc, return error(status); } + auto clientSDK = ctx.LangOpts.SDKName; + StringRef moduleSDK = Core->SDKName; + if (ctx.SearchPathOpts.EnableSameSDKCheck && + !moduleSDK.empty() && !clientSDK.empty() && + moduleSDK != clientSDK) { + status = Status::SDKMismatch; + return error(status); + } + for (const auto &searchPath : Core->SearchPaths) ctx.addSearchPath(searchPath.Path, searchPath.IsFramework, searchPath.IsSystem); diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index 8fba7e2ed85b1..eeec9a2fef78b 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -299,6 +299,10 @@ validateControlBlock(llvm::BitstreamCursor &cursor, case control_block::TARGET: result.targetTriple = blobData; break; + case control_block::SDK_NAME: { + result.sdkName = blobData; + break; + } default: // Unknown metadata record, possibly for use by a future version of the // module format. @@ -1210,6 +1214,7 @@ ModuleFileSharedCore::ModuleFileSharedCore( } Name = info.name; TargetTriple = info.targetTriple; + SDKName = info.sdkName; CompatibilityVersion = info.compatibilityVersion; UserModuleVersion = info.userModuleVersion; Bits.ArePrivateImportsEnabled = extInfo.arePrivateImportsEnabled(); diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index e192013c596fc..7f8fde8b28461 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -58,6 +58,9 @@ class ModuleFileSharedCore { /// The target the module was built for. StringRef TargetTriple; + /// The canonical name of the SDK the module was built with. + StringRef SDKName; + /// The name of the module interface this module was compiled from. /// /// Empty if this module didn't come from an interface file. diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 599ef3e5c0570..18e9530e8612e 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 628; // unaligned pointer +const uint16_t SWIFTMODULE_VERSION_MINOR = 629; // BuilderSDK /// A standard hash seed used for all string hashes in a serialized module. /// @@ -754,7 +754,8 @@ namespace control_block { enum { METADATA = 1, MODULE_NAME, - TARGET + TARGET, + SDK_NAME }; using MetadataLayout = BCRecordLayout< @@ -779,6 +780,11 @@ namespace control_block { TARGET, BCBlob // LLVM triple >; + + using SDKNameLayout = BCRecordLayout< + SDK_NAME, + BCBlob + >; } /// The record types within the options block (a sub-block of the control diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 92ce769c8851b..0720a001b724f 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -802,6 +802,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(control_block, METADATA); BLOCK_RECORD(control_block, MODULE_NAME); BLOCK_RECORD(control_block, TARGET); + BLOCK_RECORD(control_block, SDK_NAME); BLOCK(OPTIONS_BLOCK); BLOCK_RECORD(options_block, SDK_PATH); @@ -952,6 +953,7 @@ void Serializer::writeHeader(const SerializationOptions &options) { control_block::ModuleNameLayout ModuleName(Out); control_block::MetadataLayout Metadata(Out); control_block::TargetLayout Target(Out); + control_block::SDKNameLayout SDKName(Out); ModuleName.emit(ScratchRecord, M->getName().str()); @@ -985,6 +987,9 @@ void Serializer::writeHeader(const SerializationOptions &options) { userModuleSubminor, userModuleBuild, versionString.str()); + if (!options.SDKName.empty()) + SDKName.emit(ScratchRecord, options.SDKName); + Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str()); { diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 57c3443143717..5d5dac786cd21 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -976,6 +976,13 @@ void swift::serialization::diagnoseSerializedASTLoadFailure( moduleOSInfo.second, moduleBufferID); break; } + + case serialization::Status::SDKMismatch: + auto currentSDK = Ctx.LangOpts.SDKName; + auto moduleSDK = loadInfo.sdkName; + Ctx.Diags.diagnose(diagLoc, diag::serialization_sdk_mismatch, + ModuleName, moduleSDK, currentSDK, moduleBufferID); + break; } } diff --git a/test/Serialization/restrict-swiftmodule-to-sdk.swift b/test/Serialization/restrict-swiftmodule-to-sdk.swift new file mode 100644 index 0000000000000..5c678fe70a3a8 --- /dev/null +++ b/test/Serialization/restrict-swiftmodule-to-sdk.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t/cache) +// RUN: %empty-directory(%t/build) +// RUN: %{python} %utils/split_file.py -o %t %s + +/// Build Lib against SDK A. +// RUN: %target-swift-frontend -emit-module %t/Lib.swift -swift-version 5 -target-sdk-name A -o %t/build -parse-stdlib -module-cache-path %t/cache + +/// Building Client against SDK A should work fine as expected. +// RUN: %target-swift-frontend -typecheck %t/Client.swift -swift-version 5 -target-sdk-name A -I %t/build -parse-stdlib -module-cache-path %t/cache + +/// Build Client against SDK B, this should fail at loading Lib against a different SDK than A. +// RUN: not %target-swift-frontend -typecheck %t/Client.swift -swift-version 5 -target-sdk-name B -I %t/build -parse-stdlib -module-cache-path %t/cache 2>&1 | %FileCheck %s +// CHECK: cannot load module 'Lib' built with SDK 'A' when using SDK 'B': {{.*}}Lib.swiftmodule + +// BEGIN Lib.swift +public func foo() {} + +// BEGIN Client.swift +import Lib +foo() From bccea96fccfa1fc132aa8730a3ca0b0015fa98dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Thu, 3 Jun 2021 08:56:49 -0700 Subject: [PATCH 08/24] [Test] Use -parse-stdlib to avoid loading an incompatible stdlib Tests using a mock SDK can't load the stdlib of the normal SDK (or the just-built one) with the recent changes. Use `-parse-stdlib` in those tests to prevent loading the stdlib implicitly. --- test/DebugInfo/compileunit-sysroot-sdk.swift | 2 +- .../SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface | 3 +-- .../SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface | 3 +-- .../SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface | 3 +-- .../SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface | 3 +-- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/test/DebugInfo/compileunit-sysroot-sdk.swift b/test/DebugInfo/compileunit-sysroot-sdk.swift index 0000a5f50e58d..283616f480b5b 100644 --- a/test/DebugInfo/compileunit-sysroot-sdk.swift +++ b/test/DebugInfo/compileunit-sysroot-sdk.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend %s -emit-ir -g -o - \ +// RUN: %target-swift-frontend %s -emit-ir -g -o - -parse-stdlib \ // RUN: -sdk /SWIFT_SYSROOT/MacOSX.sdk | %FileCheck %s // Test that sysroot and SDK are stored in the debug info. // CHECK: distinct !DICompileUnit({{.*}}sysroot: "/SWIFT_SYSROOT/MacOSX.sdk", diff --git a/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface b/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface index 04fba0eeed4da..851f24ce52b03 100644 --- a/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface +++ b/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface @@ -1,7 +1,6 @@ // swift-interface-format-version: 1.0 // swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14) -// swift-module-flags: -target arm64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -import Swift +// swift-module-flags: -target arm64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -parse-stdlib public class RemovedClass { @objc deinit } diff --git a/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface b/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface index 5dd2912092b75..616271689153f 100644 --- a/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface +++ b/test/api-digester/Inputs/mock-sdk-baseline.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface @@ -1,7 +1,6 @@ // swift-interface-format-version: 1.0 // swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14) -// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -import Swift +// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -parse-stdlib public class RemovedClass { @objc deinit } diff --git a/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface b/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface index 606b8bd222422..f20e4f4217a6c 100644 --- a/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface +++ b/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/arm64-apple-macos.swiftinterface @@ -1,7 +1,6 @@ // swift-interface-format-version: 1.0 // swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14) -// swift-module-flags: -target arm64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -import Swift +// swift-module-flags: -target arm64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -parse-stdlib public class AddedClass { @objc deinit } diff --git a/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface b/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface index 3bc9676211a66..5315e1537ee54 100644 --- a/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface +++ b/test/api-digester/Inputs/mock-sdk.sdk/System/Library/Frameworks/SwiftFoo.framework/Modules/SwiftFoo.swiftmodule/x86_64-apple-macos.swiftinterface @@ -1,7 +1,6 @@ // swift-interface-format-version: 1.0 // swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14) -// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -import Swift +// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo -parse-stdlib public class AddedClass { @objc deinit } From 51cec860852c8cf5b009fc8ba9865234bcc1ffa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20Laferrie=CC=80re?= Date: Thu, 3 Jun 2021 09:43:46 -0700 Subject: [PATCH 09/24] [APIDigester] Don't check whether the stdlib was built for a different SDK The API digester forces loading the stdlib which may pick up an stdlib from a different SDK than the one being tested. Disable the check enforcing loading only swiftmodules built for the same SDK. --- lib/APIDigester/ModuleAnalyzerNodes.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/APIDigester/ModuleAnalyzerNodes.cpp b/lib/APIDigester/ModuleAnalyzerNodes.cpp index c9b9fa9837f14..cd59b02dbffe0 100644 --- a/lib/APIDigester/ModuleAnalyzerNodes.cpp +++ b/lib/APIDigester/ModuleAnalyzerNodes.cpp @@ -2233,6 +2233,9 @@ swift::ide::api::getSDKNodeRoot(SDKContext &SDKCtx, auto &Ctx = CI.getASTContext(); + // Don't check if the stdlib was build with the same SDK as what is loaded + // here as some tests rely on using a different stdlib. + Ctx.SearchPathOpts.EnableSameSDKCheck = false; // Load standard library so that Clang importer can use it. auto *Stdlib = Ctx.getStdlibModule(/*loadIfAbsent=*/true); From b57b222b54015d7d38601954ffd2084d2144621b Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 13 Sep 2021 17:00:31 -0700 Subject: [PATCH 10/24] [SIL] Added lexical flag to alloc_stack. The new flag will be used to track whether a borrow scope corresponds to a source-level lexical scope. Here, the flag is just documented, added to the instruction, represented in textual and serialized SIL, and cloned. --- docs/SIL.rst | 5 +- include/swift/SIL/SILBuilder.h | 7 +-- include/swift/SIL/SILCloner.h | 6 +-- include/swift/SIL/SILInstruction.h | 15 +++--- lib/SIL/IR/SILInstructions.cpp | 19 ++++---- lib/SIL/IR/SILPrinter.cpp | 2 + lib/SIL/Parser/ParseSIL.cpp | 68 +++++++++++++++++++--------- lib/Serialization/DeserializeSIL.cpp | 7 ++- lib/Serialization/SerializeSIL.cpp | 5 +- test/SIL/Parser/basic.sil | 21 +++++++++ test/SIL/Serialization/borrow.sil | 46 ++++++++++++++----- test/SIL/cloning.sil | 25 ++++++++++ 12 files changed, 166 insertions(+), 60 deletions(-) diff --git a/docs/SIL.rst b/docs/SIL.rst index 8dcdb312c6add..ae3360c569c84 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -3079,7 +3079,7 @@ alloc_stack ``````````` :: - sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? sil-type (',' debug-var-attr)* + sil-instruction ::= 'alloc_stack' '[dynamic_lifetime]'? '[lexical]'? sil-type (',' debug-var-attr)* %1 = alloc_stack $T // %1 has type $*T @@ -3102,6 +3102,9 @@ The ``dynamic_lifetime`` attribute specifies that the initialization and destruction of the stored value cannot be verified at compile time. This is the case, e.g. for conditionally initialized objects. +The optional ``lexical`` attribute specifies that the operand corresponds to a +local variable in the Swift source. + The memory is not retainable. To allocate a retainable box for a value type, use ``alloc_box``. diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index facf575b79b8e..b8a95db4f474f 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -365,13 +365,14 @@ class SILBuilder { AllocStackInst *createAllocStack(SILLocation Loc, SILType elementType, Optional Var = None, - bool hasDynamicLifetime = false) { + bool hasDynamicLifetime = false, + bool isLexical = false) { Loc.markAsPrologue(); assert((!dyn_cast_or_null(Loc.getAsASTNode()) || Var) && "location is a VarDecl, but SILDebugVariable is empty"); return insert(AllocStackInst::create(getSILDebugLocation(Loc), elementType, - getFunction(), - Var, hasDynamicLifetime)); + getFunction(), Var, hasDynamicLifetime, + isLexical)); } AllocRefInst *createAllocRef(SILLocation Loc, SILType ObjectType, diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index a05a5c5c6c074..3d8aa161249db 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -759,9 +759,9 @@ SILCloner::visitAllocStackInst(AllocStackInst *Inst) { Loc = MandatoryInlinedLocation::getAutoGeneratedLocation(); VarInfo = None; } - auto *NewInst = - getBuilder().createAllocStack(Loc, getOpType(Inst->getElementType()), - VarInfo, Inst->hasDynamicLifetime()); + auto *NewInst = getBuilder().createAllocStack( + Loc, getOpType(Inst->getElementType()), VarInfo, + Inst->hasDynamicLifetime(), Inst->isLexical()); remapDebugVarInfo(DebugVarCarryingInst(NewInst)); recordClonedInstruction(Inst, NewInst); } diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index a588bd4dc07a4..7dbae743ac032 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -1902,16 +1902,16 @@ class AllocStackInst final friend SILBuilder; bool dynamicLifetime = false; + bool lexical = false; AllocStackInst(SILDebugLocation Loc, SILType elementType, - ArrayRef TypeDependentOperands, - SILFunction &F, - Optional Var, bool hasDynamicLifetime); + ArrayRef TypeDependentOperands, SILFunction &F, + Optional Var, bool hasDynamicLifetime, + bool isLexical); static AllocStackInst *create(SILDebugLocation Loc, SILType elementType, - SILFunction &F, - Optional Var, - bool hasDynamicLifetime); + SILFunction &F, Optional Var, + bool hasDynamicLifetime, bool isLexical); SIL_DEBUG_VAR_SUPPLEMENT_TRAILING_OBJS_IMPL() @@ -1942,6 +1942,9 @@ class AllocStackInst final /// is conditionally initialized. bool hasDynamicLifetime() const { return dynamicLifetime; } + /// Whether the alloc_stack instruction corresponds to a source-level VarDecl. + bool isLexical() const { return lexical; } + /// Return the debug variable information attached to this instruction. Optional getVarInfo() const { Optional AuxVarType; diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 8d289b67b0c6d..dd099e2b50656 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -191,13 +191,13 @@ SILDebugVariable::createFromAllocation(const AllocationInst *AI) { AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType, ArrayRef TypeDependentOperands, SILFunction &F, Optional Var, - bool hasDynamicLifetime) + bool hasDynamicLifetime, bool isLexical) : InstructionBase(Loc, elementType.getAddressType()), SILDebugVariableSupplement(Var ? Var->DIExpr.getNumElements() : 0, Var ? Var->Type.hasValue() : false, Var ? Var->Loc.hasValue() : false, Var ? Var->Scope != nullptr : false), - dynamicLifetime(hasDynamicLifetime) { + dynamicLifetime(hasDynamicLifetime), lexical(isLexical) { SILNode::Bits.AllocStackInst.NumOperands = TypeDependentOperands.size(); assert(SILNode::Bits.AllocStackInst.NumOperands == @@ -218,19 +218,18 @@ AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType, TypeDependentOperands); } -AllocStackInst * -AllocStackInst::create(SILDebugLocation Loc, - SILType elementType, SILFunction &F, - Optional Var, - bool hasDynamicLifetime) { +AllocStackInst *AllocStackInst::create(SILDebugLocation Loc, + SILType elementType, SILFunction &F, + Optional Var, + bool hasDynamicLifetime, + bool isLexical) { SmallVector TypeDependentOperands; collectTypeDependentOperands(TypeDependentOperands, F, elementType.getASTType()); void *Buffer = allocateDebugVarCarryingInst( F.getModule(), Var, TypeDependentOperands); - return ::new (Buffer) - AllocStackInst(Loc, elementType, TypeDependentOperands, F, Var, - hasDynamicLifetime); + return ::new (Buffer) AllocStackInst(Loc, elementType, TypeDependentOperands, + F, Var, hasDynamicLifetime, isLexical); } VarDecl *AllocationInst::getDecl() const { diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 60880e364d217..ac62f83dab47f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1260,6 +1260,8 @@ class SILPrinter : public SILInstructionVisitor { void visitAllocStackInst(AllocStackInst *AVI) { if (AVI->hasDynamicLifetime()) *this << "[dynamic_lifetime] "; + if (AVI->isLexical()) + *this << "[lexical] "; *this << AVI->getElementType(); printDebugVar(AVI->getVarInfo(), &AVI->getModule().getASTContext().SourceMgr); diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 805447371252d..241867d4a56ec 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -4108,34 +4108,60 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, break; } - case SILInstructionKind::AllocStackInst: - case SILInstructionKind::MetatypeInst: { - + case SILInstructionKind::AllocStackInst: { bool hasDynamicLifetime = false; - if (Opcode == SILInstructionKind::AllocStackInst && - parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime")) + bool isLexical = false; + + while (P.consumeIf(tok::l_square)) { + Identifier ident; + SourceLoc identLoc; + if (parseSILIdentifier(ident, identLoc, + diag::expected_in_attribute_list)) { + if (P.consumeIf(tok::r_square)) { + continue; + } else { + return true; + } + } + StringRef attr = ident.str(); + + if (attr == "dynamic_lifetime") { + hasDynamicLifetime = true; + } else if (attr == "lexical") { + isLexical = true; + } else { + return true; + } + + if (!P.consumeIf(tok::r_square)) + return true; + } + + SILType Ty; + if (parseSILType(Ty)) return true; + SILDebugVariable VarInfo; + if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B)) + return true; + // It doesn't make sense to attach a debug var info if the name is empty + if (VarInfo.Name.size()) + ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime, + isLexical); + else + ResultVal = + B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical); + break; + } + case SILInstructionKind::MetatypeInst: { SILType Ty; if (parseSILType(Ty)) return true; - if (Opcode == SILInstructionKind::AllocStackInst) { - SILDebugVariable VarInfo; - if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B)) - return true; - // It doesn't make sense to attach a debug var info if the name is empty - if (VarInfo.Name.size()) - ResultVal = - B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime); - else - ResultVal = B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime); - } else { - assert(Opcode == SILInstructionKind::MetatypeInst); - if (parseSILDebugLocation(InstLoc, B)) - return true; - ResultVal = B.createMetatype(InstLoc, Ty); - } + assert(Opcode == SILInstructionKind::MetatypeInst); + if (parseSILDebugLocation(InstLoc, B)) + return true; + ResultVal = B.createMetatype(InstLoc, Ty); break; } case SILInstructionKind::AllocRefInst: diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index a752f33451622..57469d49b1745 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -1217,12 +1217,15 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, Loc, cast(MF->getType(TyID)->getCanonicalType()), None, /*bool hasDynamicLifetime*/ Attr != 0); break; - case SILInstructionKind::AllocStackInst: + case SILInstructionKind::AllocStackInst: { assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); + bool hasDynamicLifetime = Attr & 0x1; + bool isLexical = (Attr >> 1) & 0x1; ResultInst = Builder.createAllocStack( Loc, getSILType(MF->getType(TyID), (SILValueCategory)TyCategory, Fn), - None, /*bool hasDynamicLifetime*/ Attr != 0); + None, hasDynamicLifetime, isLexical); break; + } case SILInstructionKind::MetatypeInst: assert(RecordKind == SIL_ONE_TYPE && "Layout should be OneType."); ResultInst = Builder.createMetatype( diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index edbb5c658f091..3b8ac0ba3dd00 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -992,8 +992,9 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { } case SILInstructionKind::AllocStackInst: { const AllocStackInst *ASI = cast(&SI); - writeOneTypeLayout(ASI->getKind(), ASI->hasDynamicLifetime() ? 1 : 0, - ASI->getElementType()); + unsigned attr = + unsigned(ASI->hasDynamicLifetime()) + unsigned(ASI->isLexical() << 1); + writeOneTypeLayout(ASI->getKind(), attr, ASI->getElementType()); break; } case SILInstructionKind::ProjectValueBufferInst: { diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index f4a494071ceb5..619fecbce783d 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -1230,6 +1230,27 @@ bb0: return %2 : $() } +// CHECK-LABEL: sil @test_alloc_stack_flags +sil @test_alloc_stack_flags : $() -> () { + // CHECK: alloc_stack $Builtin.NativeObjec + %instance = alloc_stack $Builtin.NativeObject + dealloc_stack %instance : $*Builtin.NativeObject + // CHECK: alloc_stack [dynamic_lifetime] + %instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject + dealloc_stack %instance2 : $*Builtin.NativeObject + // CHECK: alloc_stack [lexical] + %instance3 = alloc_stack [lexical] $Builtin.NativeObject + dealloc_stack %instance3 : $*Builtin.NativeObject + // CHECK: alloc_stack [dynamic_lifetime] [lexical] + %instance4 = alloc_stack [dynamic_lifetime] [lexical] $Builtin.NativeObject + dealloc_stack %instance4 : $*Builtin.NativeObject + // CHECK: alloc_stack [dynamic_lifetime] [lexical] + %instance5 = alloc_stack [lexical] [dynamic_lifetime] $Builtin.NativeObject + dealloc_stack %instance5 : $*Builtin.NativeObject + %res = tuple () + return %res : $() +} + sil_global @staticProp: $Int // CHECK-LABEL: sil private @globalinit_func0 : $@convention(thin) () -> () { diff --git a/test/SIL/Serialization/borrow.sil b/test/SIL/Serialization/borrow.sil index cdb8725d165f2..0362b1b572c76 100644 --- a/test/SIL/Serialization/borrow.sil +++ b/test/SIL/Serialization/borrow.sil @@ -8,6 +8,40 @@ sil_stage canonical import Builtin +// CHECK-LABEL: sil [serialized] [ossa] @begin_borrow_test +// CHECK: begin_borrow [defined] {{%[^,]+}} +// CHECK: begin_borrow {{%[^,]+}} +// CHECK: } // end sil function 'begin_borrow_test' +sil [serialized] [ossa] @begin_borrow_test : $@convention(thin) () -> () { + %instance = alloc_ref $C + %guaranteed_c = begin_borrow [defined] %instance : $C + end_borrow %guaranteed_c : $C + %guaranteed_c2 = begin_borrow %instance : $C + end_borrow %guaranteed_c2 : $C + destroy_value %instance : $C + %res = tuple () + return %res : $() +} + +// CHECK-LABEL: sil [serialized] [ossa] @alloc_stack_test +// CHECK: alloc_stack $Builtin.NativeObject +// CHECK: alloc_stack [dynamic_lifetime] +// CHECK: alloc_stack [lexical] +// CHECK: alloc_stack [dynamic_lifetime] [lexical] +// CHECK: } // end sil function 'alloc_stack_test' +sil [serialized] [ossa] @alloc_stack_test : $@convention(thin) () -> () { + %instance = alloc_stack $Builtin.NativeObject + dealloc_stack %instance : $*Builtin.NativeObject + %instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject + dealloc_stack %instance2 : $*Builtin.NativeObject + %instance3 = alloc_stack [lexical] $Builtin.NativeObject + dealloc_stack %instance3 : $*Builtin.NativeObject + %instance4 = alloc_stack [lexical] [dynamic_lifetime] $Builtin.NativeObject + dealloc_stack %instance4 : $*Builtin.NativeObject + %res = tuple () + return %res : $() +} + // We do not verify here, but just make sure that all of the combinations parse and print correctly. // CHECK-LABEL: sil [serialized] [ossa] @borrow_test : $@convention(thin) (@in Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () { // CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : @guaranteed $Builtin.NativeObject): @@ -31,15 +65,3 @@ bb0(%0 : $*Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject): } class C {} - -// CHECK-LABEL: sil [ossa] @defined_borrow_test -// CHECK: begin_borrow [defined] {{%[^,]+}} -// CHECK-LABEL: } // end sil function 'defined_borrow_test' -sil [ossa] @defined_borrow_test : $@convention(thin) () -> () { - %instance = alloc_ref $C - %guaranteed_c = begin_borrow [defined] %instance : $C - end_borrow %guaranteed_c : $C - destroy_value %instance : $C - %res = tuple () - return %res : $() -} diff --git a/test/SIL/cloning.sil b/test/SIL/cloning.sil index 1f1b84375d812..46c472dd4e313 100644 --- a/test/SIL/cloning.sil +++ b/test/SIL/cloning.sil @@ -45,3 +45,28 @@ sil [ossa] @caller_begin_borrow_defined : $@convention(thin) () -> () { %res = apply %callee_begin_borrow_defined() : $@convention(thin) () -> () return %res : $() } + +sil [ossa] @callee_alloc_stack : $@convention(thin) () -> () { + %instance = alloc_stack $Builtin.NativeObject + dealloc_stack %instance : $*Builtin.NativeObject + %instance2 = alloc_stack [dynamic_lifetime] $Builtin.NativeObject + dealloc_stack %instance2 : $*Builtin.NativeObject + %instance3 = alloc_stack [lexical] $Builtin.NativeObject + dealloc_stack %instance3 : $*Builtin.NativeObject + %instance4 = alloc_stack [dynamic_lifetime] [lexical] $Builtin.NativeObject + dealloc_stack %instance4 : $*Builtin.NativeObject + %res = tuple () + return %res : $() +} + +// CHECK-LABEL: sil [ossa] @caller_alloc_stack_lexical +// CHECK: alloc_stack +// CHECK: alloc_stack [dynamic_lifetime] +// CHECK: alloc_stack [lexical] +// CHECK: alloc_stack [dynamic_lifetime] [lexical] +// CHECK-LABEL: } // end sil function 'caller_alloc_stack_lexical' +sil [ossa] @caller_alloc_stack_lexical : $@convention(thin) () -> () { + %callee_alloc_stack = function_ref @callee_alloc_stack : $@convention(thin) () -> () + %res = apply %callee_alloc_stack() : $@convention(thin) () -> () + return %res : $() +} From 4fb2d07b2513b599cc546a4f327984f968f00670 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Tue, 17 Aug 2021 15:58:08 -0700 Subject: [PATCH 11/24] Refactor IsBindableVisitor's handling of generic nominals. In order to correctly handle upper bound requirements arising from conditional conformances, we need to be able to ingest requirements introduced by conditional conformance extensions, which means recursively visiting the parent is no longer possible to do cleanly. It is simpler to substitute the generic type's entire generic context as a whole. --- lib/AST/Type.cpp | 242 ++++++++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 106 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f20ea1969684b..0634a0e0bf56e 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1798,12 +1798,13 @@ class IsBindableVisitor } CanType visitDynamicSelfType(DynamicSelfType *orig, CanType subst, - ArchetypeType *, ArrayRef) { + ArchetypeType *upperBound, + ArrayRef substConformances) { // A "dynamic self" type can be bound to another dynamic self type, or the // non-dynamic base class type. if (auto dynSubst = dyn_cast(subst)) { if (auto newBase = visit(orig->getSelfType(), dynSubst.getSelfType(), - nullptr, {})) { + upperBound, substConformances)) { return CanDynamicSelfType::get(newBase, orig->getASTContext()) ->getCanonicalType(); } @@ -1811,31 +1812,146 @@ class IsBindableVisitor } if (auto newNonDynBase = visit(orig->getSelfType(), subst, - nullptr, {})) { + upperBound, substConformances)) { return newNonDynBase; } return CanType(); } + /// Handle a nominal type with generic parameters anywhere in its context. + /// \c origType and \c substType must already have been established to be + /// instantiations of the same \c NominalTypeDecl. + CanType handleGenericNominalType(NominalTypeDecl *decl, + CanType origType, + CanType substType, + ArchetypeType *upperBound, + ArrayRef substConformances) { + assert(origType->getAnyNominal() == decl + && substType->getAnyNominal() == decl); + + auto *moduleDecl = decl->getParentModule(); + auto origSubMap = origType->getContextSubstitutionMap( + moduleDecl, decl, decl->getGenericEnvironment()); + auto substSubMap = substType->getContextSubstitutionMap( + moduleDecl, decl, decl->getGenericEnvironment()); + + auto genericSig = decl->getGenericSignature(); + + SmallVector newParams; + llvm::DenseMap newParamsMap; + bool didChange = false; + + for (auto gpTy : genericSig.getGenericParams()) { + auto gp = gpTy->getCanonicalType(); + + auto orig = gp.subst(origSubMap)->getCanonicalType(); + auto subst = gp.subst(substSubMap)->getCanonicalType(); + + // The new type is upper-bounded by the constraints the nominal type + // requires. The substitution operation may be interested in transforming + // the substituted type's conformances to these protocols. + // + // FIXME: The upperBound on the nominal type itself may impose additional + // requirements on the type parameters due to conditional conformances. + // These are currently not considered, leading to invalid generic signatures + // built during SILGen. + auto paramUpperBound = decl->mapTypeIntoContext(gp) + ->getAs(); + SmallVector paramSubstConformances; + if (paramUpperBound) { + for (auto proto : paramUpperBound->getConformsTo()) { + auto conformance = substSubMap.lookupConformance(gp->getCanonicalType(), + proto); + if (!conformance) + return CanType(); + paramSubstConformances.push_back(conformance); + } + } + + auto newParam = visit(orig, subst, paramUpperBound, + paramSubstConformances); + if (!newParam) + return CanType(); + + newParams.push_back(newParam); + newParamsMap.insert({gpTy, newParam}); + didChange |= (newParam != subst); + } + + SmallVector newConformances; + + // Collect conformances for the new substitutions, and verify that they don't + // invalidate the binding to the original type. + for (const auto &req : genericSig.getRequirements()) { + if (req.getKind() != RequirementKind::Conformance) continue; + + auto canTy = req.getFirstType()->getCanonicalType(); + + // Verify the generic requirements, if the subst type is bound to + // concrete type. + auto *proto = req.getProtocolDecl(); + if (!canTy.subst(substSubMap)->isTypeParameter()) { + auto origConf = origSubMap.lookupConformance(canTy, proto); + auto substConf = substSubMap.lookupConformance(canTy, proto); + + if (origConf.isConcrete()) { + // A generic argument may inherit a concrete conformance from a class + // constraint, which could still be bound to a type parameter we don't + // know more about. + if (origConf.getConcrete()->getType()->is()) + continue; + + if (!substConf.isConcrete()) + return CanType(); + if (origConf.getConcrete()->getRootConformance() + != substConf.getConcrete()->getRootConformance()) + return CanType(); + } + } + + // Gather the conformances for the new binding type, if the type changed. + if (didChange) { + auto newSubstTy = newParamsMap.find(req.getFirstType()); + assert(newSubstTy != newParamsMap.end()); + + if (newSubstTy->second->isTypeParameter()) { + newConformances.push_back(ProtocolConformanceRef(proto)); + } else { + auto newConformance + = moduleDecl->lookupConformance(newSubstTy->second, proto); + if (!newConformance) + return CanType(); + newConformances.push_back(newConformance); + } + } + } + + if (!didChange) + return substType; + + // Build the new substituted generic type. + auto newSubMap = SubstitutionMap::get(genericSig, + newParams, + newConformances); + return decl->getDeclaredInterfaceType().subst(newSubMap) + ->getCanonicalType(); + } + CanType visitNominalType(NominalType *nom, CanType subst, - ArchetypeType*, ArrayRef) { + ArchetypeType* upperBound, + ArrayRef substConformances) { if (auto substNom = dyn_cast(subst)) { + auto nomDecl = nom->getDecl(); if (nom->getDecl() != substNom->getDecl()) return CanType(); - // Same decl should always either have or not have a parent. - assert((bool)nom->getParent() == (bool)substNom->getParent()); - - if (nom->getParent()) { - auto substParent = visit(nom->getParent()->getCanonicalType(), - substNom->getParent()->getCanonicalType(), - nullptr, {}); - if (substParent == substNom.getParent()) - return subst; - return NominalType::get(nom->getDecl(), substParent, - nom->getASTContext()) - ->getCanonicalType(); + // If the type is generic (because it's a nested type in a generic context), + // process the generic type bindings. + if (!isa(nomDecl) && nomDecl->isGenericContext()) { + return handleGenericNominalType(nomDecl, CanType(nom), subst, + upperBound, substConformances); } + // Otherwise, the nongeneric nominal types trivially match. return subst; } return CanType(); @@ -2055,7 +2171,8 @@ class IsBindableVisitor } CanType visitBoundGenericType(BoundGenericType *bgt, CanType subst, - ArchetypeType *, ArrayRef) { + ArchetypeType *upperBound, + ArrayRef substConformances) { auto substBGT = dyn_cast(subst); if (!substBGT) return CanType(); @@ -2065,95 +2182,8 @@ class IsBindableVisitor auto *decl = bgt->getDecl(); - auto *moduleDecl = decl->getParentModule(); - auto origSubMap = bgt->getContextSubstitutionMap( - moduleDecl, decl, decl->getGenericEnvironment()); - auto substSubMap = substBGT->getContextSubstitutionMap( - moduleDecl, decl, decl->getGenericEnvironment()); - - auto genericSig = decl->getGenericSignature(); - - // Same decl should always either have or not have a parent. - assert((bool)bgt->getParent() == (bool)substBGT->getParent()); - CanType newParent; - if (bgt->getParent()) { - newParent = visit(bgt->getParent()->getCanonicalType(), - substBGT.getParent(), - nullptr, {}); - if (!newParent) - return CanType(); - } - - SmallVector newParams; - bool didChange = newParent != substBGT.getParent(); - - auto depthStart = - genericSig.getGenericParams().size() - bgt->getGenericArgs().size(); - for (auto i : indices(bgt->getGenericArgs())) { - auto orig = bgt->getGenericArgs()[i]->getCanonicalType(); - auto subst = substBGT.getGenericArgs()[i]; - auto gp = genericSig.getGenericParams()[depthStart + i]; - - // The new type is upper-bounded by the constraints the nominal type - // requires. The substitution operation may be interested in transforming - // the substituted type's conformances to these protocols. - auto upperBoundArchetype = decl->mapTypeIntoContext(gp) - ->getAs(); - SmallVector substConformances; - if (upperBoundArchetype) { - for (auto proto : upperBoundArchetype->getConformsTo()) { - auto conformance = substSubMap.lookupConformance(gp->getCanonicalType(), - proto); - if (!conformance) - return CanType(); - substConformances.push_back(conformance); - } - } - - auto newParam = visit(orig, subst, upperBoundArchetype, - substConformances); - if (!newParam) - return CanType(); - - newParams.push_back(newParam); - didChange |= (newParam != subst); - } - - for (const auto &req : genericSig.getRequirements()) { - if (req.getKind() != RequirementKind::Conformance) continue; - - auto canTy = req.getFirstType()->getCanonicalType(); - - // If the substituted type is an interface type, we can't verify the - // generic requirements. - if (canTy.subst(substSubMap)->isTypeParameter()) - continue; - - auto *proto = req.getProtocolDecl(); - auto origConf = origSubMap.lookupConformance(canTy, proto); - auto substConf = substSubMap.lookupConformance(canTy, proto); - - if (origConf.isConcrete()) { - // A generic argument may inherit a concrete conformance from a class - // constraint, which could still be bound to a type parameter we don't - // know more about. - if (origConf.getConcrete()->getType()->is()) - continue; - - if (!substConf.isConcrete()) - return CanType(); - if (origConf.getConcrete()->getRootConformance() - != substConf.getConcrete()->getRootConformance()) - return CanType(); - } - } - - if (!didChange) - return subst; - - return BoundGenericType::get(substBGT->getDecl(), - newParent, newParams) - ->getCanonicalType(); + return handleGenericNominalType(decl, CanType(bgt), subst, + upperBound, substConformances); } }; } From 85c7228df84a4c819a6b06ccbeb6dd9ceab82ce0 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 19 Aug 2021 13:37:08 -0700 Subject: [PATCH 12/24] Have IsBindableVisitor consider conditional conformances. The upper bound on a nominal type's generic argument can have more requirements imposed on it than those written in the original nominal type's generic signature, depending on the requirements imposed on the nominal type itself, thanks to conditional conformances. IsBindableVisitor failed to take this into account when visiting the bindings of generic type arguments. This could cause Type::isBindableTo to provide a false positive for a substituted type that doesn't satisfy conditional conformances, but more importantly, SIL type lowering uses the same visitor to extract an upper bound generic signature for substituted SIL function types, and if it doesn't preserve requirements from conditional conformances on nominal types in that signature, it can end up building an incorrect substitution map. Fix this by passing down the upper bound from generic arguments even when visiting nominal types, and using those upper bounds to check for conditional conformances that add requirements to generic arguments while visiting them. --- lib/AST/Type.cpp | 141 +++++++++++++++++- ...unction_type_conditional_conformance.swift | 53 +++++++ 2 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0634a0e0bf56e..7103b2218ab22 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -14,6 +14,8 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "ast-types" + #include "swift/AST/Types.h" #include "ForeignRepresentationInfo.h" #include "swift/AST/ASTContext.h" @@ -39,6 +41,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -1829,6 +1832,15 @@ class IsBindableVisitor assert(origType->getAnyNominal() == decl && substType->getAnyNominal() == decl); + LLVM_DEBUG(llvm::dbgs() << "\n---\nTesting bindability of:\n"; + origType->print(llvm::dbgs()); + llvm::dbgs() << "\nto subst type:\n"; + substType->print(llvm::dbgs()); + if (upperBound) { + llvm::dbgs() << "\nwith upper bound archetype:\n"; + upperBound->print(llvm::dbgs()); + }); + auto *moduleDecl = decl->getParentModule(); auto origSubMap = origType->getContextSubstitutionMap( moduleDecl, decl, decl->getGenericEnvironment()); @@ -1841,7 +1853,125 @@ class IsBindableVisitor llvm::DenseMap newParamsMap; bool didChange = false; - for (auto gpTy : genericSig.getGenericParams()) { + // The upper bounds for the nominal type's arguments may depend on the + // upper bounds imposed on the nominal type itself, if conditional + // conformances are involved. For instance, if we're looking at: + // + // protocol P {} + // struct A {} + // struct B {} + // extension B: P where U: P {} + // + // and visiting `A>`, then `B` has an upper bound of `_: P` because + // of A's generic type constraint. In order to stay within this upper bound, + // `V` must also have `_: P` as its upper bound, in order to satisfy the + // constraint on `B`. To handle this correctly, ingest requirements + // from any extension declarations providing conformances required by the + // upper bound. + auto upperBoundGenericSig = genericSig; + auto upperBoundSubstMap = substSubMap; + + LLVM_DEBUG(llvm::dbgs() << "\nNominal type generic signature:\n"; + upperBoundGenericSig.print(llvm::dbgs()); + upperBoundSubstMap.dump(llvm::dbgs())); + + if (upperBound && !upperBound->getConformsTo().empty()) { + // Start with the set of requirements from the nominal type. + SmallVector addedRequirements; + + llvm::DenseMap, ProtocolConformanceRef> addedConformances; + + for (auto proto : upperBound->getConformsTo()) { + // Find the DeclContext providing the conformance for the type. + auto nomConformance = moduleDecl->lookupConformance(substType, proto); + if (!nomConformance) + return CanType(); + if (nomConformance.isAbstract()) + continue; + auto conformanceContext = nomConformance.getConcrete()->getDeclContext(); + + LLVM_DEBUG(llvm::dbgs() << "\nFound extension conformance for " + << proto->getName() + << " in context:\n"; + conformanceContext->printContext(llvm::dbgs())); + + auto conformanceSig = conformanceContext->getGenericSignatureOfContext(); + // TODO: Conformance on generalized generic extensions could conceivably + // have totally different generic signatures. + assert(conformanceSig.getGenericParams().size() + == genericSig.getGenericParams().size() + && "generalized generic extension not handled properly"); + + // Collect requirements from the conformance not satisfied by the + // original declaration. + for (auto reqt : conformanceSig->requirementsNotSatisfiedBy(genericSig)) { + LLVM_DEBUG(llvm::dbgs() << "\n- adds requirement\n"; + reqt.dump(llvm::dbgs())); + + addedRequirements.push_back(reqt); + + // Collect the matching conformance for the substituted type. + // TODO: Look this up using the upperBoundSubstConformances + if (reqt.getKind() == RequirementKind::Conformance) { + auto proto = reqt.getSecondType()->castTo()->getDecl(); + auto substTy = reqt.getFirstType().subst(substSubMap); + ProtocolConformanceRef substConformance; + if (substTy->isTypeParameter()) { + substConformance = ProtocolConformanceRef(proto); + } else { + substConformance = moduleDecl->lookupConformance(substTy, proto); + } + + LLVM_DEBUG(llvm::dbgs() << "\n` adds conformance for subst type\n"; + substTy->print(llvm::dbgs()); + substConformance.dump(llvm::dbgs())); + + auto key = std::make_pair(reqt.getFirstType()->getCanonicalType(), + proto); + + addedConformances.insert({key, substConformance}); + } + } + } + + // Build the generic signature with the additional collected requirements. + if (!addedRequirements.empty()) { + upperBoundGenericSig = evaluateOrDefault( + decl->getASTContext().evaluator, + AbstractGenericSignatureRequest{ + upperBoundGenericSig.getPointer(), + /*genericParams=*/{ }, + std::move(addedRequirements)}, + nullptr); + upperBoundSubstMap = SubstitutionMap::get(upperBoundGenericSig, + [&](SubstitutableType *t) -> Type { + // Type substitutions remain the same as the original substitution + // map. + return Type(t).subst(substSubMap); + }, + [&](CanType dependentType, + Type conformingReplacementType, + ProtocolDecl *conformedProtocol) -> ProtocolConformanceRef { + // Check whether we added this conformance. + auto added = addedConformances.find({dependentType, + conformedProtocol}); + if (added != addedConformances.end()) { + return added->second; + } + // Otherwise, use the conformance from the original map. + + return substSubMap.lookupConformance(dependentType, conformedProtocol); + }); + + LLVM_DEBUG(llvm::dbgs() << "\nGeneric signature with conditional reqts:\n"; + upperBoundGenericSig.print(llvm::dbgs()); + upperBoundSubstMap.dump(llvm::dbgs())); + } + } + + auto upperBoundGenericEnv = upperBoundGenericSig.getGenericEnvironment(); + + for (auto gpTy : upperBoundGenericSig.getGenericParams()) { auto gp = gpTy->getCanonicalType(); auto orig = gp.subst(origSubMap)->getCanonicalType(); @@ -1855,13 +1985,14 @@ class IsBindableVisitor // requirements on the type parameters due to conditional conformances. // These are currently not considered, leading to invalid generic signatures // built during SILGen. - auto paramUpperBound = decl->mapTypeIntoContext(gp) - ->getAs(); + auto paramUpperBound = + GenericEnvironment::mapTypeIntoContext(upperBoundGenericEnv, gp) + ->getAs(); SmallVector paramSubstConformances; if (paramUpperBound) { for (auto proto : paramUpperBound->getConformsTo()) { - auto conformance = substSubMap.lookupConformance(gp->getCanonicalType(), - proto); + auto conformance = upperBoundSubstMap.lookupConformance(gp->getCanonicalType(), + proto); if (!conformance) return CanType(); paramSubstConformances.push_back(conformance); diff --git a/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift b/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift new file mode 100644 index 0000000000000..0f867d75db931 --- /dev/null +++ b/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift @@ -0,0 +1,53 @@ +// RUN: %target-swift-emit-silgen %s | %FileCheck %s + +enum E { + case a(T.X) +} + +struct S {} + +protocol P { + associatedtype X +} + +extension S : P where T : P { + typealias X = T.X +} + +func foo(_ x: E>) { +// Ensure that the lowered substituted SIL function type for `() -> E>` +// preserves the T: P constraint necessary to allow for `S` to substitute +// into `E` + bar({ return x }) +} + +// CHECK-LABEL: {{^}}sil {{.*}} @${{.*}}3bar +// CHECK-SAME: @substituted <τ_0_0 where τ_0_0 : P> () -> @out E> for +func bar(_: () -> E>) {} + +// --- + +protocol Q: P { + associatedtype Y +} + +enum E2 { + case a(T.Y) +} + +struct S2: P { + typealias X = T.X +} + +extension S2: Q where T: Q { + typealias Y = T.Y +} + +func foo2(_ x: E2>) { + bar2({ return x }) +} + +// CHECK-LABEL: {{^}}sil {{.*}} @${{.*}}4bar2 +// CHECK-SAME: @substituted <τ_0_0 where τ_0_0 : Q> () -> @out E2> for +func bar2(_: () -> E2>) {} + From 2feb76d50443bd64b5bea331531dee6684934831 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Sep 2021 18:30:01 -0400 Subject: [PATCH 13/24] Run type_lowering_subst_function_type_conditional_conformance.swift test with requirement machine enabled --- ...e_lowering_subst_function_type_conditional_conformance.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift b/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift index 0f867d75db931..1910aa0b8dd8e 100644 --- a/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift +++ b/test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen %s | %FileCheck %s +// RUN: %target-swift-emit-silgen %s -requirement-machine=verify | %FileCheck %s enum E { case a(T.X) From eeae6cfa17cafcc5c0176a6a56c18f7542307f8b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 13 Sep 2021 22:54:52 -0400 Subject: [PATCH 14/24] SIL: Fix for when conditional requirements reference nested type parameters --- lib/AST/Type.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 7103b2218ab22..40fcad55141cc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1850,7 +1850,7 @@ class IsBindableVisitor auto genericSig = decl->getGenericSignature(); SmallVector newParams; - llvm::DenseMap newParamsMap; + llvm::DenseMap newParamsMap; bool didChange = false; // The upper bounds for the nominal type's arguments may depend on the @@ -1991,8 +1991,7 @@ class IsBindableVisitor SmallVector paramSubstConformances; if (paramUpperBound) { for (auto proto : paramUpperBound->getConformsTo()) { - auto conformance = upperBoundSubstMap.lookupConformance(gp->getCanonicalType(), - proto); + auto conformance = upperBoundSubstMap.lookupConformance(gp, proto); if (!conformance) return CanType(); paramSubstConformances.push_back(conformance); @@ -2005,7 +2004,7 @@ class IsBindableVisitor return CanType(); newParams.push_back(newParam); - newParamsMap.insert({gpTy, newParam}); + newParamsMap.insert({gp->castTo(), newParam}); didChange |= (newParam != subst); } @@ -2042,14 +2041,15 @@ class IsBindableVisitor // Gather the conformances for the new binding type, if the type changed. if (didChange) { - auto newSubstTy = newParamsMap.find(req.getFirstType()); - assert(newSubstTy != newParamsMap.end()); + auto newSubstTy = req.getFirstType().subst( + QueryTypeSubstitutionMap{newParamsMap}, + LookUpConformanceInModule(moduleDecl)); - if (newSubstTy->second->isTypeParameter()) { + if (newSubstTy->isTypeParameter()) { newConformances.push_back(ProtocolConformanceRef(proto)); } else { auto newConformance - = moduleDecl->lookupConformance(newSubstTy->second, proto); + = moduleDecl->lookupConformance(newSubstTy, proto); if (!newConformance) return CanType(); newConformances.push_back(newConformance); From 7e0eaf7b9926420a2989f75c377a4b2220298a4d Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 14 Sep 2021 11:55:39 -0700 Subject: [PATCH 15/24] Remove metadata section functions from the stdlib (#39236) add aliases in test suite --- .../SwiftReflectionTest.swift | 21 +++++++++++++++++++ stdlib/public/core/Misc.swift | 14 ------------- .../public/runtime/ImageInspectionCommon.cpp | 15 +++++-------- .../stability-stdlib-abi-without-asserts.test | 5 ----- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift index 7904d43015b19..db1919bb81be5 100644 --- a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift +++ b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift @@ -131,6 +131,19 @@ import Glibc let rtldDefault: UnsafeMutableRawPointer? = nil +#if INTERNAL_CHECKS_ENABLED +@_silgen_name("swift_getMetadataSection") +internal func _getMetadataSection(_ index: UInt) -> UnsafeRawPointer? + +@_silgen_name("swift_getMetadataSectionCount") +internal func _getMetadataSectionCount() -> UInt + +@_silgen_name("swift_getMetadataSectionName") +internal func _getMetadataSectionName( + _ metadata_section: UnsafeRawPointer +) -> UnsafePointer +#endif + extension Section { init(range: MetadataSectionRange) { self.startAddress = UnsafeRawPointer(bitPattern: range.start)! @@ -139,6 +152,7 @@ extension Section { } internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? { +#if INTERNAL_CHECKS_ENABLED return _getMetadataSection(UInt(i)).map { rawPointer in let name = _getMetadataSectionName(rawPointer) let metadataSection = rawPointer.bindMemory(to: MetadataSections.self, capacity: 1).pointee @@ -150,10 +164,17 @@ internal func getReflectionInfoForImage(atIndex i: UInt32) -> ReflectionInfo? { typeref: Section(range: metadataSection.swift5_typeref), reflstr: Section(range: metadataSection.swift5_reflstr)) } +#else + return nil +#endif } internal func getImageCount() -> UInt32 { +#if INTERNAL_CHECKS_ENABLED return UInt32(_getMetadataSectionCount()) +#else + return 0 +#endif } internal func sendImages() { diff --git a/stdlib/public/core/Misc.swift b/stdlib/public/core/Misc.swift index 2b63a7f69c93c..469ac429b8ee8 100644 --- a/stdlib/public/core/Misc.swift +++ b/stdlib/public/core/Misc.swift @@ -118,17 +118,3 @@ public func _getTypeByMangledNameInContext( genericContext: UnsafeRawPointer?, genericArguments: UnsafeRawPointer?) -> Any.Type? - -@_silgen_name("swift_getMetadataSection") -public func _getMetadataSection( - _ index: UInt) - -> UnsafeRawPointer? - -@_silgen_name("swift_getMetadataSectionCount") -public func _getMetadataSectionCount() - -> UInt - -@_silgen_name("swift_getMetadataSectionName") -public func _getMetadataSectionName( - _ metadata_section: UnsafeRawPointer) - -> UnsafePointer diff --git a/stdlib/public/runtime/ImageInspectionCommon.cpp b/stdlib/public/runtime/ImageInspectionCommon.cpp index fa2d58a311fe5..c70e886c06806 100644 --- a/stdlib/public/runtime/ImageInspectionCommon.cpp +++ b/stdlib/public/runtime/ImageInspectionCommon.cpp @@ -131,9 +131,10 @@ void swift::initializeTypeMetadataRecordLookup() { void swift::initializeDynamicReplacementLookup() { } +#ifndef NDEBUG + SWIFT_RUNTIME_EXPORT const swift::MetadataSections *swift_getMetadataSection(size_t index) { - #ifndef NDEBUG if (swift::registered == nullptr) { return nullptr; } @@ -147,27 +148,21 @@ const swift::MetadataSections *swift_getMetadataSection(size_t index) { --index; } return selected; - #else // NDEBUG - return nullptr; - #endif // else NDEBUG } SWIFT_RUNTIME_EXPORT const char *swift_getMetadataSectionName(void *metadata_section) { - #ifndef NDEBUG swift::SymbolInfo info; if (lookupSymbol(metadata_section, &info)) { if (info.fileName) { return info.fileName; } } - #endif // NDEBUG return ""; } SWIFT_RUNTIME_EXPORT size_t swift_getMetadataSectionCount() { - #ifndef NDEBUG if (swift::registered == nullptr) return 0; @@ -176,10 +171,10 @@ size_t swift_getMetadataSectionCount() { current != swift::registered; current = current->next, ++count); return count; - #else // NDEBUG - return 0; - #endif // else NDEBUG } + +#endif // NDEBUG + #endif // !defined(__MACH__) #endif // SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H \ No newline at end of file diff --git a/test/api-digester/stability-stdlib-abi-without-asserts.test b/test/api-digester/stability-stdlib-abi-without-asserts.test index 4006a88b676d9..9b731bbf42fb1 100644 --- a/test/api-digester/stability-stdlib-abi-without-asserts.test +++ b/test/api-digester/stability-stdlib-abi-without-asserts.test @@ -50,11 +50,6 @@ Func _prespecialize() is a new API without @available attribute Func _stdlib_isOSVersionAtLeastOrVariantVersionAtLeast(_:_:_:_:_:_:) is a new API without @available attribute -// These reflection APIs are exposed to facilitate building SwiftReflectionTest.swift when testing Release builds. -Func _getMetadataSection(_:) is a new API without @available attribute -Func _getMetadataSectionCount() is a new API without @available attribute -Func _getMetadataSectionName(_:) is a new API without @available attribute - Func Collection.removingSubranges(_:) has been removed Func Collection.subranges(of:) has been removed Func Collection.subranges(where:) has been removed From 2381233ac1029ede7edbe0a3f81d2d0e74d979e5 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Tue, 14 Sep 2021 12:46:48 -0700 Subject: [PATCH 16/24] Add flag -swift-async-framepointer=auto,never,always to control swift extended frame information emission On linux we default to disable the extended frame info (since the system libraries don't support it). On darwin the default is to automatically choose based on the deployment target. The Concurrency library explicitly forces extended frame information and the back deployment library explicitly disables it. --- include/swift/AST/IRGenOptions.h | 12 +++++++++- include/swift/Option/FrontendOptions.td | 4 ++++ lib/Frontend/CompilerInvocation.cpp | 18 +++++++++++++++ lib/IRGen/IRGen.cpp | 12 ++++++++++ .../BackDeployConcurrency/CMakeLists.txt | 1 + stdlib/public/Concurrency/CMakeLists.txt | 22 +++++++++++++++++- .../swift_async_extended_frame_info.swift | 23 +++++++++++++++++++ 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 test/IRGen/swift_async_extended_frame_info.swift diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 427bc6e28fecf..b27fe476bdc36 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -81,6 +81,12 @@ enum class IRGenEmbedMode : unsigned { EmbedBitcode }; +enum class SwiftAsyncFramePointerKind : unsigned { + Auto, // Choose Swift async extended frame info based on deployment target. + Always, // Unconditionally emit Swift async extended frame info. + Never, // Don't emit Swift async extended frame info. +}; + using clang::PointerAuthSchema; struct PointerAuthOptions : clang::PointerAuthOptions { @@ -282,6 +288,8 @@ class IRGenOptions { IRGenLLVMLTOKind LLVMLTOKind : 2; + SwiftAsyncFramePointerKind SwiftAsyncFramePointer : 2; + /// Add names to LLVM values. unsigned HasValueNamesSetting : 1; unsigned ValueNames : 1; @@ -393,7 +401,9 @@ class IRGenOptions { Playground(false), EmitStackPromotionChecks(false), FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None), - LLVMLTOKind(IRGenLLVMLTOKind::None), HasValueNamesSetting(false), + LLVMLTOKind(IRGenLLVMLTOKind::None), + SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto), + HasValueNamesSetting(false), ValueNames(false), EnableReflectionMetadata(true), EnableReflectionNames(true), EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false), LazyInitializeClassMetadata(false), diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 5a3ff6410fd72..3b36485cb2f1d 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -806,6 +806,10 @@ def type_info_dump_filter_EQ : Joined<["-"], "type-info-dump-filter=">, Flags<[FrontendOption]>, HelpText<"One of 'all', 'resilient' or 'fragile'">; +def swift_async_frame_pointer_EQ : Joined<["-"], "swift-async-frame-pointer=">, + Flags<[FrontendOption]>, + HelpText<"One of 'auto', 'always' or 'never'">; + def previous_module_installname_map_file : Separate<["-"], "previous-module-installname-map-file">, MetaVarName<"">, HelpText<"Path to a Json file indicating module name to installname map for @_originallyDefinedIn">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 10a74a9461651..bfdc363947f48 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1908,6 +1908,24 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.VirtualFunctionElimination = true; } + // Default to disabling swift async extended frame info on linux. + if (Triple.getOS() == llvm::Triple::Linux) { + Opts.SwiftAsyncFramePointer = SwiftAsyncFramePointerKind::Never; + } + if (const Arg *A = Args.getLastArg(OPT_swift_async_frame_pointer_EQ)) { + StringRef mode(A->getValue()); + if (mode == "auto") + Opts.SwiftAsyncFramePointer = SwiftAsyncFramePointerKind::Auto; + else if (mode == "always") + Opts.SwiftAsyncFramePointer = SwiftAsyncFramePointerKind::Always; + else if (mode == "never") + Opts.SwiftAsyncFramePointer = SwiftAsyncFramePointerKind::Never; + else { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getAsString(Args), A->getValue()); + } + } + return false; } diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 31ed912b0a3a3..905c5063a9e4f 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -180,6 +180,18 @@ swift::getIRTargetOptions(const IRGenOptions &Opts, ASTContext &Ctx) { TargetOpts.GlobalISelAbort = GlobalISelAbortMode::DisableWithDiag; } + switch (Opts.SwiftAsyncFramePointer) { + case SwiftAsyncFramePointerKind::Never: + TargetOpts.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Never; + break; + case SwiftAsyncFramePointerKind::Auto: + TargetOpts.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::DeploymentBased; + break; + case SwiftAsyncFramePointerKind::Always: + TargetOpts.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Always; + break; + } + clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts(); return std::make_tuple(TargetOpts, ClangOpts.CPU, ClangOpts.Features, ClangOpts.Triple); } diff --git a/stdlib/public/BackDeployConcurrency/CMakeLists.txt b/stdlib/public/BackDeployConcurrency/CMakeLists.txt index beabf8a25bd42..514120348a080 100644 --- a/stdlib/public/BackDeployConcurrency/CMakeLists.txt +++ b/stdlib/public/BackDeployConcurrency/CMakeLists.txt @@ -46,5 +46,6 @@ set(swift_concurrency_options set(swift_concurrency_extra_sources "../BackDeployConcurrency/Exclusivity.cpp" "../BackDeployConcurrency/Metadata.cpp") +set(swift_concurrency_async_fp_mode "never") add_subdirectory(../Concurrency stdlib/public/BackDeployConcurrency) diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 7376eac880275..3f2e067ab4e18 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -31,6 +31,25 @@ if(SWIFT_CONCURRENCY_USES_DISPATCH) endif() endif() + +set(SWIFT_RUNTIME_CONCURRENCY_C_FLAGS) +set(SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS) + +if(NOT swift_concurrency_async_fp_mode) + set(swift_concurrency_async_fp_mode "always") +endif() + +# Don't emit extended frame info on linux, system backtracer and system debugger +# are unlikely to support it. +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=never") +elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=${swift_concurrency_async_fp_mode}") + list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS + "-Xfrontend" + "-swift-async-frame-pointer=${swift_concurrency_async_fp_mode}") +endif() + add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB ../CompatibilityOverride/CompatibilityOverride.cpp Actor.cpp @@ -91,13 +110,14 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I LINK_LIBRARIES ${swift_concurrency_link_libraries} C_COMPILE_FLAGS - -Dswift_Concurrency_EXPORTS + -Dswift_Concurrency_EXPORTS ${SWIFT_RUNTIME_CONCURRENCY_C_FLAGS} SWIFT_COMPILE_FLAGS ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} -parse-stdlib -Xfrontend -enable-experimental-concurrency -Xfrontend -define-availability -Xfrontend "SwiftStdlib 5.5:macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0" + ${SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS} LINK_FLAGS "${SWIFT_RUNTIME_CONCURRENCY_SWIFT_LINK_FLAGS}" ${swift_concurrency_options} INSTALL_IN_COMPONENT ${swift_concurrency_install_component} diff --git a/test/IRGen/swift_async_extended_frame_info.swift b/test/IRGen/swift_async_extended_frame_info.swift new file mode 100644 index 0000000000000..965d2b64a2f44 --- /dev/null +++ b/test/IRGen/swift_async_extended_frame_info.swift @@ -0,0 +1,23 @@ +// RUN: %target-swift-frontend -disable-availability-checking -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=AUTO %s +// RUN: %target-swift-frontend -disable-availability-checking -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=ALWAYS %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=auto -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=AUTO %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=auto -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=ALWAYS %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=never -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=NEVER %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=never -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=NEVER %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=always -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=ALWAYS %s +// RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=always -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=ALWAYS %s + +// REQUIRES: OS=macosx + +public func someAsyncFunction() async { +} + +// AUTO: s31swift_async_extended_frame_info17someAsyncFunctionyyYaF: +// AUTO: _swift_async_extendedFramePointerFlags + +// ALWAYS: s31swift_async_extended_frame_info17someAsyncFunctionyyYaF: +// ALWAYS: btsq $60 + +// NEVER: s31swift_async_extended_frame_info17someAsyncFunctionyyYaF: +// NEVER-NOT: _swift_async_extendedFramePointerFlags +// NEVER-NOT: btsq $60 From a1a9dd16cee3f83d240799c5a4c7ff3b7a51f3a4 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Tue, 14 Sep 2021 12:48:27 -0700 Subject: [PATCH 17/24] Change the logic to exclude extended frame info on all platforms but darwin --- lib/Frontend/CompilerInvocation.cpp | 6 ++++-- stdlib/public/Concurrency/CMakeLists.txt | 13 +++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index bfdc363947f48..40f3a44a0af90 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1908,8 +1908,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.VirtualFunctionElimination = true; } - // Default to disabling swift async extended frame info on linux. - if (Triple.getOS() == llvm::Triple::Linux) { + // Default to disabling swift async extended frame info on anything but + // darwin. Other platforms are unlikely to have support for extended frame + // pointer information. + if (!Triple.isOSDarwin()) { Opts.SwiftAsyncFramePointer = SwiftAsyncFramePointerKind::Never; } if (const Arg *A = Args.getLastArg(OPT_swift_async_frame_pointer_EQ)) { diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index 3f2e067ab4e18..c35cac8d85936 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -39,15 +39,16 @@ if(NOT swift_concurrency_async_fp_mode) set(swift_concurrency_async_fp_mode "always") endif() -# Don't emit extended frame info on linux, system backtracer and system debugger -# are unlikely to support it. -if(CMAKE_SYSTEM_NAME STREQUAL Linux) - list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=never") -elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) - list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=${swift_concurrency_async_fp_mode}") +# Don't emit extended frame info on platforms other than darwin, system +# backtracer and system debugger are unlikely to support it. +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS + "-fswift-async-fp=${swift_concurrency_async_fp_mode}") list(APPEND SWIFT_RUNTIME_CONCURRENCY_SWIFT_FLAGS "-Xfrontend" "-swift-async-frame-pointer=${swift_concurrency_async_fp_mode}") +else() + list(APPEND SWIFT_RUNTIME_CONCURRENCY_C_FLAGS "-fswift-async-fp=never") endif() add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB From a93f77746801d747464a0e6b712798fec371e249 Mon Sep 17 00:00:00 2001 From: Arnold Schwaighofer Date: Sat, 11 Sep 2021 07:02:35 -0700 Subject: [PATCH 18/24] Default to SwiftAsyncFramePointerKind::Always for now --- include/swift/AST/IRGenOptions.h | 2 +- test/IRGen/swift_async_extended_frame_info.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index b27fe476bdc36..9f51d44d38d20 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -402,7 +402,7 @@ class IRGenOptions { EmitStackPromotionChecks(false), FunctionSections(false), PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None), LLVMLTOKind(IRGenLLVMLTOKind::None), - SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto), + SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Always), HasValueNamesSetting(false), ValueNames(false), EnableReflectionMetadata(true), EnableReflectionNames(true), EnableAnonymousContextMangledNames(false), diff --git a/test/IRGen/swift_async_extended_frame_info.swift b/test/IRGen/swift_async_extended_frame_info.swift index 965d2b64a2f44..70349cddd2c03 100644 --- a/test/IRGen/swift_async_extended_frame_info.swift +++ b/test/IRGen/swift_async_extended_frame_info.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -disable-availability-checking -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=AUTO %s +// RUN: %target-swift-frontend -disable-availability-checking -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=ALWAYS %s // RUN: %target-swift-frontend -disable-availability-checking -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=ALWAYS %s // RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=auto -target x86_64-apple-macosx11 %s -S | %FileCheck -check-prefix=AUTO %s // RUN: %target-swift-frontend -disable-availability-checking -swift-async-frame-pointer=auto -target x86_64-apple-macosx12 %s -S | %FileCheck -check-prefix=ALWAYS %s From 00cb1c5330c74eb6677e3fef78fd8cf613ae7d22 Mon Sep 17 00:00:00 2001 From: LucianoAlmeida Date: Sat, 11 Sep 2021 19:12:42 -0300 Subject: [PATCH 19/24] [stdlib] Improve set isDisjoint by iterating on smaller set --- stdlib/public/core/Set.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/stdlib/public/core/Set.swift b/stdlib/public/core/Set.swift index f4fb463fe24db..2567b656e0f74 100644 --- a/stdlib/public/core/Set.swift +++ b/stdlib/public/core/Set.swift @@ -1123,7 +1123,15 @@ extension Set { /// otherwise, `false`. @inlinable public func isDisjoint(with other: Set) -> Bool { - return _isDisjoint(with: other) + guard !isEmpty && !other.isEmpty else { return true } + let (smaller, larger) = + count < other.count ? (self, other) : (other, self) + for member in smaller { + if larger.contains(member) { + return false + } + } + return true } @inlinable From 7e52fb587855a03c44d4ca063f9d2adc62a04058 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 14 Sep 2021 17:23:52 -0400 Subject: [PATCH 20/24] SIL: Use correct SILFunctionConventions when computing method self type in verifier --- lib/SIL/Verifier/SILVerifier.cpp | 1 + test/SILGen/sil_verifier_method_self_type.swift | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 test/SILGen/sil_verifier_method_self_type.swift diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 44be79d1d2339..5252eeac50585 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -3199,6 +3199,7 @@ class SILVerifier : public SILVerifierBase { } SILType getMethodSelfType(CanSILFunctionType ft) { + SILFunctionConventions fnConv(ft, F.getModule()); return fnConv.getSILType(ft->getParameters().back(), F.getTypeExpansionContext()); } diff --git a/test/SILGen/sil_verifier_method_self_type.swift b/test/SILGen/sil_verifier_method_self_type.swift new file mode 100644 index 0000000000000..173302307edb0 --- /dev/null +++ b/test/SILGen/sil_verifier_method_self_type.swift @@ -0,0 +1,11 @@ +// RUN: %target-swift-emit-silgen %s -requirement-machine=verify + +public class C { + public func method() -> Value { fatalError() } +} + +public func foo(_: () -> T) {} + +public func bar() { + foo { C().method() } +} From 680fb6ac4064f9c13f4845dedc95326f69ee69de Mon Sep 17 00:00:00 2001 From: Julian Lettner Date: Wed, 15 Sep 2021 14:50:55 +0200 Subject: [PATCH 21/24] [Swift CI] Re-enable sanitizer symbolication tests (#38489) We updated the Swift CI nodes to a version of Xcode that includes the fix for a regression in atos that broke sanitizer report symbolication. Regression: rdar://79151503 (If atos is handed a dSYM, it should find the binary rather than erring) Fix: rdar://80345994 (Regression: atos -p exits immediately) Radar-Id: rdar://80274830 Co-authored-by: Julian Lettner --- test/Sanitizers/symbolication.swift | 4 ---- test/Sanitizers/tsan/racy_async_let_fibonacci.swift | 4 ---- 2 files changed, 8 deletions(-) diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift index 4b2949e973240..a7930b2e12def 100644 --- a/test/Sanitizers/symbolication.swift +++ b/test/Sanitizers/symbolication.swift @@ -5,10 +5,6 @@ // REQUIRES: asan_runtime // REQUIRES: VENDOR=apple -// rdar://80274830 ([Swift CI] Sanitizer report symbolication fails because we fail to start atos, sanbox issue?) -// REQUIRES: 80274830 -// Might be related/same issue as below - // rdar://75365575 (Failing to start atos external symbolizer) // UNSUPPORTED: OS=watchos diff --git a/test/Sanitizers/tsan/racy_async_let_fibonacci.swift b/test/Sanitizers/tsan/racy_async_let_fibonacci.swift index 1bc28a13b671e..daf273f71d61b 100644 --- a/test/Sanitizers/tsan/racy_async_let_fibonacci.swift +++ b/test/Sanitizers/tsan/racy_async_let_fibonacci.swift @@ -10,10 +10,6 @@ // rdar://76038845 // UNSUPPORTED: use_os_stdlib -// rdar://80274830 ([Swift CI] Sanitizer report symbolication fails because we fail to start atos, sanbox issue?) -// REQUIRES: 80274830 -// Might be related/same issue as below - // rdar://75365575 (Failing to start atos external symbolizer) // UNSUPPORTED: OS=watchos From 82568468494fd74dba17ba695c3cdf6fab1c3369 Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Wed, 15 Sep 2021 07:38:55 -0700 Subject: [PATCH 22/24] Avoid using strcasecmp and unroll the comparison to 'snan' instead (#39182) --- stdlib/public/stubs/Stubs.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index cd53f51c6c2d0..9e80c0af25663 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -265,16 +265,19 @@ swift_stdlib_readLine_stdin(unsigned char **LinePtr) { #endif } -#if defined(__CYGWIN__) || defined(_WIN32) - #define strcasecmp _stricmp -#endif - static bool swift_stringIsSignalingNaN(const char *nptr) { if (nptr[0] == '+' || nptr[0] == '-') { ++nptr; } - return strcasecmp(nptr, "snan") == 0; + if ((nptr[0] == 's' || nptr[0] == 'S') && + (nptr[1] == 'n' || nptr[1] == 'N') && + (nptr[2] == 'a' || nptr[2] == 'A') && + (nptr[3] == 'n' || nptr[3] == 'N') && (nptr[4] == '\0')) { + return true; + } + + return false; } // This implementation should only be used on platforms without the From a723e6d4c233c654a58ab5900f98361bd45ae0fe Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 15 Sep 2021 18:00:13 +0100 Subject: [PATCH 23/24] CMake: disable libdispatch when targeting Wasm/WASI (#39274) Wasm/WASI doesn't currently support multi-threading, and libdispatch should be disabled when building for this target. Related to SR-12097. --- cmake/modules/Libdispatch.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/modules/Libdispatch.cmake b/cmake/modules/Libdispatch.cmake index 8791ea888ecfa..013ffcb593b9a 100644 --- a/cmake/modules/Libdispatch.cmake +++ b/cmake/modules/Libdispatch.cmake @@ -47,7 +47,8 @@ endif() # Build any target libdispatch if needed. foreach(sdk ${SWIFT_SDKS}) # Darwin targets have libdispatch available, do not build it. - if(NOT "${sdk}" IN_LIST SWIFT_DARWIN_PLATFORMS) + # Wasm/WASI doesn't support libdispatch yet. See https://bugs.swift.org/browse/SR-12097 for more details. + if(NOT "${sdk}" IN_LIST SWIFT_DARWIN_PLATFORMS AND NOT "${sdk}" STREQUAL WASI) list(APPEND DISPATCH_SDKS "${sdk}") endif() endforeach() From feece9da701d1dfb8bc5cdff62049c4f854801fa Mon Sep 17 00:00:00 2001 From: Nate Cook Date: Wed, 15 Sep 2021 14:45:18 -0500 Subject: [PATCH 24/24] Revert "[Swift CI] Re-enable sanitizer symbolication tests (#38489)" (#39320) This reverts commit 680fb6ac4064f9c13f4845dedc95326f69ee69de. --- test/Sanitizers/symbolication.swift | 4 ++++ test/Sanitizers/tsan/racy_async_let_fibonacci.swift | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/Sanitizers/symbolication.swift b/test/Sanitizers/symbolication.swift index a7930b2e12def..4b2949e973240 100644 --- a/test/Sanitizers/symbolication.swift +++ b/test/Sanitizers/symbolication.swift @@ -5,6 +5,10 @@ // REQUIRES: asan_runtime // REQUIRES: VENDOR=apple +// rdar://80274830 ([Swift CI] Sanitizer report symbolication fails because we fail to start atos, sanbox issue?) +// REQUIRES: 80274830 +// Might be related/same issue as below + // rdar://75365575 (Failing to start atos external symbolizer) // UNSUPPORTED: OS=watchos diff --git a/test/Sanitizers/tsan/racy_async_let_fibonacci.swift b/test/Sanitizers/tsan/racy_async_let_fibonacci.swift index daf273f71d61b..1bc28a13b671e 100644 --- a/test/Sanitizers/tsan/racy_async_let_fibonacci.swift +++ b/test/Sanitizers/tsan/racy_async_let_fibonacci.swift @@ -10,6 +10,10 @@ // rdar://76038845 // UNSUPPORTED: use_os_stdlib +// rdar://80274830 ([Swift CI] Sanitizer report symbolication fails because we fail to start atos, sanbox issue?) +// REQUIRES: 80274830 +// Might be related/same issue as below + // rdar://75365575 (Failing to start atos external symbolizer) // UNSUPPORTED: OS=watchos