diff --git a/CHANGELOG.md b/CHANGELOG.md index e0fb2864e8601..6a78223d73018 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,7 +135,7 @@ And the module structure to support such applications looks like this: ```swift @MainActor - class MyViewController: ViewDelegateProtocol { + class MyViewController: @preconcurrency ViewDelegateProtocol { func respondToUIEvent() { // implementation... } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift index 0dba0d0487ab2..eabfae2e05d12 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift @@ -64,8 +64,11 @@ func computeLinearLiveness(for definingValue: Value, _ context: Context) var range = InstructionRange(for: definingValue, context) // Compute liveness. - definingValue.lookThroughBorrowedFromUser.uses.endingLifetime.forEach { - range.insert($0.instruction) + for use in definingValue.lookThroughBorrowedFromUser.uses { + let instruction = use.instruction + if use.endsLifetime || instruction is ExtendLifetimeInst { + range.insert(instruction) + } } return range } diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 5127fe6e36492..e0f74296387e8 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -514,6 +514,8 @@ final public class DestroyAddrInst : Instruction, UnaryInstruction { final public class EndLifetimeInst : Instruction, UnaryInstruction {} +final public class ExtendLifetimeInst : Instruction, UnaryInstruction {} + final public class InjectEnumAddrInst : Instruction, UnaryInstruction, EnumInstruction { public var `enum`: Value { operand.value } public var caseIndex: Int { bridged.InjectEnumAddrInst_caseIndex() } diff --git a/SwiftCompilerSources/Sources/SIL/Registration.swift b/SwiftCompilerSources/Sources/SIL/Registration.swift index d2f7c22023727..72b89e82a2801 100644 --- a/SwiftCompilerSources/Sources/SIL/Registration.swift +++ b/SwiftCompilerSources/Sources/SIL/Registration.swift @@ -78,6 +78,7 @@ public func registerSILClasses() { register(DestroyValueInst.self) register(DestroyAddrInst.self) register(EndLifetimeInst.self) + register(ExtendLifetimeInst.self) register(StrongCopyUnownedValueInst.self) register(StrongCopyUnmanagedValueInst.self) register(StrongCopyWeakValueInst.self) diff --git a/docs/SIL.rst b/docs/SIL.rst index 64a731d50c12c..81a65299311a3 100644 --- a/docs/SIL.rst +++ b/docs/SIL.rst @@ -4682,6 +4682,22 @@ The instruction accepts an object or address type. This instruction is valid only in OSSA and is lowered to a no-op when lowering to non-OSSA. +extend_lifetime +``````````````` + +:: + + sil-instruction ::= 'extend_lifetime' sil-operand + + // Indicate that %0's linear lifetime extends to this point + extend_lifetime %0 : $X + +Indicates that a value's linear lifetime extends to this point. Inserted by +OSSALifetimeCompletion(AvailabilityBoundary) in order to provide the invariant +that a value is either consumed OR has an `extend_lifetime` user on all paths +and furthermore that all uses are within the boundary defined by that set of +instructions (the consumes and the `extend_lifetime`s). + assign `````` :: diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index 8320435945672..38c9aca02e278 100644 --- a/include/swift-c/DependencyScan/DependencyScan.h +++ b/include/swift-c/DependencyScan/DependencyScan.h @@ -25,7 +25,7 @@ /// SWIFTSCAN_VERSION_MINOR should increase when there are API additions. /// SWIFTSCAN_VERSION_MAJOR is intended for "major" source/ABI breaking changes. #define SWIFTSCAN_VERSION_MAJOR 0 -#define SWIFTSCAN_VERSION_MINOR 9 +#define SWIFTSCAN_VERSION_MINOR 10 SWIFTSCAN_BEGIN_DECLS @@ -46,6 +46,9 @@ typedef struct swiftscan_module_details_s *swiftscan_module_details_t; /// Opaque container to a dependency info of a given module. typedef struct swiftscan_dependency_info_s *swiftscan_dependency_info_t; +/// Opaque container to a link library info. +typedef struct swiftscan_link_library_info_s *swiftscan_link_library_info_t; + /// Opaque container to an overall result of a dependency scan. typedef struct swiftscan_dependency_graph_s *swiftscan_dependency_graph_t; @@ -64,6 +67,12 @@ typedef struct { size_t count; } swiftscan_dependency_set_t; +/// Set of linked libraries +typedef struct { + swiftscan_link_library_info_t *link_libraries; + size_t count; +} swiftscan_link_library_set_t; + typedef enum { SWIFTSCAN_DIAGNOSTIC_SEVERITY_ERROR = 0, SWIFTSCAN_DIAGNOSTIC_SEVERITY_WARNING = 1, @@ -127,9 +136,21 @@ swiftscan_module_info_get_source_files(swiftscan_dependency_info_t info); SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_module_info_get_direct_dependencies(swiftscan_dependency_info_t info); +SWIFTSCAN_PUBLIC swiftscan_link_library_set_t * +swiftscan_module_info_get_link_libraries(swiftscan_dependency_info_t info); + SWIFTSCAN_PUBLIC swiftscan_module_details_t swiftscan_module_info_get_details(swiftscan_dependency_info_t info); +//=== Link Library Info Functions ------------------------------------===// +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_link_library_info_get_link_name( + swiftscan_link_library_info_t info); +SWIFTSCAN_PUBLIC bool swiftscan_link_library_info_get_is_framework( + swiftscan_link_library_info_t info); +SWIFTSCAN_PUBLIC bool swiftscan_link_library_info_get_should_force_load( + swiftscan_link_library_info_t info); + //=== Dependency Module Info Details Functions ----------------------------===// SWIFTSCAN_PUBLIC swiftscan_dependency_info_kind_t diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h index d7769211b0d43..95dc3c660ffa2 100644 --- a/include/swift/ABI/Executor.h +++ b/include/swift/ABI/Executor.h @@ -260,12 +260,6 @@ class TaskExecutorRef { return reinterpret_cast(table); } -// /// Do we have to do any work to start running as the requested -// /// executor? -// bool mustSwitchToRun(TaskExecutorRef newExecutor) const { -// return Identity != newExecutor.Identity; -// } - /// Get the raw value of the Implementation field, for tracing. uintptr_t getRawImplementation() const { return Implementation & WitnessTableMask; diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index edd1ccfd5f932..3fdc23fb5f2e9 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -2697,7 +2697,8 @@ enum class TaskOptionRecordKind : uint8_t { /// Information about the result type of the task, used in embedded Swift. ResultTypeInfo = 4, /// Set the initial task executor preference of the task. - InitialTaskExecutor = 5, + InitialTaskExecutorUnowned = 5, + InitialTaskExecutorOwned = 6, /// Request a child task for swift_task_run_inline. RunInline = UINT8_MAX, }; diff --git a/include/swift/ABI/Task.h b/include/swift/ABI/Task.h index 4ef2550b8ca3e..1cefd0f45077d 100644 --- a/include/swift/ABI/Task.h +++ b/include/swift/ABI/Task.h @@ -419,12 +419,16 @@ class AsyncTask : public Job { /// Get the preferred task executor reference if there is one set for this /// task. - TaskExecutorRef getPreferredTaskExecutor(); + TaskExecutorRef getPreferredTaskExecutor(bool assumeHasRecord = false); /// WARNING: Only to be used during task creation, in other situations prefer /// to use `swift_task_pushTaskExecutorPreference` and /// `swift_task_popTaskExecutorPreference`. - void pushInitialTaskExecutorPreference(TaskExecutorRef preferred); + /// + /// The `owned` parameter indicates if the executor is owned by the task, + /// and must be released when the task completes. + void pushInitialTaskExecutorPreference( + TaskExecutorRef preferred, bool owned); /// WARNING: Only to be used during task completion (destroy). /// diff --git a/include/swift/ABI/TaskOptions.h b/include/swift/ABI/TaskOptions.h index 96cc3d88e6bc4..39775009bef4d 100644 --- a/include/swift/ABI/TaskOptions.h +++ b/include/swift/ABI/TaskOptions.h @@ -77,23 +77,58 @@ class TaskGroupTaskOptionRecord : public TaskOptionRecord { /// Task option to specify on what executor the task should be executed. /// -/// Not passing this option implies that an inferred (e.g. surrounding actor -/// when we inherit execution context) or the default executor should be used. +/// Not passing this option (or it's alternative "owned" version) implies that +/// an inferred (e.g. surrounding actor when we inherit execution context) +/// or the default executor should be used. /// /// Lack of this option usually means that the global concurrent executor, or /// the executor of the enclosing actor will be used. -class InitialTaskExecutorPreferenceTaskOptionRecord : public TaskOptionRecord { +class InitialTaskExecutorRefPreferenceTaskOptionRecord : public TaskOptionRecord { const TaskExecutorRef Executor; public: - InitialTaskExecutorPreferenceTaskOptionRecord(TaskExecutorRef executor) - : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutor), + InitialTaskExecutorRefPreferenceTaskOptionRecord(TaskExecutorRef executor) + : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutorUnowned), Executor(executor) {} TaskExecutorRef getExecutorRef() const { return Executor; } static bool classof(const TaskOptionRecord *record) { - return record->getKind() == TaskOptionRecordKind::InitialTaskExecutor; + return record->getKind() == TaskOptionRecordKind::InitialTaskExecutorUnowned; + } +}; + +/// This is quite similar to `InitialTaskExecutorRefPreferenceTaskOptionRecord` +/// however it takes a "raw" TaskExecutor existential in the form of an Identity +/// and WitnessTable - rather than the specific UnownedTaskExecutor which already +/// may have specific "flags" set on it. +/// +/// In order to use the executor in the runtime, we need to call into the type's +/// `asUnownedTaskExecutor` which is done by +/// `getExecutorRefFromUnownedTaskExecutor`. +class InitialTaskExecutorOwnedPreferenceTaskOptionRecord + : public TaskOptionRecord { + + // These look similar to TaskExecutorRef but are NOT the same! + // A TaskExecutorRef is obtained through calling user defined + // `asUnownedTaskExecutor` which is what we need to do on these to get a real executor ref. + HeapObject *Identity; + const TaskExecutorWitnessTable *WitnessTable; + +public: + InitialTaskExecutorOwnedPreferenceTaskOptionRecord( + HeapObject *executor, uintptr_t witnessTable) + : TaskOptionRecord(TaskOptionRecordKind::InitialTaskExecutorOwned), + Identity(executor) { + WitnessTable = reinterpret_cast(witnessTable); + } + + /// Invokes Swift implemented `asUnownedTaskExecutor` in order to obtain an + /// `TaskExecutorRef` which is properly populated with any flags it might need. + TaskExecutorRef getExecutorRefFromUnownedTaskExecutor() const; + + static bool classof(const TaskOptionRecord *record) { + return record->getKind() == TaskOptionRecordKind::InitialTaskExecutorOwned; } }; diff --git a/include/swift/ABI/TaskStatus.h b/include/swift/ABI/TaskStatus.h index 88702002189cf..5c3a38932baba 100644 --- a/include/swift/ABI/TaskStatus.h +++ b/include/swift/ABI/TaskStatus.h @@ -20,6 +20,7 @@ #ifndef SWIFT_ABI_TASKSTATUS_H #define SWIFT_ABI_TASKSTATUS_H +#include "swift/Basic/OptionSet.h" #include "swift/ABI/MetadataValues.h" #include "swift/ABI/Task.h" #include "swift/ABI/Executor.h" @@ -285,15 +286,35 @@ class EscalationNotificationStatusRecord : public TaskStatusRecord { /// innermost preference takes priority. class TaskExecutorPreferenceStatusRecord : public TaskStatusRecord { private: + enum class Flags : uint8_t { + /// The executor was retained during this task's creation, + /// and therefore must be released when this task completes. + /// + /// The only tasks which need to manually retain/release the task executor + /// are those which cannot structurally guarantee its lifetime. E.g. an async + /// let does not need to do so, because it structurally always will end + /// before/// we leave the scope in which it was defined -- and such scope + /// must have been keeping alive the executor. + HasRetainedExecutor = 1 << 0 + }; + OptionSet flags; const TaskExecutorRef Preferred; public: - TaskExecutorPreferenceStatusRecord(TaskExecutorRef executor) + TaskExecutorPreferenceStatusRecord(TaskExecutorRef executor, bool retainedExecutor) : TaskStatusRecord(TaskStatusRecordKind::TaskExecutorPreference), - Preferred(executor) {} + Preferred(executor) { + if (retainedExecutor) { + flags = Flags::HasRetainedExecutor; + } + } TaskExecutorRef getPreferredExecutor() { return Preferred; } + bool hasRetainedExecutor() const { + return flags.contains(Flags::HasRetainedExecutor); + } + static bool classof(const TaskStatusRecord *record) { return record->getKind() == TaskStatusRecordKind::TaskExecutorPreference; } diff --git a/include/swift/AST/ASTSynthesis.h b/include/swift/AST/ASTSynthesis.h index 6605cff3959cb..f01fb594c9ad6 100644 --- a/include/swift/AST/ASTSynthesis.h +++ b/include/swift/AST/ASTSynthesis.h @@ -328,6 +328,10 @@ constexpr SpecifiedParamSynthesizer _owned(G sub) { return {ParamSpecifier::LegacyOwned, sub}; } template +constexpr SpecifiedParamSynthesizer _consuming(G sub) { + return {ParamSpecifier::Consuming, sub}; +} +template constexpr SpecifiedParamSynthesizer _inout(G sub) { return {ParamSpecifier::InOut, sub}; } diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 7bf1dceed2f46..97821a3aefc53 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7830,6 +7830,10 @@ ERROR(noncopyable_objc_enum, none, "noncopyable enums cannot be marked '@objc'", ()) ERROR(moveOnly_not_allowed_here,none, "'@_moveOnly' attribute is only valid on structs or enums", ()) +ERROR(consume_expression_needed_for_cast,none, + "implicit conversion to %0 is consuming", (Type)) +NOTE(add_consume_to_silence,none, + "add 'consume' to make consumption explicit", ()) ERROR(consume_expression_not_passed_lvalue,none, "'consume' can only be applied to a local binding ('let', 'var', or parameter)", ()) ERROR(consume_expression_partial_copyable,none, diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 68654b5974e68..0c7bbc8ef3cc6 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -337,6 +337,9 @@ class IRGenOptions { /// Whether we should disable inserting autolink directives altogether. unsigned DisableAllAutolinking : 1; + /// Whether we should disable inserting __swift_FORCE_LOAD_ symbols. + unsigned DisableForceLoadSymbols : 1; + /// Print the LLVM inline tree at the end of the LLVM pass pipeline. unsigned PrintInlineTree : 1; diff --git a/include/swift/AST/Import.h b/include/swift/AST/Import.h index 8f3bfaa961c95..0e014d5e24036 100644 --- a/include/swift/AST/Import.h +++ b/include/swift/AST/Import.h @@ -36,6 +36,7 @@ namespace swift { class ASTContext; class ModuleDecl; +class ImportDecl; // MARK: - Fundamental import enums @@ -102,6 +103,8 @@ using ImportOptions = OptionSet; void simple_display(llvm::raw_ostream &out, ImportOptions options); +ImportOptions getImportOptions(ImportDecl *ID); + // MARK: - Import Paths namespace detail { diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 980affdaa4013..e6a02d3a14756 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -19,6 +19,7 @@ #define SWIFT_AST_MODULE_DEPENDENCIES_H #include "swift/AST/Import.h" +#include "swift/AST/LinkLibrary.h" #include "swift/AST/SearchPathOptions.h" #include "swift/Basic/LLVM.h" #include "clang/CAS/CASOptions.h" @@ -50,6 +51,7 @@ class SourceFile; class ASTContext; class Identifier; class CompilerInstance; +class IRGenOptions; /// Which kind of module dependencies we are looking for. enum class ModuleDependencyKind : int8_t { @@ -93,12 +95,10 @@ struct ModuleDependencyID { std::string ModuleName; ModuleDependencyKind Kind; bool operator==(const ModuleDependencyID &Other) const { - return std::tie(ModuleName, Kind) == - std::tie(Other.ModuleName, Other.Kind); + return std::tie(ModuleName, Kind) == std::tie(Other.ModuleName, Other.Kind); } - bool operator<(const ModuleDependencyID& Other) const { - return std::tie(ModuleName, Kind) < - std::tie(Other.ModuleName, Other.Kind); + bool operator<(const ModuleDependencyID &Other) const { + return std::tie(ModuleName, Kind) < std::tie(Other.ModuleName, Other.Kind); } }; @@ -115,50 +115,50 @@ struct ModuleDependencyIDHash { }; using ModuleDependencyIDSet = - std::unordered_set; + std::unordered_set; using ModuleDependencyIDSetVector = llvm::SetVector, std::set>; namespace dependencies { - std::string createEncodedModuleKindAndName(ModuleDependencyID id); - bool checkImportNotTautological(const ImportPath::Module, - const SourceLoc, - const SourceFile&, - bool); -} +std::string createEncodedModuleKindAndName(ModuleDependencyID id); +bool checkImportNotTautological(const ImportPath::Module, const SourceLoc, + const SourceFile &, bool); +void registerBackDeployLibraries( + const IRGenOptions &IRGenOpts, + std::function RegistrationCallback); +void registerCxxInteropLibraries( + const llvm::Triple &Target, StringRef mainModuleName, bool hasStaticCxx, + bool hasStaticCxxStdlib, + std::function RegistrationCallback); +} // namespace dependencies struct ScannerImportStatementInfo { struct ImportDiagnosticLocationInfo { ImportDiagnosticLocationInfo() = delete; ImportDiagnosticLocationInfo(std::string bufferIdentifier, - uint32_t lineNumber, - uint32_t columnNumber) - : bufferIdentifier(bufferIdentifier), - lineNumber(lineNumber), - columnNumber(columnNumber) {} + uint32_t lineNumber, uint32_t columnNumber) + : bufferIdentifier(bufferIdentifier), lineNumber(lineNumber), + columnNumber(columnNumber) {} std::string bufferIdentifier; uint32_t lineNumber; uint32_t columnNumber; }; ScannerImportStatementInfo(std::string importIdentifier) - : importLocations(), - importIdentifier(importIdentifier) {} + : importLocations(), importIdentifier(importIdentifier) {} ScannerImportStatementInfo(std::string importIdentifier, ImportDiagnosticLocationInfo location) - : importLocations({location}), - importIdentifier(importIdentifier) {} + : importLocations({location}), importIdentifier(importIdentifier) {} void addImportLocation(ImportDiagnosticLocationInfo location) { importLocations.push_back(location); } - // Buffer, line & column number of the import statement + /// Buffer, line & column number of the import statement SmallVector importLocations; - // Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar' + /// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar' std::string importIdentifier; }; @@ -170,19 +170,21 @@ class ModuleDependencyInfoStorageBase { const ModuleDependencyKind dependencyKind; ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind, + ArrayRef linkLibraries, StringRef moduleCacheKey = "") - : dependencyKind(dependencyKind), moduleCacheKey(moduleCacheKey.str()), - resolved(false), finalized(false) {} + : dependencyKind(dependencyKind), linkLibraries(linkLibraries), + moduleCacheKey(moduleCacheKey.str()), resolved(false), + finalized(false) {} ModuleDependencyInfoStorageBase( ModuleDependencyKind dependencyKind, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, - StringRef moduleCacheKey = "") + ArrayRef moduleImports, + ArrayRef optionalModuleImports, + ArrayRef linkLibraries, StringRef moduleCacheKey = "") : dependencyKind(dependencyKind), moduleImports(moduleImports), optionalModuleImports(optionalModuleImports), - moduleCacheKey(moduleCacheKey.str()), resolved(false), - finalized(false) {} + linkLibraries(linkLibraries), moduleCacheKey(moduleCacheKey.str()), + resolved(false), finalized(false) {} virtual ModuleDependencyInfoStorageBase *clone() const = 0; @@ -196,6 +198,10 @@ class ModuleDependencyInfoStorageBase { /// or `internal` imports. std::vector optionalModuleImports; + /// A collection of libraries that must be linked to + /// use this module. + std::vector linkLibraries; + /// The set of modules on which this module depends, resolved /// to Module IDs, qualified by module kind: Swift, Clang, etc. std::vector resolvedDirectModuleDependencies; @@ -221,7 +227,7 @@ class ModuleDependencyInfoStorageBase { struct CommonSwiftTextualModuleDependencyDetails { CommonSwiftTextualModuleDependencyDetails( ArrayRef extraPCMArgs, ArrayRef buildCommandLine, - const std::string &CASFileSystemRootID) + StringRef CASFileSystemRootID) : extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()), buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), CASFileSystemRootID(CASFileSystemRootID) {} @@ -251,11 +257,12 @@ struct CommonSwiftTextualModuleDependencyDetails { std::string CASBridgingHeaderIncludeTreeRootID; }; -/// Describes the dependencies of a Swift module described by an Swift interface file. +/// Describes the dependencies of a Swift module described by an Swift interface +/// file. /// /// This class is mostly an implementation detail for \c ModuleDependencyInfo. -class SwiftInterfaceModuleDependenciesStorage : - public ModuleDependencyInfoStorageBase { +class SwiftInterfaceModuleDependenciesStorage + : public ModuleDependencyInfoStorageBase { public: /// Destination output path const std::string moduleOutputPath; @@ -272,23 +279,25 @@ class SwiftInterfaceModuleDependenciesStorage : /// A flag that indicates this dependency is a framework const bool isFramework; + /// A flag that indicates this dependency is associated with a static archive + const bool isStatic; + /// Details common to Swift textual (interface or source) modules CommonSwiftTextualModuleDependencyDetails textualModuleDetails; SwiftInterfaceModuleDependenciesStorage( - const std::string &moduleOutputPath, - const std::string &swiftInterfaceFile, - ArrayRef compiledModuleCandidates, - ArrayRef buildCommandLine, ArrayRef extraPCMArgs, - StringRef contextHash, bool isFramework, const std::string &RootID, - const std::string &moduleCacheKey) + StringRef moduleOutputPath, StringRef swiftInterfaceFile, + ArrayRef compiledModuleCandidates, + ArrayRef buildCommandLine, ArrayRef linkLibraries, + ArrayRef extraPCMArgs, StringRef contextHash, bool isFramework, + bool isStatic, StringRef RootID, StringRef moduleCacheKey) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftInterface, - moduleCacheKey), + linkLibraries, moduleCacheKey), moduleOutputPath(moduleOutputPath), swiftInterfaceFile(swiftInterfaceFile), compiledModuleCandidates(compiledModuleCandidates.begin(), compiledModuleCandidates.end()), - contextHash(contextHash), isFramework(isFramework), + contextHash(contextHash), isFramework(isFramework), isStatic(isStatic), textualModuleDetails(extraPCMArgs, buildCommandLine, RootID) {} ModuleDependencyInfoStorageBase *clone() const override { @@ -307,10 +316,9 @@ class SwiftInterfaceModuleDependenciesStorage : /// Describes the dependencies of a Swift module /// /// This class is mostly an implementation detail for \c ModuleDependencyInfo. -class SwiftSourceModuleDependenciesStorage : - public ModuleDependencyInfoStorageBase { +class SwiftSourceModuleDependenciesStorage + : public ModuleDependencyInfoStorageBase { public: - /// Swift source files that are part of the Swift module, when known. std::vector sourceFiles; @@ -324,10 +332,10 @@ class SwiftSourceModuleDependenciesStorage : std::vector bridgingHeaderBuildCommandLine; SwiftSourceModuleDependenciesStorage( - const std::string &RootID, ArrayRef buildCommandLine, + StringRef RootID, ArrayRef buildCommandLine, ArrayRef bridgingHeaderBuildCommandLine, ArrayRef extraPCMArgs) - : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftSource), + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftSource, {}), textualModuleDetails(extraPCMArgs, buildCommandLine, RootID), testableImports(llvm::StringSet<>()), bridgingHeaderBuildCommandLine(bridgingHeaderBuildCommandLine.begin(), @@ -363,18 +371,18 @@ class SwiftBinaryModuleDependencyStorage : public ModuleDependencyInfoStorageBase { public: SwiftBinaryModuleDependencyStorage( - const std::string &compiledModulePath, const std::string &moduleDocPath, - const std::string &sourceInfoPath, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, - const std::string &headerImport, const bool isFramework, - const std::string &moduleCacheKey) + StringRef compiledModulePath, StringRef moduleDocPath, + StringRef sourceInfoPath, + ArrayRef moduleImports, + ArrayRef optionalModuleImports, + ArrayRef linkLibraries, StringRef headerImport, + bool isFramework, bool isStatic, StringRef moduleCacheKey) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, moduleImports, optionalModuleImports, - moduleCacheKey), + linkLibraries, moduleCacheKey), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath), headerImport(headerImport), - isFramework(isFramework) {} + isFramework(isFramework), isStatic(isStatic) {} ModuleDependencyInfoStorageBase *clone() const override { return new SwiftBinaryModuleDependencyStorage(*this); @@ -401,6 +409,9 @@ class SwiftBinaryModuleDependencyStorage /// A flag that indicates this dependency is a framework const bool isFramework; + /// A flag that indicates this dependency is associated with a static archive + const bool isStatic; + static bool classof(const ModuleDependencyInfoStorageBase *base) { return base->dependencyKind == ModuleDependencyKind::SwiftBinary; } @@ -443,19 +454,17 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { /// Whether this is a "system" module. bool IsSystem; - ClangModuleDependencyStorage(const std::string &pcmOutputPath, - const std::string &mappedPCMPath, - const std::string &moduleMapFile, - const std::string &contextHash, - const std::vector &buildCommandLine, - const std::vector &fileDependencies, - const std::vector &capturedPCMArgs, - const std::string &CASFileSystemRootID, - const std::string &clangIncludeTreeRoot, - const std::string &moduleCacheKey, - bool IsSystem) + ClangModuleDependencyStorage(StringRef pcmOutputPath, StringRef mappedPCMPath, + StringRef moduleMapFile, StringRef contextHash, + ArrayRef buildCommandLine, + ArrayRef fileDependencies, + ArrayRef capturedPCMArgs, + ArrayRef linkLibraries, + StringRef CASFileSystemRootID, + StringRef clangIncludeTreeRoot, + StringRef moduleCacheKey, bool IsSystem) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang, - moduleCacheKey), + linkLibraries, moduleCacheKey), pcmOutputPath(pcmOutputPath), mappedPCMPath(mappedPCMPath), moduleMapFile(moduleMapFile), contextHash(contextHash), buildCommandLine(buildCommandLine), fileDependencies(fileDependencies), @@ -471,7 +480,7 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { return base->dependencyKind == ModuleDependencyKind::Clang; } - void updateCommandLine(const std::vector &newCommandLine) { + void updateCommandLine(ArrayRef newCommandLine) { buildCommandLine = newCommandLine; } }; @@ -480,14 +489,15 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { /// /// This class is mostly an implementation detail for \c ModuleDependencyInfo. -class SwiftPlaceholderModuleDependencyStorage : public ModuleDependencyInfoStorageBase { +class SwiftPlaceholderModuleDependencyStorage + : public ModuleDependencyInfoStorageBase { public: - SwiftPlaceholderModuleDependencyStorage(const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath) - : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftPlaceholder), - compiledModulePath(compiledModulePath), - moduleDocPath(moduleDocPath), + SwiftPlaceholderModuleDependencyStorage(StringRef compiledModulePath, + StringRef moduleDocPath, + StringRef sourceInfoPath) + : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftPlaceholder, + {}), + compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath) {} ModuleDependencyInfoStorageBase *clone() const override { @@ -518,13 +528,14 @@ class ModuleDependencyInfo { private: std::unique_ptr storage; - ModuleDependencyInfo(std::unique_ptr &&storage) - : storage(std::move(storage)) { } + ModuleDependencyInfo( + std::unique_ptr &&storage) + : storage(std::move(storage)) {} public: ModuleDependencyInfo() = default; ModuleDependencyInfo(const ModuleDependencyInfo &other) - : storage(other.storage->clone()) { } + : storage(other.storage->clone()) {} ModuleDependencyInfo(ModuleDependencyInfo &&other) = default; ModuleDependencyInfo &operator=(const ModuleDependencyInfo &other) { @@ -536,36 +547,32 @@ class ModuleDependencyInfo { /// Describe the module dependencies for a Swift module that can be /// built from a Swift interface file (\c .swiftinterface). - static ModuleDependencyInfo - forSwiftInterfaceModule(const std::string &moduleOutputPath, - const std::string &swiftInterfaceFile, - ArrayRef compiledCandidates, - ArrayRef buildCommands, - ArrayRef extraPCMArgs, - StringRef contextHash, bool isFramework, - const std::string &CASFileSystemRootID, - const std::string &moduleCacheKey) { + static ModuleDependencyInfo forSwiftInterfaceModule( + StringRef moduleOutputPath, StringRef swiftInterfaceFile, + ArrayRef compiledCandidates, ArrayRef buildCommands, + ArrayRef linkLibraries, ArrayRef extraPCMArgs, + StringRef contextHash, bool isFramework, bool isStatic, + StringRef CASFileSystemRootID, StringRef moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( moduleOutputPath, swiftInterfaceFile, compiledCandidates, - buildCommands, extraPCMArgs, contextHash, isFramework, - CASFileSystemRootID, moduleCacheKey)); + buildCommands, linkLibraries, extraPCMArgs, contextHash, + isFramework, isStatic, CASFileSystemRootID, moduleCacheKey)); } /// Describe the module dependencies for a serialized or parsed Swift module. static ModuleDependencyInfo forSwiftBinaryModule( - const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath, - const std::vector &moduleImports, - const std::vector &optionalModuleImports, - const std::string &headerImport, - bool isFramework, const std::string &moduleCacheKey) { + StringRef compiledModulePath, StringRef moduleDocPath, + StringRef sourceInfoPath, + ArrayRef moduleImports, + ArrayRef optionalModuleImports, + ArrayRef linkLibraries, StringRef headerImport, + bool isFramework, bool isStatic, StringRef moduleCacheKey) { return ModuleDependencyInfo( std::make_unique( - compiledModulePath, moduleDocPath, sourceInfoPath, - moduleImports, optionalModuleImports, - headerImport, isFramework, moduleCacheKey)); + compiledModulePath, moduleDocPath, sourceInfoPath, moduleImports, + optionalModuleImports, linkLibraries, headerImport, isFramework, + isStatic, moduleCacheKey)); } /// Describe the main Swift module. @@ -583,29 +590,26 @@ class ModuleDependencyInfo { /// Describe the module dependencies for a Clang module that can be /// built from a module map and headers. static ModuleDependencyInfo forClangModule( - const std::string &pcmOutputPath, const std::string &mappedPCMPath, - const std::string &moduleMapFile, const std::string &contextHash, - const std::vector &nonPathCommandLine, - const std::vector &fileDependencies, - const std::vector &capturedPCMArgs, - const std::string &CASFileSystemRootID, - const std::string &clangIncludeTreeRoot, - const std::string &moduleCacheKey, - bool IsSystem) { + StringRef pcmOutputPath, StringRef mappedPCMPath, StringRef moduleMapFile, + StringRef contextHash, ArrayRef nonPathCommandLine, + ArrayRef fileDependencies, + ArrayRef capturedPCMArgs, + ArrayRef linkLibraries, StringRef CASFileSystemRootID, + StringRef clangIncludeTreeRoot, StringRef moduleCacheKey, bool IsSystem) { return ModuleDependencyInfo(std::make_unique( pcmOutputPath, mappedPCMPath, moduleMapFile, contextHash, - nonPathCommandLine, fileDependencies, capturedPCMArgs, + nonPathCommandLine, fileDependencies, capturedPCMArgs, linkLibraries, CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey, IsSystem)); } /// Describe a placeholder dependency swift module. - static ModuleDependencyInfo forPlaceholderSwiftModuleStub( - const std::string &compiledModulePath, - const std::string &moduleDocPath, - const std::string &sourceInfoPath) { + static ModuleDependencyInfo + forPlaceholderSwiftModuleStub(StringRef compiledModulePath, + StringRef moduleDocPath, + StringRef sourceInfoPath) { return ModuleDependencyInfo( std::make_unique( - compiledModulePath, moduleDocPath, sourceInfoPath)); + compiledModulePath, moduleDocPath, sourceInfoPath)); } /// Retrieve the module-level imports. @@ -634,22 +638,43 @@ class ModuleDependencyInfo { } /// Resolve a dependency's set of `imports` with qualified Module IDs - void resolveDirectDependencies(const ArrayRef dependencyIDs) { + void + resolveDirectDependencies(const ArrayRef dependencyIDs) { assert(!storage->resolved && "Resolving an already-resolved dependency"); storage->resolved = true; - storage->resolvedDirectModuleDependencies.assign(dependencyIDs.begin(), dependencyIDs.end()); + storage->resolvedDirectModuleDependencies.assign(dependencyIDs.begin(), + dependencyIDs.end()); } /// Set this module's set of Swift Overlay dependencies - void setOverlayDependencies(const ArrayRef dependencyIDs) { + void + setOverlayDependencies(const ArrayRef dependencyIDs) { assert(isSwiftModule()); - storage->swiftOverlayDependencies.assign(dependencyIDs.begin(), dependencyIDs.end()); + storage->swiftOverlayDependencies.assign(dependencyIDs.begin(), + dependencyIDs.end()); } const ArrayRef getSwiftOverlayDependencies() const { return storage->swiftOverlayDependencies; } + const ArrayRef getLinkLibraries() const { + return storage->linkLibraries; + } + + void + setLinkLibraries(const ArrayRef linkLibraries) { + storage->linkLibraries.assign(linkLibraries.begin(), linkLibraries.end()); + } + + bool isStaticLibrary() const { + if (auto *detail = getAsSwiftInterfaceModule()) + return detail->isStatic; + else if (auto *detail = getAsSwiftBinaryModule()) + return detail->isStatic; + return false; + } + const ArrayRef getHeaderInputSourceFiles() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->textualModuleDetails.bridgingSourceFiles; @@ -725,19 +750,11 @@ class ModuleDependencyInfo { llvm_unreachable("Unexpected type"); } - bool isResolved() const { - return storage->resolved; - } - void setIsResolved(bool isResolved) { - storage->resolved = isResolved; - } + bool isResolved() const { return storage->resolved; } + void setIsResolved(bool isResolved) { storage->resolved = isResolved; } - bool isFinalized() const { - return storage->finalized; - } - void setIsFinalized(bool isFinalized) { - storage->finalized = isFinalized; - } + bool isFinalized() const { return storage->finalized; } + void setIsFinalized(bool isFinalized) { storage->finalized = isFinalized; } /// For a Source dependency, register a `Testable` import void addTestableImport(ImportPath::Module module); @@ -746,10 +763,12 @@ class ModuleDependencyInfo { /// of this module. Can only return `true` for Swift source modules. bool isTestableImport(StringRef moduleName) const; - /// Whether the dependencies are for a Swift module: either Textual, Source, Binary, or Placeholder. + /// Whether the dependencies are for a Swift module: either Textual, Source, + /// Binary, or Placeholder. bool isSwiftModule() const; - /// Whether the dependencies are for a textual interface Swift module or a Source Swift module. + /// Whether the dependencies are for a textual interface Swift module or a + /// Source Swift module. bool isTextualSwiftModule() const; /// Whether the dependencies are for a textual Swift module. @@ -767,12 +786,11 @@ class ModuleDependencyInfo { /// Whether the dependencies are for a Clang module. bool isClangModule() const; - ModuleDependencyKind getKind() const { - return storage->dependencyKind; - } + ModuleDependencyKind getKind() const { return storage->dependencyKind; } /// Retrieve the dependencies for a Swift textual-interface module. - const SwiftInterfaceModuleDependenciesStorage *getAsSwiftInterfaceModule() const; + const SwiftInterfaceModuleDependenciesStorage * + getAsSwiftInterfaceModule() const; /// Retrieve the dependencies for a Swift module. const SwiftSourceModuleDependenciesStorage *getAsSwiftSourceModule() const; @@ -785,11 +803,12 @@ class ModuleDependencyInfo { /// Retrieve the dependencies for a placeholder dependency module stub. const SwiftPlaceholderModuleDependencyStorage * - getAsPlaceholderDependencyModule() const; + getAsPlaceholderDependencyModule() const; /// Add a dependency on the given module, if it was not already in the set. - void addOptionalModuleImport(StringRef module, - llvm::StringSet<> *alreadyAddedModules = nullptr); + void + addOptionalModuleImport(StringRef module, + llvm::StringSet<> *alreadyAddedModules = nullptr); /// Add all of the module imports in the given source /// file to the set of module imports. @@ -852,11 +871,11 @@ class ModuleDependencyInfo { std::vector> &overlayFiles) const; }; -using ModuleDependencyVector = llvm::SmallVector, 1>; +using ModuleDependencyVector = + llvm::SmallVector, 1>; using ModuleNameToDependencyMap = llvm::StringMap; using ModuleDependenciesKindMap = - std::unordered_map; using ModuleDependenciesKindRefMap = std::unordered_map getCachingFS() const { return CacheFS; } + llvm::IntrusiveRefCntPtr + getCachingFS() const { + return CacheFS; + } llvm::cas::CachingOnDiskFileSystem &getSharedCachingFS() const { assert(CacheFS && "Expect CachingOnDiskFileSystem"); @@ -988,6 +1011,7 @@ class SwiftDependencyScanningService { /// Setup caching service. bool setupCachingDependencyScanningService(CompilerInstance &Instance); + private: /// Enforce clients not being allowed to query this cache directly, it must be /// wrapped in an instance of `ModuleDependenciesCache`. @@ -1024,16 +1048,18 @@ class SwiftDependencyScanningService { StringRef scanContextHash) const; /// Record dependencies for the given module. - const ModuleDependencyInfo *recordDependency(StringRef moduleName, - ModuleDependencyInfo dependencies, - StringRef scanContextHash); + const ModuleDependencyInfo * + recordDependency(StringRef moduleName, ModuleDependencyInfo dependencies, + StringRef scanContextHash); /// Update stored dependencies for the given module. - const ModuleDependencyInfo *updateDependency(ModuleDependencyID moduleID, - ModuleDependencyInfo dependencies, - StringRef scanContextHash); + const ModuleDependencyInfo * + updateDependency(ModuleDependencyID moduleID, + ModuleDependencyInfo dependencies, + StringRef scanContextHash); - /// Reference the list of all module dependency infos for a given scanning context + /// Reference the list of all module dependency infos for a given scanning + /// context const std::vector & getAllModules(StringRef scanningContextHash) const { auto contextSpecificCache = @@ -1054,7 +1080,8 @@ class ModuleDependenciesCache { /// References to data in the `globalScanningService` for module dependencies ModuleDependenciesKindRefMap ModuleDependenciesMap; /// Set containing all of the Clang modules that have already been seen. - llvm::DenseSet alreadySeenClangModules; + llvm::DenseSet + alreadySeenClangModules; /// Name of the module under scan std::string mainScanModuleName; /// The context hash of the current scanning invocation @@ -1092,15 +1119,14 @@ class ModuleDependenciesCache { const SwiftDependencyScanningService &getScanService() const { return globalScanningService; } - const llvm::DenseSet& getAlreadySeenClangModules() const { + const llvm::DenseSet & + getAlreadySeenClangModules() const { return alreadySeenClangModules; } void addSeenClangModule(clang::tooling::dependencies::ModuleID newModule) { alreadySeenClangModules.insert(newModule); } - std::string getModuleOutputPath() const { - return moduleOutputPath; - } + std::string getModuleOutputPath() const { return moduleOutputPath; } /// Query all dependencies, direct and Swift overlay. std::vector @@ -1152,19 +1178,18 @@ class ModuleDependenciesCache { /// Resolve a dependency module's set of imports /// to a kind-qualified set of module IDs. - void resolveDependencyImports(ModuleDependencyID moduleID, - const ArrayRef dependencyIDs); + void + resolveDependencyImports(ModuleDependencyID moduleID, + const ArrayRef dependencyIDs); /// Resolve a dependency module's set of Swift module dependencies /// that are Swift overlays of Clang module dependencies. - void setSwiftOverlayDependencies(ModuleDependencyID moduleID, - const ArrayRef dependencyIDs); - - StringRef getMainModuleName() const { - return mainScanModuleName; - } -}; + void + setSwiftOverlayDependencies(ModuleDependencyID moduleID, + const ArrayRef dependencyIDs); + StringRef getMainModuleName() const { return mainScanModuleName; } +}; } // namespace swift namespace std { diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 24d2285fd0358..214745bb0b259 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -184,6 +184,10 @@ class alignas(1 << TypeReprAlignInBits) TypeRepr /// opaque return type reprs. bool hasOpaque(); + /// Returns a Boolean value indicating whether this written type is + /// parenthesized, that is, matches the following grammar: `'(' type ')'`. + bool isParenType() const; + /// Retrieve the type repr without any parentheses around it. /// /// The use of this function must be restricted to contexts where diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 284ae437c7f3e..9535de9ab727d 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -399,6 +399,8 @@ EXPERIMENTAL_FEATURE(Sensitive, true) // Enable the stdlib @DebugDescription macro. EXPERIMENTAL_FEATURE(DebugDescriptionMacro, true) +EXPERIMENTAL_FEATURE(ReinitializeConsumeInMultiBlockDefer, false) + #undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE #undef EXPERIMENTAL_FEATURE #undef UPCOMING_FEATURE diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index a00dff1d6749a..64681e469dcfb 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -60,10 +60,19 @@ struct swiftscan_dependency_info_s { */ swiftscan_string_set_t *direct_dependencies; + /// The list of link libraries for this module. + swiftscan_link_library_set_t *link_libraries; + /// Specific details of a particular kind of module. swiftscan_module_details_t details; }; +struct swiftscan_link_library_info_s { + swiftscan_string_ref_t name; + bool isFramework; + bool forceLoad; +}; + /// Swift modules to be built from a module interface, may have a bridging /// header. typedef struct { @@ -103,6 +112,9 @@ typedef struct { /// A flag to indicate whether or not this module is a framework. bool is_framework; + /// A flag that indicates this dependency is associated with a static archive + bool is_static; + /// The CASID for CASFileSystemRoot swiftscan_string_ref_t cas_fs_root_id; @@ -140,6 +152,9 @@ typedef struct { /// A flag to indicate whether or not this module is a framework. bool is_framework; + /// A flag that indicates this dependency is associated with a static archive + bool is_static; + /// ModuleCacheKey swiftscan_string_ref_t module_cache_key; } swiftscan_swift_binary_details_t; diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index f5895cf28eeb5..f520cca659fbc 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -55,6 +55,8 @@ using ContextHashIDField = IdentifierIDField; using IsFrameworkField = BCFixed<1>; /// A bit that indicates whether or not a module is a system module using IsSystemField = BCFixed<1>; +/// A bit that indicates whether or not a module is that of a static archive +using IsStaticField = BCFixed<1>; /// Arrays of various identifiers, distinguished for readability using IdentifierIDArryField = llvm::BCArray; @@ -140,10 +142,11 @@ using SwiftInterfaceModuleDetailsLayout = FlagIDArrayIDField, // extraPCMArgs ContextHashIDField, // contextHash IsFrameworkField, // isFramework + IsStaticField, // isStatic FileIDField, // bridgingHeaderFile FileIDArrayIDField, // sourceFiles FileIDArrayIDField, // bridgingSourceFiles - IdentifierIDField, // bridgingModuleDependencies + IdentifierIDField, // bridgingModuleDependencies DependencyIDArrayIDField, // swiftOverlayDependencies IdentifierIDField, // CASFileSystemRootID IdentifierIDField, // bridgingHeaderIncludeTree @@ -174,6 +177,7 @@ using SwiftBinaryModuleDetailsLayout = IdentifierIDField, // headerModuleDependencies FileIDArrayIDField, // headerSourceFiles IsFrameworkField, // isFramework + IsStaticField, // isStatic IdentifierIDField // moduleCacheKey >; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index a50cf5cd7c6ad..1cbcc3e8a4341 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -557,6 +557,10 @@ def disable_autolink_frameworks : Flag<["-"],"disable-autolink-frameworks">, def disable_all_autolinking : Flag<["-"],"disable-all-autolinking">, HelpText<"Disable all Swift autolink directives">; +def disable_force_load_symbols : Flag<["-"],"disable-force-load-symbols">, + Flags<[FrontendOption, HelpHidden]>, + HelpText<"Disable generation of all Swift _FORCE_LOAD symbols">; + def disable_diagnostic_passes : Flag<["-"], "disable-diagnostic-passes">, HelpText<"Don't run diagnostic passes">; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index e6d38cb396e41..b310870c49387 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1376,6 +1376,10 @@ def explain_module_dependency : Separate<["-"], "explain-module-dependency">, Flags<[NewDriverOnlyOption]>, HelpText<"Emit remark/notes describing why compilation may depend on a module with a given name.">; +def explicit_auto_linking : Flag<["-"], "explicit-auto-linking">, + Flags<[NewDriverOnlyOption]>, + HelpText<"Instead of linker-load directives, have the driver specify all link dependencies on the linker invocation. Requires '-explicit-module-build'.">; + def min_inlining_target_version : Separate<["-"], "target-min-inlining-version">, Flags<[FrontendOption, ModuleInterfaceOption]>, HelpText<"Require inlinable code with no '@available' attribute to back-deploy " diff --git a/include/swift/SIL/OSSALifetimeCompletion.h b/include/swift/SIL/OSSALifetimeCompletion.h index 2320c46b6b9e5..ba8d9e05c830c 100644 --- a/include/swift/SIL/OSSALifetimeCompletion.h +++ b/include/swift/SIL/OSSALifetimeCompletion.h @@ -120,10 +120,17 @@ class OSSALifetimeCompletion { DoNotAllowLeaks = false, }; - static void visitUnreachableLifetimeEnds( + enum class LifetimeEnd : uint8_t { + /// The lifetime ends at the boundary. + Boundary, + /// The lifetime "ends" in a loop. + Loop, + }; + + static void visitAvailabilityBoundary( SILValue value, AllowLeaks_t allowLeaks, const SSAPrunedLiveness &liveness, - llvm::function_ref visit); + llvm::function_ref visit); protected: bool analyzeAndUpdateLifetime(SILValue value, Boundary boundary); diff --git a/include/swift/SIL/OwnershipLiveness.h b/include/swift/SIL/OwnershipLiveness.h index cf04f095e3d64..0f78fa96f8238 100644 --- a/include/swift/SIL/OwnershipLiveness.h +++ b/include/swift/SIL/OwnershipLiveness.h @@ -206,9 +206,19 @@ class LinearLiveness : public OSSALiveness { friend LinearLivenessVisitor; public: - LinearLiveness(SILValue def); + /// Whether extend_lifetime instructions should be added to the boundary. + /// Used to verify extend_lifetime instructions. + enum IncludeExtensions_t { + DoNotIncludeExtensions = false, + IncludeExtensions = true, + }; + LinearLiveness(SILValue def, + IncludeExtensions_t includeExtensions = IncludeExtensions); void compute(); + +private: + const IncludeExtensions_t includeExtensions; }; // Internal implementation diff --git a/include/swift/SIL/OwnershipUseVisitor.h b/include/swift/SIL/OwnershipUseVisitor.h index c334ac7420113..9fdca1f5bebe0 100644 --- a/include/swift/SIL/OwnershipUseVisitor.h +++ b/include/swift/SIL/OwnershipUseVisitor.h @@ -213,6 +213,13 @@ bool OwnershipUseVisitor::visitLifetimeEndingUses(SILValue ssaDef) { template bool OwnershipUseVisitor::visitConsumes(SILValue ssaDef) { for (Operand *use : ssaDef->getUses()) { + // extend_lifetime instructions are non-consuming but need to be visited + // because together with consuming uses they enclose all users of the value. + if (isa(use->getUser())) { + if (!handleUsePoint(use, UseLifetimeConstraint::NonLifetimeEnding)) + return false; + continue; + } if (use->isConsuming()) { if (PhiOperand(use) && !asImpl().handleOwnedPhi(use)) return false; @@ -245,6 +252,9 @@ bool OwnershipUseVisitor::visitOuterBorrowScopeEnd(Operand *borrowEnd) { return handleUsePoint(borrowEnd, UseLifetimeConstraint::LifetimeEnding); + case OperandOwnership::InstantaneousUse: + assert(isa(borrowEnd->getUser())); + return handleUsePoint(borrowEnd, UseLifetimeConstraint::NonLifetimeEnding); default: llvm_unreachable("expected borrow scope end"); } diff --git a/include/swift/SIL/PrunedLiveness.h b/include/swift/SIL/PrunedLiveness.h index bd72e9e3f1511..501886df8a0ba 100644 --- a/include/swift/SIL/PrunedLiveness.h +++ b/include/swift/SIL/PrunedLiveness.h @@ -391,22 +391,20 @@ class PrunedLiveness { Ending, // The instruction doesn't use the value. NonUse, - }; - Value value; + } value; LifetimeEnding(Value value) : value(value) {} - explicit LifetimeEnding(bool lifetimeEnding) - : value(lifetimeEnding ? Value::Ending : Value::NonEnding) {} operator Value() const { return value; } + + static LifetimeEnding forUse(bool lifetimeEnding) { + return lifetimeEnding ? Value::Ending : Value::NonEnding; + } + bool isEnding() const { return value == Value::Ending; } + LifetimeEnding meet(LifetimeEnding const other) const { return value < other.value ? *this : other; } void meetInPlace(LifetimeEnding const other) { *this = meet(other); } - bool isEnding() const { return value == Value::Ending; } - - static LifetimeEnding NonUse() { return {Value::NonUse}; }; - static LifetimeEnding Ending() { return {Value::Ending}; }; - static LifetimeEnding NonEnding() { return {Value::NonEnding}; }; }; protected: @@ -467,8 +465,8 @@ class PrunedLiveness { auto useIter = users.find(user); if (useIter == users.end()) return NonUser; - return useIter->second == LifetimeEnding::Ending() ? LifetimeEndingUse - : NonLifetimeEndingUse; + return useIter->second.isEnding() ? LifetimeEndingUse + : NonLifetimeEndingUse; } using ConstUserRange = diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 9df56472477ec..db10cffcf0d83 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -2292,6 +2292,11 @@ class SILBuilder { EndLifetimeInst(getSILDebugLocation(Loc), Operand)); } + ExtendLifetimeInst *createExtendLifetime(SILLocation Loc, SILValue Operand) { + return insert(new (getModule()) + ExtendLifetimeInst(getSILDebugLocation(Loc), Operand)); + } + UncheckedOwnershipConversionInst * createUncheckedOwnershipConversion(SILLocation Loc, SILValue Operand, ValueOwnershipKind Kind) { diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 9b16e59580b12..3338b82a322de 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -3019,6 +3019,18 @@ void SILCloner::visitEndLifetimeInst(EndLifetimeInst *Inst) { getOpValue(Inst->getOperand()))); } +template +void SILCloner::visitExtendLifetimeInst(ExtendLifetimeInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + + if (!getBuilder().hasOwnership()) + return; + + recordClonedInstruction( + Inst, getBuilder().createExtendLifetime(getOpLocation(Inst->getLoc()), + getOpValue(Inst->getOperand()))); +} + template void SILCloner::visitUncheckedOwnershipConversionInst( UncheckedOwnershipConversionInst *Inst) { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 29de2d3c1b89b..4d382b579de2d 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -8535,6 +8535,16 @@ class EndLifetimeInst : UnaryInstructionBase(DebugLoc, Operand) {} }; +/// Mark the end of the linear live range of a value without destroying it. +class ExtendLifetimeInst + : public UnaryInstructionBase { + friend SILBuilder; + + ExtendLifetimeInst(SILDebugLocation loc, SILValue operand) + : UnaryInstructionBase(loc, operand) {} +}; + /// An unsafe conversion in between ownership kinds. /// /// This is used today in destructors where due to Objective-C legacy diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 24b1f18b4b69e..44dd495b2bf28 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -864,6 +864,8 @@ NON_VALUE_INST(DestroyAddrInst, destroy_addr, SILInstruction, MayHaveSideEffects, MayRelease) NON_VALUE_INST(EndLifetimeInst, end_lifetime, SILInstruction, MayHaveSideEffects, MayRelease) +NON_VALUE_INST(ExtendLifetimeInst, extend_lifetime, + SILInstruction, None, DoesNotRelease) NON_VALUE_INST(InjectEnumAddrInst, inject_enum_addr, SILInstruction, MayWrite, DoesNotRelease) NON_VALUE_INST(DeinitExistentialAddrInst, deinit_existential_addr, diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 54581399c1455..45dc07602c1ac 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -6582,6 +6582,13 @@ TypeVariableType *TypeVariableType::getNew(const ASTContext &C, unsigned ID, /// underlying forced downcast expression. ForcedCheckedCastExpr *findForcedDowncast(ASTContext &ctx, Expr *expr); +/// Assuming the expression appears in a consuming context, +/// if it does not already have an explicit `consume`, +/// can I add `consume` around this expression? +/// +/// \param module represents the module in which the expr appears +bool canAddExplicitConsume(ModuleDecl *module, Expr *expr); + // Count the number of overload sets present // in the expression and all of the children. class OverloadSetCounter : public ASTWalker { diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index cffba1fb45d3a..2070b8281f7fa 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -1532,7 +1532,8 @@ static ValueDecl *getCreateTask(ASTContext &ctx, Identifier id) { _label("flags", _swiftInt), _label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)), _label("taskGroup", _defaulted(_optional(_rawPointer), _nil)), - _label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), + /* deprecated */_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), + _label("initialTaskExecutorConsuming", _defaulted(_consuming(_optional(_taskExecutor)), _nil)), _label("operation", _function(_async(_throws(_sendable(_thick))), _typeparam(0), _parameters()))), _tuple(_nativeObject, _rawPointer)); @@ -1545,12 +1546,14 @@ static ValueDecl *getCreateDiscardingTask(ASTContext &ctx, Identifier id) { _label("flags", _swiftInt), _label("initialSerialExecutor", _defaulted(_optional(_executor), _nil)), _label("taskGroup", _defaulted(_optional(_rawPointer), _nil)), - _label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), + /* deprecated */_label("initialTaskExecutor", _defaulted(_optional(_executor), _nil)), + _label("initialTaskExecutorConsuming", _defaulted(_consuming(_optional(_taskExecutor)), _nil)), _label("operation", _function(_async(_throws(_sendable(_thick))), _void, _parameters()))), _tuple(_nativeObject, _rawPointer)); } +// Legacy entry point, prefer `createAsyncTask` static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id, bool inGroup, bool withTaskExecutor, bool isDiscarding) { @@ -1560,6 +1563,7 @@ static ValueDecl *getCreateAsyncTask(ASTContext &ctx, Identifier id, if (inGroup) { builder.addParameter(makeConcrete(ctx.TheRawPointerType)); // group } + if (withTaskExecutor) { builder.addParameter(makeConcrete(ctx.TheExecutorType)); // executor } @@ -2976,7 +2980,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::FixLifetime: return getFixLifetimeOperation(Context, Id); - + case BuiltinValueKind::CanBeObjCClass: return getCanBeObjCClassOperation(Context, Id); diff --git a/lib/AST/ConformanceLookupTable.cpp b/lib/AST/ConformanceLookupTable.cpp index 6c2606ed07b7e..03051d88d8bad 100644 --- a/lib/AST/ConformanceLookupTable.cpp +++ b/lib/AST/ConformanceLookupTable.cpp @@ -306,9 +306,9 @@ void ConformanceLookupTable::updateLookupTable(NominalTypeDecl *nominal, if (!proto) continue; auto kp = proto->getKnownProtocolKind(); - assert(!found.isSuppressed || - kp.has_value() && - "suppressed conformance for non-known protocol!?"); + assert(!found.isSuppressed || + kp.has_value() && + "suppressed conformance for non-known protocol!?"); if (!found.isSuppressed) { addProtocol(proto, found.Loc, source.withUncheckedLoc(found.uncheckedLoc) diff --git a/lib/AST/FeatureSet.cpp b/lib/AST/FeatureSet.cpp index 6cbb9e653b80a..63edcfb0f1166 100644 --- a/lib/AST/FeatureSet.cpp +++ b/lib/AST/FeatureSet.cpp @@ -778,6 +778,7 @@ static bool usesFeatureSensitive(Decl *decl) { } UNINTERESTING_FEATURE(DebugDescriptionMacro) +UNINTERESTING_FEATURE(ReinitializeConsumeInMultiBlockDefer) // ---------------------------------------------------------------------------- // MARK: - FeatureSet diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index 618876627fb7d..17dbb88505d3f 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -483,7 +483,7 @@ SwiftDependencyScanningService::SwiftDependencyScanningService() { } bool -swift::dependencies::checkImportNotTautological(const ImportPath::Module modulePath, +swift::dependencies::checkImportNotTautological(const ImportPath::Module modulePath, const SourceLoc importLoc, const SourceFile &SF, bool isExported) { @@ -509,6 +509,85 @@ swift::dependencies::checkImportNotTautological(const ImportPath::Module moduleP return false; } +void +swift::dependencies::registerCxxInteropLibraries( + const llvm::Triple &Target, + StringRef mainModuleName, + bool hasStaticCxx, bool hasStaticCxxStdlib, + std::function RegistrationCallback) { + if (Target.isOSDarwin()) + RegistrationCallback(LinkLibrary("c++", LibraryKind::Library)); + else if (Target.isOSLinux()) + RegistrationCallback(LinkLibrary("stdc++", LibraryKind::Library)); + + // Do not try to link Cxx with itself. + if (mainModuleName != "Cxx") { + RegistrationCallback(LinkLibrary(Target.isOSWindows() && hasStaticCxx + ? "libswiftCxx" + : "swiftCxx", + LibraryKind::Library)); + } + + // Do not try to link CxxStdlib with the C++ standard library, Cxx or + // itself. + if (llvm::none_of(llvm::ArrayRef{"Cxx", "CxxStdlib", "std"}, + [mainModuleName](StringRef Name) { + return mainModuleName == Name; + })) { + // Only link with CxxStdlib on platforms where the overlay is available. + switch (Target.getOS()) { + case llvm::Triple::Linux: + if (!Target.isAndroid()) + RegistrationCallback(LinkLibrary("swiftCxxStdlib", + LibraryKind::Library)); + break; + case llvm::Triple::Win32: { + RegistrationCallback( + LinkLibrary(hasStaticCxxStdlib ? "libswiftCxxStdlib" : "swiftCxxStdlib", + LibraryKind::Library)); + break; + } + default: + if (Target.isOSDarwin()) + RegistrationCallback(LinkLibrary("swiftCxxStdlib", + LibraryKind::Library)); + break; + } + } +} + +void +swift::dependencies::registerBackDeployLibraries( + const IRGenOptions &IRGenOpts, + std::function RegistrationCallback) { + auto addBackDeployLib = [&](llvm::VersionTuple version, + StringRef libraryName, bool forceLoad) { + std::optional compatibilityVersion; + if (libraryName == "swiftCompatibilityDynamicReplacements") { + compatibilityVersion = IRGenOpts. + AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion; + } else if (libraryName == "swiftCompatibilityConcurrency") { + compatibilityVersion = + IRGenOpts.AutolinkRuntimeCompatibilityConcurrencyLibraryVersion; + } else { + compatibilityVersion = IRGenOpts. + AutolinkRuntimeCompatibilityLibraryVersion; + } + + if (!compatibilityVersion) + return; + + if (*compatibilityVersion > version) + return; + + RegistrationCallback({libraryName, LibraryKind::Library, forceLoad}); + }; + +#define BACK_DEPLOYMENT_LIB(Version, Filter, LibraryName, ForceLoad) \ + addBackDeployLib(llvm::VersionTuple Version, LibraryName, ForceLoad); + #include "swift/Frontend/BackDeploymentLibs.def" +} + void SwiftDependencyTracker::addCommonSearchPathDeps( const SearchPathOptions &Opts) { // Add SDKSetting file. diff --git a/lib/AST/TypeRepr.cpp b/lib/AST/TypeRepr.cpp index ce7b5d915c9da..2398bec807a05 100644 --- a/lib/AST/TypeRepr.cpp +++ b/lib/AST/TypeRepr.cpp @@ -109,14 +109,18 @@ bool TypeRepr::hasOpaque() { findIf([](TypeRepr *ty) { return isa(ty); }); } +bool TypeRepr::isParenType() const { + auto *tuple = dyn_cast(this); + return tuple && tuple->isParenType(); +} + TypeRepr *TypeRepr::getWithoutParens() const { - auto *repr = const_cast(this); - while (auto *tupleRepr = dyn_cast(repr)) { - if (!tupleRepr->isParenType()) - break; - repr = tupleRepr->getElementType(0); + auto *result = this; + while (result->isParenType()) { + result = cast(result)->getElementType(0); } - return repr; + + return const_cast(result); } bool TypeRepr::isSimpleUnqualifiedIdentifier(Identifier identifier) const { diff --git a/lib/ClangImporter/ClangIncludePaths.cpp b/lib/ClangImporter/ClangIncludePaths.cpp index f5183091bde37..f76fd229c549c 100644 --- a/lib/ClangImporter/ClangIncludePaths.cpp +++ b/lib/ClangImporter/ClangIncludePaths.cpp @@ -180,7 +180,7 @@ createClangArgs(const ASTContext &ctx, clang::driver::Driver &clangDriver) { static SmallVector, 2> getLibcFileMapping(ASTContext &ctx, StringRef modulemapFileName, - std::optional maybeHeaderFileName, + std::optional> maybeHeaderFileNames, const llvm::IntrusiveRefCntPtr &vfs) { const llvm::Triple &triple = ctx.LangOpts.Target; @@ -220,18 +220,20 @@ getLibcFileMapping(ASTContext &ctx, StringRef modulemapFileName, SmallVector, 2> vfsMappings{ {std::string(injectedModuleMapPath), std::string(actualModuleMapPath)}}; - if (maybeHeaderFileName) { - // TODO: remove the SwiftGlibc.h header and reference all Glibc headers - // directly from the modulemap. - Path actualHeaderPath = actualModuleMapPath; - llvm::sys::path::remove_filename(actualHeaderPath); - llvm::sys::path::append(actualHeaderPath, maybeHeaderFileName.value()); + if (maybeHeaderFileNames) { + for (const auto &filename : *maybeHeaderFileNames) { + // TODO: remove the SwiftGlibc.h header and reference all Glibc headers + // directly from the modulemap. + Path actualHeaderPath = actualModuleMapPath; + llvm::sys::path::remove_filename(actualHeaderPath); + llvm::sys::path::append(actualHeaderPath, filename); - Path injectedHeaderPath(libcDir); - llvm::sys::path::append(injectedHeaderPath, maybeHeaderFileName.value()); + Path injectedHeaderPath(libcDir); + llvm::sys::path::append(injectedHeaderPath, filename); - vfsMappings.push_back( - {std::string(injectedHeaderPath), std::string(actualHeaderPath)}); + vfsMappings.push_back( + {std::string(injectedHeaderPath), std::string(actualHeaderPath)}); + } } return vfsMappings; @@ -552,9 +554,14 @@ ClangInvocationFileMapping swift::getClangInvocationFileMapping( } else if (triple.isMusl()) { libcFileMapping = getLibcFileMapping(ctx, "musl.modulemap", StringRef("SwiftMusl.h"), vfs); + } else if (triple.isAndroid()) { + // Android uses the android-specific module map that overlays the NDK. + StringRef headerFiles[] = {"SwiftAndroidNDK.h", "SwiftBionic.h"}; + libcFileMapping = + getLibcFileMapping(ctx, "android.modulemap", headerFiles, vfs); } else if (triple.isOSGlibc() || triple.isOSOpenBSD() || - triple.isOSFreeBSD() || triple.isAndroid()) { - // Android/BSD/Linux Mappings + triple.isOSFreeBSD()) { + // BSD/Linux Mappings libcFileMapping = getLibcFileMapping(ctx, "glibc.modulemap", StringRef("SwiftGlibc.h"), vfs); diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 06f12575bee2f..cf054231728d6 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -285,12 +285,19 @@ ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies( if (Mapper) Mapper->mapInPlace(mappedPCMPath); + std::vector LinkLibraries; + for (const auto &ll : clangModuleDep.LinkLibraries) + LinkLibraries.push_back( + {ll.Library, + ll.IsFramework ? LibraryKind::Framework : LibraryKind::Library}); + // Module-level dependencies. llvm::StringSet<> alreadyAddedModules; auto dependencies = ModuleDependencyInfo::forClangModule( pcmPath, mappedPCMPath, clangModuleDep.ClangModuleMapFile, clangModuleDep.ID.ContextHash, swiftArgs, fileDeps, capturedPCMArgs, - RootID, IncludeTree, /*module-cache-key*/ "", clangModuleDep.IsSystem); + LinkLibraries, RootID, IncludeTree, /*module-cache-key*/ "", + clangModuleDep.IsSystem); for (const auto &moduleName : clangModuleDep.ClangModuleDeps) { dependencies.addModuleImport(moduleName.ModuleName, &alreadyAddedModules); // It is safe to assume that all dependencies of a Clang module are Clang modules. diff --git a/lib/DependencyScan/DependencyScanJSON.cpp b/lib/DependencyScan/DependencyScanJSON.cpp index 133b98b7e7329..7d89271a6051c 100644 --- a/lib/DependencyScan/DependencyScanJSON.cpp +++ b/lib/DependencyScan/DependencyScanJSON.cpp @@ -202,6 +202,46 @@ static void writeDependencies(llvm::raw_ostream &out, out << "\n"; } +void writeLinkLibraries(llvm::raw_ostream &out, + const swiftscan_link_library_set_t *link_libraries, + unsigned indentLevel, bool trailingComma) { + out.indent(indentLevel * 2); + out << "\"linkLibraries\": "; + out << "[\n"; + + for (size_t i = 0; i < link_libraries->count; ++i) { + const auto &llInfo = *link_libraries->link_libraries[i]; + out.indent((indentLevel + 1) * 2); + out << "{\n"; + auto entryIndentLevel = ((indentLevel + 2) * 2); + out.indent(entryIndentLevel); + out << "\"linkName\": "; + writeJSONValue(out, llInfo.name, indentLevel); + out << ",\n"; + out.indent(entryIndentLevel); + out << "\"isFramework\": "; + writeJSONValue(out, llInfo.isFramework, entryIndentLevel); + out << ",\n"; + out.indent(entryIndentLevel); + out << "\"shouldForceLoad\": "; + writeJSONValue(out, llInfo.forceLoad, entryIndentLevel); + out << "\n"; + out.indent((indentLevel + 1) * 2); + out << "}"; + if (i != link_libraries->count - 1) { + out << ","; + } + out << "\n"; + } + + out.indent(indentLevel * 2); + out << "]"; + + if (trailingComma) + out << ","; + out << "\n"; +} + static const swiftscan_swift_textual_details_t * getAsTextualDependencyModule(swiftscan_module_details_t details) { if (details->kind == SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL) @@ -295,10 +335,13 @@ void writeJSON(llvm::raw_ostream &out, } // Direct dependencies. - if (swiftTextualDeps || swiftBinaryDeps || clangDeps) + if (swiftTextualDeps || swiftBinaryDeps || clangDeps) { writeDependencies(out, directDependencies, "directDependencies", 3, /*trailingComma=*/true); + writeLinkLibraries(out, moduleInfo.link_libraries, + 3, /*trailingComma=*/true); + } // Swift and Clang-specific details. out.indent(3 * 2); out << "\"details\": {\n"; diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index 3783957c3099c..6eeec2b04cee1 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -251,14 +251,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi cache.configureForContextHash(getContextHash()); unsigned outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, buildCommandLineArrayID, - extraPCMArgsArrayID, contextHashID, isFramework, bridgingHeaderFileID, + extraPCMArgsArrayID, contextHashID, isFramework, isStatic, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID; SwiftInterfaceModuleDetailsLayout::readRecord( Scratch, outputPathFileID, interfaceFileID, compiledModuleCandidatesArrayID, buildCommandLineArrayID, - extraPCMArgsArrayID, contextHashID, isFramework, bridgingHeaderFileID, + extraPCMArgsArrayID, contextHashID, isFramework, isStatic, bridgingHeaderFileID, sourceFilesArrayID, bridgingSourceFilesArrayID, bridgingModuleDependenciesArrayID, overlayDependencyIDArrayID, CASFileSystemRootID, bridgingHeaderIncludeTreeID, moduleCacheKeyID); @@ -293,6 +293,9 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi std::vector extraPCMRefs; for (auto &arg : *extraPCMArgs) extraPCMRefs.push_back(arg); + std::vector compiledCandidatesRefs; + for (auto &cc : compiledCandidatesRefs) + compiledCandidatesRefs.push_back(cc); auto rootFileSystemID = getIdentifier(CASFileSystemRootID); if (!rootFileSystemID) @@ -301,11 +304,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi if (!moduleCacheKeyID) llvm::report_fatal_error("Bad moduleCacheKey"); + // TODO: LinkLibraries // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftInterfaceModule( outputModulePath.value(), optionalSwiftInterfaceFile.value(), - *compiledModuleCandidates, buildCommandRefs, extraPCMRefs, - *contextHash, isFramework, *rootFileSystemID, *moduleCacheKey); + compiledCandidatesRefs, buildCommandRefs, {}, extraPCMRefs, + *contextHash, isFramework, isStatic, *rootFileSystemID, *moduleCacheKey); // Add imports of this module for (const auto &moduleName : currentModuleImports) @@ -484,13 +488,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, overlayDependencyIDArrayID, headerImportID, headerModuleDependenciesArrayID, - headerImportsSourceFilesArrayID, isFramework, + headerImportsSourceFilesArrayID, isFramework, isStatic, moduleCacheKeyID; SwiftBinaryModuleDetailsLayout::readRecord( Scratch, compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID, overlayDependencyIDArrayID, headerImportID, headerModuleDependenciesArrayID, - headerImportsSourceFilesArrayID, isFramework, moduleCacheKeyID); + headerImportsSourceFilesArrayID, isFramework, isStatic, + moduleCacheKeyID); auto compiledModulePath = getIdentifier(compiledModulePathID); if (!compiledModulePath) @@ -508,11 +513,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi if (!headerImport) llvm::report_fatal_error("Bad binary direct dependencies: no header import"); + // TODO: LinkLibraries // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule( *compiledModulePath, *moduleDocPath, *moduleSourceInfoPath, - currentModuleImports, currentOptionalModuleImports, - *headerImport, isFramework, *moduleCacheKey); + currentModuleImports, currentOptionalModuleImports, {}, + *headerImport, isFramework, isStatic, *moduleCacheKey); auto headerModuleDependencies = getStringArray(headerModuleDependenciesArrayID); if (!headerModuleDependencies) @@ -619,10 +625,11 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi if (!moduleCacheKeyID) llvm::report_fatal_error("Bad moduleCacheKey"); + // TODO: LinkLibraries // Form the dependencies storage object auto moduleDep = ModuleDependencyInfo::forClangModule( *pcmOutputPath, *mappedPCMPath, *moduleMapPath, *contextHash, - *commandLineArgs, *fileDependencies, *capturedPCMArgs, + *commandLineArgs, *fileDependencies, *capturedPCMArgs, {}, *rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey, isSystem); // Add dependencies of this module @@ -984,7 +991,8 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo( ModuleIdentifierArrayKind::CompiledModuleCandidates), getArrayID(moduleID, ModuleIdentifierArrayKind::BuildCommandLine), getArrayID(moduleID, ModuleIdentifierArrayKind::ExtraPCMArgs), - getIdentifier(swiftTextDeps->contextHash), swiftTextDeps->isFramework, + getIdentifier(swiftTextDeps->contextHash), + swiftTextDeps->isFramework, swiftTextDeps->isStatic, bridgingHeaderFileId, getArrayID(moduleID, ModuleIdentifierArrayKind::SourceFiles), getArrayID(moduleID, ModuleIdentifierArrayKind::BridgingSourceFiles), @@ -1040,7 +1048,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo( getArrayID(moduleID, ModuleIdentifierArrayKind::DependencyHeaders), getArrayID(moduleID, ModuleIdentifierArrayKind::HeaderInputModuleDependencies), getArrayID(moduleID, ModuleIdentifierArrayKind::HeaderInputDependencySourceFiles), - swiftBinDeps->isFramework, + swiftBinDeps->isFramework, swiftBinDeps->isStatic, getIdentifier(swiftBinDeps->moduleCacheKey)); break; diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index d37c55d5c9ccf..667b8416f364a 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -714,6 +714,7 @@ generateFullDependencyGraph(const CompilerInstance &instance, create_set(swiftTextualDeps->textualModuleDetails.extraPCMArgs), create_clone(swiftTextualDeps->contextHash.c_str()), swiftTextualDeps->isFramework, + swiftTextualDeps->isStatic, create_clone(swiftTextualDeps->textualModuleDetails .CASFileSystemRootID.c_str()), create_clone(swiftTextualDeps->textualModuleDetails @@ -746,6 +747,7 @@ generateFullDependencyGraph(const CompilerInstance &instance, create_clone( instance.getInvocation().getModuleScanningHash().c_str()), /*isFramework*/ false, + /*isStatic*/ false, /*CASFS*/ create_clone(swiftSourceDeps->textualModuleDetails .CASFileSystemRootID.c_str()), @@ -774,6 +776,7 @@ generateFullDependencyGraph(const CompilerInstance &instance, create_set(swiftBinaryDeps->headerModuleDependencies), create_set(swiftBinaryDeps->headerSourceFiles), swiftBinaryDeps->isFramework, + swiftBinaryDeps->isStatic, create_clone(swiftBinaryDeps->moduleCacheKey.c_str())}; } else { // Clang module details @@ -804,6 +807,23 @@ generateFullDependencyGraph(const CompilerInstance &instance, bridgeDependencyIDs(directDependencies, bridgedDependencyNames); moduleInfo->direct_dependencies = create_set(bridgedDependencyNames); moduleInfo->details = getModuleDetails(); + + // Create a link libraries set for this module + auto &linkLibraries = depInfo.getLinkLibraries(); + swiftscan_link_library_set_t *linkLibrarySet = + new swiftscan_link_library_set_t; + linkLibrarySet->count = linkLibraries.size(); + linkLibrarySet->link_libraries = + new swiftscan_link_library_info_t[linkLibrarySet->count]; + for (size_t i = 0; i < linkLibraries.size(); ++i) { + const auto &ll = linkLibraries[i]; + swiftscan_link_library_info_s *llInfo = new swiftscan_link_library_info_s; + llInfo->name = create_clone(ll.getName().str().c_str()); + llInfo->isFramework = ll.getKind() == LibraryKind::Framework; + llInfo->forceLoad = ll.shouldForceLoad(); + linkLibrarySet->link_libraries[i] = llInfo; + } + moduleInfo->link_libraries = linkLibrarySet; } swiftscan_dependency_graph_t result = new swiftscan_dependency_graph_s; @@ -1406,10 +1426,46 @@ updateDependencyTracker(CompilerInstance &instance, } } +static void resolveImplicitLinkLibraries(const CompilerInstance &instance, + ModuleDependenciesCache &cache) { + auto langOpts = instance.getInvocation().getLangOptions(); + auto irGenOpts = instance.getInvocation().getIRGenOptions(); + auto mainModuleName = instance.getMainModule()->getNameStr(); + auto mainModuleID = ModuleDependencyID{mainModuleName.str(), + ModuleDependencyKind::SwiftSource}; + auto mainModuleDepInfo = cache.findKnownDependency(mainModuleID); + + std::vector linkLibraries; + auto addLinkLibrary = [&linkLibraries](const LinkLibrary &ll) { + linkLibraries.push_back(ll); + }; + + if (langOpts.EnableObjCInterop) + addLinkLibrary({"objc", LibraryKind::Library}); + + if (langOpts.EnableCXXInterop) { + auto OptionalCxxDep = cache.findDependency("Cxx"); + auto OptionalCxxStdLibDep = cache.findDependency("CxxStdlib"); + bool hasStaticCxx = + OptionalCxxDep.has_value() && OptionalCxxDep.value()->isStaticLibrary(); + bool hasStaticCxxStdlib = OptionalCxxStdLibDep.has_value() && + OptionalCxxStdLibDep.value()->isStaticLibrary(); + registerCxxInteropLibraries(langOpts.Target, mainModuleName, hasStaticCxx, + hasStaticCxxStdlib, addLinkLibrary); + } + + if (!irGenOpts.UseJIT && !langOpts.hasFeature(Feature::Embedded)) + registerBackDeployLibraries(irGenOpts, addLinkLibrary); + + mainModuleDepInfo.setLinkLibraries(linkLibraries); + cache.updateDependency(mainModuleID, mainModuleDepInfo); +} + llvm::ErrorOr -swift::dependencies::performModuleScan(CompilerInstance &instance, - DependencyScanDiagnosticCollector *diagnosticCollector, - ModuleDependenciesCache &cache) { +swift::dependencies::performModuleScan( + CompilerInstance &instance, + DependencyScanDiagnosticCollector *diagnosticCollector, + ModuleDependenciesCache &cache) { auto scanner = ModuleDependencyScanner( cache.getScanService(), instance.getInvocation(), instance.getSILOptions(), instance.getASTContext(), @@ -1425,10 +1481,8 @@ swift::dependencies::performModuleScan(CompilerInstance &instance, ModuleDependencyKind::SwiftSource}; // We may be re-using an instance of the cache which already contains // an entry for this module. - if (cache.findDependency(mainModuleName, ModuleDependencyKind::SwiftSource)) - cache.updateDependency( - ModuleDependencyID{mainModuleName.str(), ModuleDependencyKind::SwiftSource}, - std::move(*mainModuleDepInfo)); + if (cache.findDependency(mainModuleID)) + cache.updateDependency(mainModuleID, std::move(*mainModuleDepInfo)); else cache.recordDependency(mainModuleName, std::move(*mainModuleDepInfo)); @@ -1451,7 +1505,7 @@ swift::dependencies::performModuleScan(CompilerInstance &instance, computeTopologicalSortOfExplicitDependencies(allModules, cache); resolveDependencyCommandLineArguments(instance, cache, topologicallySortedModuleList); - + resolveImplicitLinkLibraries(instance, cache); updateDependencyTracker(instance, cache, allModules); return generateFullDependencyGraph(instance, diagnosticCollector, cache, topologicallySortedModuleList); @@ -1542,8 +1596,8 @@ swift::dependencies::performBatchModuleScan( : ModuleDependencyKind::SwiftInterface}; auto allDependencies = scanner.getModuleDependencies(moduleID, cache); batchScanResult.push_back( - generateFullDependencyGraph(instance, diagnosticCollector, - cache, allDependencies)); + generateFullDependencyGraph(instance, diagnosticCollector, cache, + allDependencies)); if (diagnosticCollector) diagnosticCollector->reset(); }); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d7872e3d3acaa..26e5f319e9407 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2995,6 +2995,7 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, } Opts.DisableFrameworkAutolinking = Args.hasArg(OPT_disable_autolink_frameworks); Opts.DisableAllAutolinking = Args.hasArg(OPT_disable_all_autolinking); + Opts.DisableForceLoadSymbols = Args.hasArg(OPT_disable_force_load_symbols); Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate); const Arg *ProfileUse = Args.getLastArg(OPT_profile_use); diff --git a/lib/IRGen/GenConcurrency.cpp b/lib/IRGen/GenConcurrency.cpp index 428066d348d0c..db73ce029953a 100644 --- a/lib/IRGen/GenConcurrency.cpp +++ b/lib/IRGen/GenConcurrency.cpp @@ -472,7 +472,7 @@ static llvm::Value *addOptionRecord(IRGenFunction &IGF, } /// Add a task option record to the options list if the given value -/// is presernt. +/// is present. template static llvm::Value *maybeAddOptionRecord(IRGenFunction &IGF, llvm::Value *curRecordPointer, @@ -645,15 +645,15 @@ struct TaskGroupRecordTraits { } }; -struct InitialTaskExecutorRecordTraits { +struct InitialTaskExecutorUnownedRecordTraits { static StringRef getLabel() { - return "task_executor"; + return "task_executor_unowned"; } static llvm::StructType *getRecordType(IRGenModule &IGM) { - return IGM.SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy; + return IGM.SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy; } static TaskOptionRecordFlags getRecordFlags() { - return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutor); + return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutorUnowned); } static CanType getValueType(ASTContext &ctx) { return ctx.TheExecutorType; @@ -670,6 +670,36 @@ struct InitialTaskExecutorRecordTraits { } }; +struct InitialTaskExecutorOwnedRecordTraits { + static StringRef getLabel() { + return "task_executor_owned"; + } + static llvm::StructType *getRecordType(IRGenModule &IGM) { + return IGM.SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy; + } + static TaskOptionRecordFlags getRecordFlags() { + return TaskOptionRecordFlags(TaskOptionRecordKind::InitialTaskExecutorOwned); + } + static CanType getValueType(ASTContext &ctx) { + return OptionalType::get(ctx.getProtocol(KnownProtocolKind::TaskExecutor) + ->getDeclaredInterfaceType()) + ->getCanonicalType(); + } + + void initialize(IRGenFunction &IGF, Address recordAddr, + Explosion &taskExecutor) const { + auto executorRecord = + IGF.Builder.CreateStructGEP(recordAddr, 1, 2 * IGF.IGM.getPointerSize()); + + // This relies on the fact that the HeapObject is directly followed by a + // pointer to the witness table. + IGF.Builder.CreateStore(taskExecutor.claimNext(), + IGF.Builder.CreateStructGEP(executorRecord, 0, Size())); + IGF.Builder.CreateStore(taskExecutor.claimNext(), + IGF.Builder.CreateStructGEP(executorRecord, 1, Size())); + } +}; + } // end anonymous namespace static llvm::Value * @@ -693,15 +723,25 @@ maybeAddInitialTaskExecutorOptionRecord(IRGenFunction &IGF, llvm::Value *prevOptions, OptionalExplosion &taskExecutor) { return maybeAddOptionRecord(IGF, prevOptions, - InitialTaskExecutorRecordTraits(), + InitialTaskExecutorUnownedRecordTraits(), taskExecutor); } +static llvm::Value * +maybeAddInitialTaskExecutorOwnedOptionRecord(IRGenFunction &IGF, + llvm::Value *prevOptions, + OptionalExplosion &taskExecutorExistential) { + return maybeAddOptionRecord(IGF, prevOptions, + InitialTaskExecutorOwnedRecordTraits(), + taskExecutorExistential); +} + std::pair irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, OptionalExplosion &serialExecutor, OptionalExplosion &taskGroup, - OptionalExplosion &taskExecutor, + OptionalExplosion &taskExecutorUnowned, + OptionalExplosion &taskExecutorExistential, Explosion &taskFunction, SubstitutionMap subs) { llvm::Value *taskOptions = @@ -729,8 +769,14 @@ irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, taskOptions = maybeAddTaskGroupOptionRecord(IGF, taskOptions, taskGroup); // Add an option record for the initial task executor, if present. - taskOptions = - maybeAddInitialTaskExecutorOptionRecord(IGF, taskOptions, taskExecutor); + { + // Deprecated: This is the UnownedTaskExecutor? which is NOT consuming + taskOptions = maybeAddInitialTaskExecutorOptionRecord( + IGF, taskOptions, taskExecutorUnowned); + // Take an (any TaskExecutor)? which we retain until task has completed + taskOptions = maybeAddInitialTaskExecutorOwnedOptionRecord( + IGF, taskOptions, taskExecutorExistential); + } // In embedded Swift, create and pass result type info. taskOptions = maybeAddEmbeddedSwiftResultTypeInfo(IGF, taskOptions, resultType); diff --git a/lib/IRGen/GenConcurrency.h b/lib/IRGen/GenConcurrency.h index 0fbb5169445fc..ec4bc110118b7 100644 --- a/lib/IRGen/GenConcurrency.h +++ b/lib/IRGen/GenConcurrency.h @@ -104,7 +104,8 @@ std::pair emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags, OptionalExplosion &initialExecutor, OptionalExplosion &taskGroup, - OptionalExplosion &taskExecutor, + OptionalExplosion &taskExecutorUnowned, + OptionalExplosion &taskExecutorExistential, Explosion &taskFunction, SubstitutionMap subs); diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 51ac5e3e754ba..f549411e4965f 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -22,6 +22,7 @@ #include "swift/AST/GenericSignature.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Module.h" +#include "swift/AST/ModuleDependencies.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Pattern.h" #include "swift/AST/ProtocolConformance.h" @@ -475,61 +476,33 @@ void IRGenModule::emitSourceFile(SourceFile &SF) { for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls()) maybeEmitOpaqueTypeDecl(opaqueDecl); - SF.collectLinkLibraries([this](LinkLibrary linkLib) { - this->addLinkLibrary(linkLib); + auto registerLinkLibrary = [this](const LinkLibrary &ll) { + this->addLinkLibrary(ll); + }; + + SF.collectLinkLibraries([registerLinkLibrary](LinkLibrary linkLib) { + registerLinkLibrary(linkLib); }); if (ObjCInterop) - this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library)); + registerLinkLibrary(LinkLibrary("objc", LibraryKind::Library)); // If C++ interop is enabled, add -lc++ on Darwin and -lstdc++ on linux. // Also link with C++ bridging utility module (Cxx) and C++ stdlib overlay // (std) if available. if (Context.LangOpts.EnableCXXInterop) { - const llvm::Triple &target = Context.LangOpts.Target; - if (target.isOSDarwin()) - this->addLinkLibrary(LinkLibrary("c++", LibraryKind::Library)); - else if (target.isOSLinux()) - this->addLinkLibrary(LinkLibrary("stdc++", LibraryKind::Library)); - - // Do not try to link Cxx with itself. - if (!getSwiftModule()->getName().is("Cxx")) { - bool isStatic = false; - if (const auto *M = Context.getModuleByName("Cxx")) - isStatic = M->isStaticLibrary(); - this->addLinkLibrary(LinkLibrary(target.isOSWindows() && isStatic - ? "libswiftCxx" - : "swiftCxx", - LibraryKind::Library)); - } - - // Do not try to link CxxStdlib with the C++ standard library, Cxx or - // itself. - if (llvm::none_of(llvm::ArrayRef{"Cxx", "CxxStdlib", "std"}, - [M = getSwiftModule()->getName().str()](StringRef Name) { - return M == Name; - })) { - // Only link with CxxStdlib on platforms where the overlay is available. - switch (target.getOS()) { - case llvm::Triple::Linux: - if (!target.isAndroid()) - this->addLinkLibrary(LinkLibrary("swiftCxxStdlib", - LibraryKind::Library)); - break; - case llvm::Triple::Win32: { - bool isStatic = Context.getModuleByName("CxxStdlib")->isStaticLibrary(); - this->addLinkLibrary( - LinkLibrary(isStatic ? "libswiftCxxStdlib" : "swiftCxxStdlib", - LibraryKind::Library)); - break; - } - default: - if (target.isOSDarwin()) - this->addLinkLibrary(LinkLibrary("swiftCxxStdlib", - LibraryKind::Library)); - break; - } - } + bool hasStaticCxx = false; + bool hasStaticCxxStdlib = false; + if (const auto *M = Context.getModuleByName("Cxx")) + hasStaticCxx = M->isStaticLibrary(); + if (Context.LangOpts.Target.getOS() == llvm::Triple::Win32) + if (const auto *M = Context.getModuleByName("CxxStdlib")) + hasStaticCxxStdlib = M->isStaticLibrary(); + dependencies::registerCxxInteropLibraries(Context.LangOpts.Target, + getSwiftModule()->getName().str(), + hasStaticCxx, + hasStaticCxxStdlib, + registerLinkLibrary); } // FIXME: It'd be better to have the driver invocation or build system that @@ -541,36 +514,8 @@ void IRGenModule::emitSourceFile(SourceFile &SF) { // libraries. This may however cause the library to get pulled in in // situations where it isn't useful, such as for dylibs, though this is // harmless aside from code size. - if (!IRGen.Opts.UseJIT && !Context.LangOpts.hasFeature(Feature::Embedded)) { - auto addBackDeployLib = [&](llvm::VersionTuple version, - StringRef libraryName, bool forceLoad) { - std::optional compatibilityVersion; - if (libraryName == "swiftCompatibilityDynamicReplacements") { - compatibilityVersion = IRGen.Opts. - AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion; - } else if (libraryName == "swiftCompatibilityConcurrency") { - compatibilityVersion = - IRGen.Opts.AutolinkRuntimeCompatibilityConcurrencyLibraryVersion; - } else { - compatibilityVersion = IRGen.Opts. - AutolinkRuntimeCompatibilityLibraryVersion; - } - - if (!compatibilityVersion) - return; - - if (*compatibilityVersion > version) - return; - - this->addLinkLibrary(LinkLibrary(libraryName, - LibraryKind::Library, - forceLoad)); - }; - -#define BACK_DEPLOYMENT_LIB(Version, Filter, LibraryName, ForceLoad) \ - addBackDeployLib(llvm::VersionTuple Version, LibraryName, ForceLoad); - #include "swift/Frontend/BackDeploymentLibs.def" - } + if (!IRGen.Opts.UseJIT && !Context.LangOpts.hasFeature(Feature::Embedded)) + dependencies::registerBackDeployLibraries(IRGen.Opts, registerLinkLibrary); } /// Emit all the top-level code in the synthesized file unit. diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp index 53ad6f72d8ebe..af6456cceccc6 100644 --- a/lib/IRGen/IRGenMangler.cpp +++ b/lib/IRGen/IRGenMangler.cpp @@ -186,6 +186,9 @@ IRGenMangler::mangleTypeForFlatUniqueTypeRef(CanGenericSignature sig, // mangled name. configureForSymbolicMangling(); + llvm::SaveAndRestore savedAllowMarkerProtocols( + AllowMarkerProtocols, false); + // We don't make the substitution adjustments above because they're // target-specific and so would break the goal of getting a unique // string. diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index 5c318a2c03105..d777686673ed7 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -706,9 +706,6 @@ class IRGenMangler : public Mangle::ASTMangler { llvm::function_ref body); std::string mangleTypeSymbol(Type type, const char *Op) { - llvm::SaveAndRestore savedAllowMarkerProtocols(AllowMarkerProtocols, - false); - beginMangling(); appendType(type, nullptr); appendOperator(Op); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 4158847a6bf6b..19eb234924e2c 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -708,11 +708,16 @@ IRGenModule::IRGenModule(IRGenerator &irgen, SwiftTaskOptionRecordTy, // Base option record SwiftExecutorTy, // Executor }); - SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy = + SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy = createStructType(*this, "swift.task_executor_task_option", { SwiftTaskOptionRecordTy, // Base option record SwiftExecutorTy, // Executor }); + SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy = + createStructType(*this, "swift.task_executor_owned_task_option", { + SwiftTaskOptionRecordTy, // Base option record + SwiftExecutorTy, // Executor + }); SwiftJobTy = createStructType(*this, "swift.job", { RefCountedStructTy, // object header Int8PtrTy, Int8PtrTy, // SchedulerPrivate @@ -1583,7 +1588,7 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { } } - if (linkLib.shouldForceLoad()) { + if (!IRGen.Opts.DisableForceLoadSymbols && linkLib.shouldForceLoad()) { llvm::SmallString<64> buf; encodeForceLoadSymbolName(buf, linkLib.getName()); auto ForceImportThunk = cast( diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 9b1e8bf8386d8..c3820bf9e7106 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -821,7 +821,8 @@ class IRGenModule { llvm::StructType *SwiftTaskOptionRecordTy; llvm::StructType *SwiftInitialSerialExecutorTaskOptionRecordTy; llvm::StructType *SwiftTaskGroupTaskOptionRecordTy; - llvm::StructType *SwiftInitialTaskExecutorPreferenceTaskOptionRecordTy; + llvm::StructType *SwiftInitialTaskExecutorUnownedPreferenceTaskOptionRecordTy; + llvm::StructType *SwiftInitialTaskExecutorOwnedPreferenceTaskOptionRecordTy; llvm::StructType *SwiftResultTypeInfoTaskOptionRecordTy; llvm::PointerType *SwiftJobPtrTy; llvm::IntegerType *ExecutorFirstTy; diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index e04d778f8a8d2..7959bd9a9674e 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -1350,6 +1350,9 @@ class IRGenSILFunction : void visitEndLifetimeInst(EndLifetimeInst *i) { llvm_unreachable("unimplemented"); } + void visitExtendLifetimeInst(ExtendLifetimeInst *i) { + llvm_unreachable("should not exist after ownership lowering!?"); + } void visitUncheckedOwnershipConversionInst(UncheckedOwnershipConversionInst *i) { llvm_unreachable("unimplemented"); @@ -3617,14 +3620,18 @@ static void emitBuiltinStackDealloc(IRGenSILFunction &IGF, static void emitBuiltinCreateAsyncTask(IRGenSILFunction &IGF, swift::BuiltinInst *i) { + assert(i->getOperandValues().size() == 6 && + "createAsyncTask needs 6 operands"); auto flags = IGF.getLoweredSingletonExplosion(i->getOperand(0)); auto serialExecutor = IGF.getLoweredOptionalExplosion(i->getOperand(1)); auto taskGroup = IGF.getLoweredOptionalExplosion(i->getOperand(2)); - auto taskExecutor = IGF.getLoweredOptionalExplosion(i->getOperand(3)); - Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(4)); + auto taskExecutorUnowned = IGF.getLoweredOptionalExplosion(i->getOperand(3)); + auto taskExecutorOwned = IGF.getLoweredOptionalExplosion(i->getOperand(4)); + Explosion taskFunction = IGF.getLoweredExplosion(i->getOperand(5)); auto taskAndContext = - emitTaskCreate(IGF, flags, serialExecutor, taskGroup, taskExecutor, + emitTaskCreate(IGF, flags, serialExecutor, taskGroup, + taskExecutorUnowned, taskExecutorOwned, taskFunction, i->getSubstitutions()); Explosion out; out.add(taskAndContext.first); diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index ce81201f59411..72295817d50e7 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1979,6 +1979,16 @@ namespace { MetadataResponse visitExistentialType(CanExistentialType type, DynamicMetadataRequest request) { + if (auto *PCT = + type->getConstraintType()->getAs()) { + auto constraintTy = PCT->withoutMarkerProtocols(); + if (constraintTy->getClassOrBoundGenericClass()) { + auto response = IGF.emitTypeMetadataRef( + constraintTy->getCanonicalType(), request); + return setLocal(type, response); + } + } + if (auto metadata = tryGetLocal(type, request)) return metadata; diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 70baa169c7917..140a398a2c54c 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -225,6 +225,7 @@ OPERAND_OWNERSHIP(InstantaneousUse, SuperMethod) OPERAND_OWNERSHIP(InstantaneousUse, ClassifyBridgeObject) OPERAND_OWNERSHIP(InstantaneousUse, UnownedCopyValue) OPERAND_OWNERSHIP(InstantaneousUse, WeakCopyValue) +OPERAND_OWNERSHIP(InstantaneousUse, ExtendLifetime) #define REF_STORAGE(Name, ...) \ OPERAND_OWNERSHIP(InstantaneousUse, StrongCopy##Name##Value) #include "swift/AST/ReferenceStorage.def" @@ -927,6 +928,12 @@ ::visitStartAsyncLetWithLocalBuffer(BuiltinInst *bi, StringRef attr) { OperandOwnership OperandOwnershipBuiltinClassifier::visitCreateAsyncTask(BuiltinInst *bi, StringRef attr) { + if (&op == &bi->getOperandRef(4)) { + // The (any TaskExecutor)? (optional) must be consumed by the builtin, + // as we will keep it alive and later destroy it as the task runs to completion. + return OperandOwnership::ForwardingConsume; + } + // The function operand is consumed by the new task. if (&op == &bi->getArgumentOperands().back()) return OperandOwnership::DestroyingConsume; diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index 8a7ae3014b085..ef9cd814c645f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2565,6 +2565,9 @@ class SILPrinter : public SILInstructionVisitor { void visitEndLifetimeInst(EndLifetimeInst *ELI) { *this << getIDAndType(ELI->getOperand()); } + void visitExtendLifetimeInst(ExtendLifetimeInst *ELLI) { + *this << getIDAndType(ELLI->getOperand()); + } void visitValueToBridgeObjectInst(ValueToBridgeObjectInst *VBOI) { *this << getIDAndType(VBOI->getOperand()); } diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index ad5e77cfd5184..9226ba94e845a 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -3308,6 +3308,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, UNARY_INSTRUCTION(ValueToBridgeObject) UNARY_INSTRUCTION(FixLifetime) UNARY_INSTRUCTION(EndLifetime) + UNARY_INSTRUCTION(ExtendLifetime) UNARY_INSTRUCTION(CopyBlock) UNARY_INSTRUCTION(IsUnique) UNARY_INSTRUCTION(DestroyAddr) diff --git a/lib/SIL/Utils/InstructionUtils.cpp b/lib/SIL/Utils/InstructionUtils.cpp index 77cf3c28524e1..b3cc52ef3d5f1 100644 --- a/lib/SIL/Utils/InstructionUtils.cpp +++ b/lib/SIL/Utils/InstructionUtils.cpp @@ -560,6 +560,7 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType) case SILInstructionKind::AssignOrInitInst: case SILInstructionKind::MarkFunctionEscapeInst: case SILInstructionKind::EndLifetimeInst: + case SILInstructionKind::ExtendLifetimeInst: case SILInstructionKind::EndApplyInst: case SILInstructionKind::AbortApplyInst: case SILInstructionKind::CondFailInst: diff --git a/lib/SIL/Utils/OSSALifetimeCompletion.cpp b/lib/SIL/Utils/OSSALifetimeCompletion.cpp index 8e2a84e131cec..fa6cf09c53e4f 100644 --- a/lib/SIL/Utils/OSSALifetimeCompletion.cpp +++ b/lib/SIL/Utils/OSSALifetimeCompletion.cpp @@ -58,9 +58,14 @@ using namespace swift; -static SILInstruction *endOSSALifetime(SILValue value, SILBuilder &builder) { +static SILInstruction *endOSSALifetime(SILValue value, + OSSALifetimeCompletion::LifetimeEnd end, + SILBuilder &builder) { auto loc = RegularLocation::getAutoGeneratedLocation(builder.getInsertionPointLoc()); + if (end == OSSALifetimeCompletion::LifetimeEnd::Loop) { + return builder.createExtendLifetime(loc, value); + } if (value->getOwnershipKind() == OwnershipKind::Owned) { if (value->getType().is()) { return builder.createDeallocBox(loc, value); @@ -81,14 +86,16 @@ static bool endLifetimeAtLivenessBoundary(SILValue value, != PrunedLiveness::LifetimeEndingUse) { changed = true; SILBuilderWithScope::insertAfter(lastUser, [value](SILBuilder &builder) { - endOSSALifetime(value, builder); + endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary, + builder); }); } } for (SILBasicBlock *edge : boundary.boundaryEdges) { changed = true; SILBuilderWithScope builder(edge->begin()); - endOSSALifetime(value, builder); + endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary, + builder); } for (SILNode *deadDef : boundary.deadDefs) { SILInstruction *next = nullptr; @@ -99,15 +106,54 @@ static bool endLifetimeAtLivenessBoundary(SILValue value, } changed = true; SILBuilderWithScope builder(next); - endOSSALifetime(value, builder); + endOSSALifetime(value, OSSALifetimeCompletion::LifetimeEnd::Boundary, + builder); } return changed; } +static void visitUsersOutsideLinearLivenessBoundary( + SILValue value, const SSAPrunedLiveness &liveness, + llvm::function_ref visitor) { + if (value->getOwnershipKind() == OwnershipKind::None) { + return; + } + LinearLiveness linearLiveness(value); + linearLiveness.compute(); + for (auto pair : liveness.getAllUsers()) { + if (pair.second.isEnding() || isa(pair.first)) { + continue; + } + auto *user = pair.first; + if (linearLiveness.getLiveness().isWithinBoundary(user)) { + continue; + } + visitor(user); + } +} + +namespace swift::test { +// Arguments: +// - SILValue: value +// Dumps: +// - the instructions outside the liveness boundary +static FunctionTest LivenessPartialBoundaryOutsideUsersTest( + "liveness_partial_boundary_outside_users", + [](auto &function, auto &arguments, auto &test) { + SILValue value = arguments.takeValue(); + InteriorLiveness liveness(value); + liveness.compute(test.getDominanceInfo()); + visitUsersOutsideLinearLivenessBoundary( + value, liveness.getLiveness(), + [](auto *inst) { inst->print(llvm::outs()); }); + }); +} // end namespace swift::test + namespace { -/// Implements OSSALifetimeCompletion::visitUnreachableLifetimeEnds. Finds -/// positions as near as possible to unreachables at which `value`'s lifetime -/// is available. +/// Visits the latest instructions at which `value` is available. +/// +/// Together with visitUsersOutsideLinearLivenessBoundary, implements +/// OSSALifetimeCompletion::visitAvailabilityBoundary. /// /// Finding these positions is a three step process: /// 1) computeRegion: Forward CFG walk from non-lifetime-ending boundary to find @@ -118,7 +164,7 @@ namespace { /// the value is available--these are the blocks /// without successors or with at least one /// unavailable successor. -class VisitUnreachableLifetimeEnds { +class AvailabilityBoundaryVisitor { /// The value whose dead-end block lifetime ends are to be visited. SILValue value; @@ -134,26 +180,31 @@ class VisitUnreachableLifetimeEnds { BasicBlockSetVector region; public: - VisitUnreachableLifetimeEnds(SILValue value, - OSSALifetimeCompletion::AllowLeaks_t allowLeaks) + AvailabilityBoundaryVisitor(SILValue value, + OSSALifetimeCompletion::AllowLeaks_t allowLeaks) : value(value), allowLeaks(allowLeaks), starts(value->getFunction()), region(value->getFunction()) {} + using Visit = llvm::function_ref; + + struct Result; + + /// Do all three steps at once. + void visit(const SSAPrunedLiveness &liveness, Result &result, Visit visit); + +private: /// Region discovery. /// /// Forward CFG walk from non-lifetime-ending boundary to unreachable /// instructions. void computeRegion(const SSAPrunedLiveness &liveness); - struct Result; - /// Iterative dataflow to determine availability for each block in `region`. void propagateAvailablity(Result &result); /// Visit the terminators of blocks on the boundary of availability. - void - visitAvailabilityBoundary(Result const &result, - llvm::function_ref visit); + void visitAvailabilityBoundary(Result const &result, Visit visit); struct State { enum Value : uint8_t { @@ -170,6 +221,7 @@ class VisitUnreachableLifetimeEnds { } }; +public: struct Result { BasicBlockBitfield states; @@ -198,7 +250,16 @@ class VisitUnreachableLifetimeEnds { }; }; -void VisitUnreachableLifetimeEnds::computeRegion( +void AvailabilityBoundaryVisitor::visit(const SSAPrunedLiveness &liveness, + Result &result, Visit visit) { + computeRegion(liveness); + + propagateAvailablity(result); + + visitAvailabilityBoundary(result, visit); +} + +void AvailabilityBoundaryVisitor::computeRegion( const SSAPrunedLiveness &liveness) { // (1) Compute the complete liveness boundary. PrunedLivenessBoundary boundary; @@ -258,7 +319,7 @@ void VisitUnreachableLifetimeEnds::computeRegion( } } -void VisitUnreachableLifetimeEnds::propagateAvailablity(Result &result) { +void AvailabilityBoundaryVisitor::propagateAvailablity(Result &result) { // Initialize per-block state. // - all blocks outside of the region are ::Unavailable (automatically // initialized) @@ -299,8 +360,11 @@ void VisitUnreachableLifetimeEnds::propagateAvailablity(Result &result) { } } -void VisitUnreachableLifetimeEnds::visitAvailabilityBoundary( - Result const &result, llvm::function_ref visit) { +void AvailabilityBoundaryVisitor::visitAvailabilityBoundary( + Result const &result, + llvm::function_ref + visit) { for (auto *block : region) { auto available = result.getState(block) == State::Available; if (!available) { @@ -323,34 +387,37 @@ void VisitUnreachableLifetimeEnds::visitAvailabilityBoundary( } assert(hasUnavailableSuccessor() || isa(block->getTerminator())); - visit(block->getTerminator()); + visit(block->getTerminator(), + OSSALifetimeCompletion::LifetimeEnd::Boundary); } } } // end anonymous namespace -void OSSALifetimeCompletion::visitUnreachableLifetimeEnds( +void OSSALifetimeCompletion::visitAvailabilityBoundary( SILValue value, AllowLeaks_t allowLeaks, const SSAPrunedLiveness &liveness, - llvm::function_ref visit) { - - VisitUnreachableLifetimeEnds visitor(value, allowLeaks); - - visitor.computeRegion(liveness); - - VisitUnreachableLifetimeEnds::Result result(value->getFunction()); - - visitor.propagateAvailablity(result); - - visitor.visitAvailabilityBoundary(result, visit); + llvm::function_ref visit) { + + AvailabilityBoundaryVisitor visitor(value, allowLeaks); + AvailabilityBoundaryVisitor::Result result(value->getFunction()); + visitor.visit(liveness, result, visit); + + visitUsersOutsideLinearLivenessBoundary( + value, liveness, [&](auto *instruction) { + instruction->visitSubsequentInstructions([&](auto *next) { + visit(next, LifetimeEnd::Loop); + return true; + }); + }); } static bool endLifetimeAtAvailabilityBoundary( SILValue value, OSSALifetimeCompletion::AllowLeaks_t allowLeaks, const SSAPrunedLiveness &liveness) { bool changed = false; - OSSALifetimeCompletion::visitUnreachableLifetimeEnds( - value, allowLeaks, liveness, [&](auto *unreachable) { + OSSALifetimeCompletion::visitAvailabilityBoundary( + value, allowLeaks, liveness, [&](auto *unreachable, auto end) { SILBuilderWithScope builder(unreachable); - endOSSALifetime(value, builder); + endOSSALifetime(value, end, builder); changed = true; }); return changed; diff --git a/lib/SIL/Utils/OwnershipLiveness.cpp b/lib/SIL/Utils/OwnershipLiveness.cpp index 214880789d915..a29827308e0a2 100644 --- a/lib/SIL/Utils/OwnershipLiveness.cpp +++ b/lib/SIL/Utils/OwnershipLiveness.cpp @@ -38,6 +38,10 @@ struct LinearLivenessVisitor : linearLiveness(linearLiveness){} bool handleUsePoint(Operand *use, UseLifetimeConstraint useConstraint) { + if (!linearLiveness.includeExtensions && + isa(use->getUser())) { + return true; + } linearLiveness.liveness.updateForUse( use->getUser(), useConstraint == UseLifetimeConstraint::LifetimeEnding); return true; @@ -71,7 +75,9 @@ struct LinearLivenessVisitor : } }; -LinearLiveness::LinearLiveness(SILValue def): OSSALiveness(def) { +LinearLiveness::LinearLiveness(SILValue def, + IncludeExtensions_t includeExtensions) + : OSSALiveness(def), includeExtensions(includeExtensions) { if (def->getOwnershipKind() != OwnershipKind::Owned) { BorrowedValue borrowedValue(def); assert(borrowedValue && borrowedValue.isLocalScope()); @@ -118,7 +124,7 @@ struct InteriorLivenessVisitor : bool handleUsePoint(Operand *use, UseLifetimeConstraint useConstraint) { interiorLiveness.liveness.updateForUse( - use->getUser(), useConstraint == UseLifetimeConstraint::LifetimeEnding); + use->getUser(), useConstraint == UseLifetimeConstraint::LifetimeEnding); return true; } @@ -302,7 +308,7 @@ struct ExtendedLinearLivenessVisitor bool handleUsePoint(Operand *use, UseLifetimeConstraint useConstraint) { extendedLiveness.liveness.updateForUse( - use->getUser(), useConstraint == UseLifetimeConstraint::LifetimeEnding); + use->getUser(), useConstraint == UseLifetimeConstraint::LifetimeEnding); return true; } diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index 70a38af02a53e..a0bac30bebca1 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -950,6 +950,10 @@ bool BorrowedValue::visitLocalScopeEndingUses( case BorrowedValueKind::Phi: case BorrowedValueKind::BeginApplyToken: for (auto *use : lookThroughBorrowedFromUser(value)->getUses()) { + if (isa(use->getUser())) { + if (!visitor(use)) + return false; + } if (use->isLifetimeEnding()) { if (!visitor(use)) return false; diff --git a/lib/SIL/Utils/PrunedLiveness.cpp b/lib/SIL/Utils/PrunedLiveness.cpp index aa2fdbd32ea16..a714174e32b72 100644 --- a/lib/SIL/Utils/PrunedLiveness.cpp +++ b/lib/SIL/Utils/PrunedLiveness.cpp @@ -216,12 +216,12 @@ void PrunedLiveRange::updateForUse( template void PrunedLiveRange::updateForUse(SILInstruction *user, bool lifetimeEnding) { - updateForUse(user, LifetimeEnding(lifetimeEnding)); + updateForUse(user, LifetimeEnding::forUse(lifetimeEnding)); } template void PrunedLiveRange::extendToNonUse(SILInstruction *inst) { - updateForUse(inst, LifetimeEnding::NonUse()); + updateForUse(inst, LifetimeEnding::Value::NonUse); } template diff --git a/lib/SIL/Verifier/LinearLifetimeChecker.cpp b/lib/SIL/Verifier/LinearLifetimeChecker.cpp index a972154e1a0e2..71beb79f41358 100644 --- a/lib/SIL/Verifier/LinearLifetimeChecker.cpp +++ b/lib/SIL/Verifier/LinearLifetimeChecker.cpp @@ -90,6 +90,9 @@ struct State { /// The list of passed in consuming uses. ArrayRef consumingUses; + /// extend_lifetime uses. + ArrayRef extendLifetimeUses; + /// The list of passed in non consuming uses. ArrayRef nonConsumingUses; @@ -117,13 +120,16 @@ struct State { std::optional> leakingBlockCallback, std::optional> nonConsumingUseOutsideLifetimeCallback, - ArrayRef consumingUses, ArrayRef nonConsumingUses) + ArrayRef consumingUses, + ArrayRef extendLifetimeUses, + ArrayRef nonConsumingUses) : value(value), beginInst(value->getDefiningInsertionPoint()), errorBuilder(errorBuilder), visitedBlocks(value->getFunction()), leakingBlockCallback(leakingBlockCallback), nonConsumingUseOutsideLifetimeCallback( nonConsumingUseOutsideLifetimeCallback), - consumingUses(consumingUses), nonConsumingUses(nonConsumingUses), + consumingUses(consumingUses), extendLifetimeUses(extendLifetimeUses), + nonConsumingUses(nonConsumingUses), blocksWithConsumingUses(value->getFunction()) {} State(SILBasicBlock *beginBlock, @@ -131,18 +137,25 @@ struct State { std::optional> leakingBlockCallback, std::optional> nonConsumingUseOutsideLifetimeCallback, - ArrayRef consumingUses, ArrayRef nonConsumingUses) + ArrayRef consumingUses, + ArrayRef extendLifetimeUses, + ArrayRef nonConsumingUses) : value(), beginInst(&*beginBlock->begin()), errorBuilder(errorBuilder), visitedBlocks(beginBlock->getParent()), leakingBlockCallback(leakingBlockCallback), nonConsumingUseOutsideLifetimeCallback( nonConsumingUseOutsideLifetimeCallback), - consumingUses(consumingUses), nonConsumingUses(nonConsumingUses), + consumingUses(consumingUses), extendLifetimeUses(extendLifetimeUses), + nonConsumingUses(nonConsumingUses), blocksWithConsumingUses(beginBlock->getParent()) {} SILBasicBlock *getBeginBlock() const { return beginInst->getParent(); } void initializeAllNonConsumingUses(ArrayRef nonConsumingUsers); + void initializeAllExtendLifetimeUses( + ArrayRef extendLifetimeUses, + SmallVectorImpl> + &predsToAddToWorklist); void initializeAllConsumingUses( ArrayRef consumingUsers, SmallVectorImpl> @@ -245,6 +258,53 @@ void State::initializeAllNonConsumingUses( // Consuming Use Initialization //===----------------------------------------------------------------------===// +void State::initializeAllExtendLifetimeUses( + ArrayRef extendLifetimeUses, + SmallVectorImpl> + &predsToAddToWorklist) { + // TODO: Efficiency. + for (auto *use : extendLifetimeUses) { + auto *user = use->getUser(); + auto *block = user->getParent(); + + auto iter = blocksWithNonConsumingUses.find(block); + if (!iter.has_value()) { + continue; + } + + // Remove the block from `blocksWithNonConsumingUses` if all non-consuming + // uses within the block occur before `user`. + bool allBefore = true; + for (auto *nonConsumingUse : *iter) { + auto *nonConsumingUser = nonConsumingUse->getUser(); + assert(nonConsumingUser != user); + + bool sawNonConsumingUser = false; + for (auto *inst = user->getNextInstruction(); inst; + inst = inst->getNextInstruction()) { + if (inst == nonConsumingUser) { + sawNonConsumingUser = true; + break; + } + } + if (sawNonConsumingUser) { + allBefore = false; + break; + } + } + if (allBefore) { + blocksWithNonConsumingUses.erase(block); + } + + // Add relevant predecessors to the worklist. + if (block == getBeginBlock()) + continue; + for (auto *predecessor : block->getPredecessorBlocks()) { + predsToAddToWorklist.push_back({use, predecessor}); + } + } +} + void State::initializeAllConsumingUses( ArrayRef consumingUses, SmallVectorImpl> @@ -555,7 +615,7 @@ void State::checkDataflowEndState(DeadEndBlocks *deBlocks) { LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl( SILValue value, ArrayRef consumingUses, - ArrayRef nonConsumingUses, ErrorBuilder &errorBuilder, + ArrayRef regularUses, ErrorBuilder &errorBuilder, std::optional> leakingBlockCallback, std::optional> nonConsumingUseOutsideLifetimeCallback) { @@ -571,9 +631,19 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl( // || deadEndBlocks.isDeadEnd(value->getParentBlock())) && // "Must have at least one consuming user?!"); + SmallVector nonConsumingUses; + SmallVector extendLifetimeUses; + for (auto *use : regularUses) { + if (isa(use->getUser())) { + extendLifetimeUses.push_back(use); + } else { + nonConsumingUses.push_back(use); + } + } + State state(value, errorBuilder, leakingBlockCallback, nonConsumingUseOutsideLifetimeCallback, consumingUses, - nonConsumingUses); + extendLifetimeUses, nonConsumingUses); // First add our non-consuming uses and their blocks to the // blocksWithNonConsumingUses map. While we do this, if we have multiple uses @@ -595,6 +665,9 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl( SmallVector, 32> predsToAddToWorklist; state.initializeAllConsumingUses(consumingUses, predsToAddToWorklist); + state.initializeAllExtendLifetimeUses(extendLifetimeUses, + predsToAddToWorklist); + // If we have a singular consuming use and it is in the same block as value's // def, we bail early. Any use-after-frees due to non-consuming uses would // have been detected by initializing our consuming uses. So we are done. @@ -633,6 +706,10 @@ LinearLifetimeChecker::Error LinearLifetimeChecker::checkValueImpl( state.visitedBlocks.insert(i->getUser()->getParent()); } + for (const auto &i : extendLifetimeUses) { + state.visitedBlocks.insert(i->getUser()->getParent()); + } + // Now that we have marked all of our producing blocks, we go through our // predsToAddToWorklist list and add our preds, making sure that none of these // preds are in blocksWithConsumingUses. This is important so that we do not diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index c6d660d5d0bc3..215dbef250ead 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -99,6 +99,12 @@ class SILValueOwnershipChecker { /// successful. SmallVector lifetimeEndingUsers; + /// extend_lifetime users of `value`. + /// + /// Collected separately because such users do "end the lifetime" but are not + /// consuming users. + SmallVector extendLifetimeUses; + /// The list of non lifetime ending users that we found. Only valid if check /// is successful. SmallVector regularUsers; @@ -129,16 +135,26 @@ class SILValueOwnershipChecker { bool isCompatibleDefUse(Operand *op, ValueOwnershipKind ownershipKind); bool gatherUsers(SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl &extendLifetimeUses, SmallVectorImpl ®ularUsers); bool gatherNonGuaranteedUsers(SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl &extendLifetimeUses, SmallVectorImpl ®ularUsers); - bool checkValueWithoutLifetimeEndingUses(ArrayRef regularUsers); + bool + checkValueWithoutLifetimeEndingUses(ArrayRef regularUsers, + ArrayRef extendLifetimeUses); - bool checkFunctionArgWithoutLifetimeEndingUses(SILFunctionArgument *arg); - bool checkYieldWithoutLifetimeEndingUses(MultipleValueInstructionResult *yield, - ArrayRef regularUsers); + bool checkFunctionArgWithoutLifetimeEndingUses( + SILFunctionArgument *arg, ArrayRef regularUsers, + ArrayRef extendLifetimeUses); + bool + checkYieldWithoutLifetimeEndingUses(MultipleValueInstructionResult *yield, + ArrayRef regularUsers, + ArrayRef extendLifetimeUses); + bool checkDeadEnds(SILBasicBlock *block, ArrayRef regularUsers, + ArrayRef extendLifetimeUses); bool isGuaranteedFunctionArgWithLifetimeEndingUses( SILFunctionArgument *arg, @@ -166,6 +182,7 @@ bool SILValueOwnershipChecker::check() { llvm::copy(lifetimeEndingUsers, std::back_inserter(allLifetimeEndingUsers)); SmallVector allRegularUsers; llvm::copy(regularUsers, std::back_inserter(allRegularUsers)); + llvm::copy(extendLifetimeUses, std::back_inserter(allRegularUsers)); LinearLifetimeChecker checker(deadEndBlocks); auto linearLifetimeResult = checker.checkValue(value, allLifetimeEndingUsers, @@ -199,6 +216,7 @@ bool SILValueOwnershipChecker::isCompatibleDefUse( bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl &extendLifetimeUses, SmallVectorImpl &nonLifetimeEndingUsers) { bool foundError = false; @@ -209,6 +227,11 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( for (auto *op : value->getUses()) { auto *user = op->getUser(); + if (isa(user)) { + extendLifetimeUses.push_back(op); + continue; + } + // For example, type dependent operands are non-use. It is not interesting // from an ownership perspective. if (op->getOperandOwnership() == OperandOwnership::NonUse) @@ -268,6 +291,7 @@ bool SILValueOwnershipChecker::gatherNonGuaranteedUsers( bool SILValueOwnershipChecker::gatherUsers( SmallVectorImpl &lifetimeEndingUsers, + SmallVectorImpl &extendLifetimeUses, SmallVectorImpl &nonLifetimeEndingUsers) { // See if Value is guaranteed. If we are guaranteed and not forwarding, then @@ -275,7 +299,7 @@ bool SILValueOwnershipChecker::gatherUsers( // forwarding, we do not create any lifetime ending users/non lifetime ending // users since we verify against our base. if (value->getOwnershipKind() != OwnershipKind::Guaranteed) { - return !gatherNonGuaranteedUsers(lifetimeEndingUsers, + return !gatherNonGuaranteedUsers(lifetimeEndingUsers, extendLifetimeUses, nonLifetimeEndingUsers); } @@ -474,8 +498,39 @@ bool SILValueOwnershipChecker::gatherUsers( return !foundError; } +/// Precondition: value has no lifetimeEndingUsers +bool SILValueOwnershipChecker::checkDeadEnds( + SILBasicBlock *block, ArrayRef regularUses, + ArrayRef extendedLifetimeUses) { + if (deadEndBlocks && deadEndBlocks->isDeadEnd(block)) + return true; + + if (extendLifetimeUses.size() == 0) + return false; + + SSAPrunedLiveness liveness(value->getFunction()); + liveness.initializeDef(value); + for (auto *use : extendedLifetimeUses) { + liveness.updateForUse(use->getUser(), /*lifetimeEnding=*/true); + } + auto allWithinBoundary = true; + for (auto *use : regularUses) { + if (!liveness.isWithinBoundary(use->getUser())) { + allWithinBoundary |= errorBuilder.handleMalformedSIL([&] { + llvm::errs() + << "Owned value without lifetime ending uses whose regular use " + "isn't enclosed within extend_lifetime instructions:\n" + << "Value: " << value << '\n' + << "User: " << use->getUser() << '\n'; + }); + } + } + return allWithinBoundary; +} + bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses( - SILFunctionArgument *arg) { + SILFunctionArgument *arg, ArrayRef regularUses, + ArrayRef extendLifetimeUses) { switch (arg->getOwnershipKind()) { case OwnershipKind::Any: llvm_unreachable("Value can not have any ownership kind?!"); @@ -487,7 +542,7 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses( break; } - if (deadEndBlocks && deadEndBlocks->isDeadEnd(arg->getParent())) + if (checkDeadEnds(arg->getParent(), regularUses, extendLifetimeUses)) return true; return !errorBuilder.handleMalformedSIL([&] { @@ -497,7 +552,8 @@ bool SILValueOwnershipChecker::checkFunctionArgWithoutLifetimeEndingUses( } bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses( - MultipleValueInstructionResult *yield, ArrayRef regularUses) { + MultipleValueInstructionResult *yield, ArrayRef regularUses, + ArrayRef extendLifetimeUses) { switch (yield->getOwnershipKind()) { case OwnershipKind::Any: llvm_unreachable("value with any ownership kind?!"); @@ -505,8 +561,8 @@ bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses( case OwnershipKind::None: return true; case OwnershipKind::Owned: - if (deadEndBlocks - && deadEndBlocks->isDeadEnd(yield->getParent()->getParent())) { + if (checkDeadEnds(yield->getParent()->getParent(), regularUses, + extendLifetimeUses)) { return true; } return !errorBuilder.handleMalformedSIL([&] { @@ -549,16 +605,21 @@ bool SILValueOwnershipChecker::checkYieldWithoutLifetimeEndingUses( } bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses( - ArrayRef regularUses) { + ArrayRef regularUses, ArrayRef extendLifetimeUses) { + if (extendLifetimeUses.size()) { + } + LLVM_DEBUG(llvm::dbgs() << "No lifetime ending users?! Bailing early.\n"); if (auto *arg = dyn_cast(value)) { - if (checkFunctionArgWithoutLifetimeEndingUses(arg)) { + if (checkFunctionArgWithoutLifetimeEndingUses(arg, regularUses, + extendLifetimeUses)) { return true; } } if (auto *yield = isaResultOf(value)) { - return checkYieldWithoutLifetimeEndingUses(yield, regularUses); + return checkYieldWithoutLifetimeEndingUses(yield, regularUses, + extendLifetimeUses); } // Check if we are a guaranteed subobject. In such a case, we should never @@ -575,7 +636,7 @@ bool SILValueOwnershipChecker::checkValueWithoutLifetimeEndingUses( return true; if (auto *parentBlock = value->getParentBlock()) { - if (deadEndBlocks && deadEndBlocks->isDeadEnd(parentBlock)) { + if (checkDeadEnds(parentBlock, regularUses, extendLifetimeUses)) { LLVM_DEBUG(llvm::dbgs() << "Ignoring transitively unreachable value " << "without users!\n" << " Value: " << *value << '\n'); @@ -673,7 +734,7 @@ bool SILValueOwnershipChecker::checkUses() { // 1. Verify that none of the uses are in the same block. This would be an // overconsume so in this case we assert. // 2. Verify that the uses are compatible with our ownership convention. - if (!gatherUsers(lifetimeEndingUsers, regularUsers)) { + if (!gatherUsers(lifetimeEndingUsers, extendLifetimeUses, regularUsers)) { // Silently return false if this fails. // // If the user pass in a ErrorBehaviorKind that will assert, we @@ -701,7 +762,7 @@ bool SILValueOwnershipChecker::checkUses() { // In the case of a yielded guaranteed value, we need to validate that all // regular uses of the value are within the coroutine. if (lifetimeEndingUsers.empty()) { - if (checkValueWithoutLifetimeEndingUses(regularUsers)) + if (checkValueWithoutLifetimeEndingUses(regularUsers, extendLifetimeUses)) return false; return true; } diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 394b37585b3e7..c6b556a0f9e18 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -10,12 +10,14 @@ // //===----------------------------------------------------------------------===// +#include "swift/SIL/SILValue.h" +#include #define DEBUG_TYPE "sil-verifier" #include "VerifierPrivate.h" #include "swift/AST/ASTContext.h" -#include "swift/AST/AnyFunctionRef.h" #include "swift/AST/ASTSynthesis.h" +#include "swift/AST/AnyFunctionRef.h" #include "swift/AST/Decl.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" @@ -35,6 +37,7 @@ #include "swift/SIL/Dominance.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/MemAccessUtils.h" +#include "swift/SIL/OwnershipLiveness.h" #include "swift/SIL/OwnershipUtils.h" #include "swift/SIL/PostOrder.h" #include "swift/SIL/PrettyStackTrace.h" @@ -864,7 +867,15 @@ class SILVerifier : public SILVerifierBase { // Used for dominance checking within a basic block. llvm::DenseMap InstNumbers; - std::unique_ptr DEBlocks; + /// TODO: LifetimeCompletion: Remove. + std::shared_ptr DEBlocks; + + /// Blocks without function exiting paths. + /// + /// Used to verify extend_lifetime instructions. + /// + /// TODO: LifetimeCompletion: shared_ptr -> unique_ptr + std::shared_ptr deadEndBlocks; LoadBorrowImmutabilityAnalysis loadBorrowImmutabilityAnalysis; @@ -1062,6 +1073,16 @@ class SILVerifier : public SILVerifierBase { return SynthesisContext(F.getASTContext(), dc); } + DeadEndBlocks &getDeadEndBlocks() { + if (DEBlocks) { + deadEndBlocks = DEBlocks; + } else { + deadEndBlocks = + std::make_shared(const_cast(&F)); + } + return *deadEndBlocks; + } + template void requireType(SILType type1, const S &s, const Twine &what) { auto sc = getSynthesisContext(); @@ -2362,8 +2383,8 @@ class SILVerifier : public SILVerifierBase { if (builtinKind == BuiltinValueKind::CreateAsyncTask) { requireType(BI->getType(), _object(_tuple(_nativeObject, _rawPointer)), "result of createAsyncTask"); - require(arguments.size() == 5, - "createAsyncTask expects five arguments"); + require(arguments.size() == 6, + "createAsyncTask expects six arguments"); requireType(arguments[0]->getType(), _object(_swiftInt), "first argument of createAsyncTask"); requireType(arguments[1]->getType(), _object(_optional(_executor)), @@ -2372,7 +2393,9 @@ class SILVerifier : public SILVerifierBase { "third argument of createAsyncTask"); requireType(arguments[3]->getType(), _object(_optional(_executor)), "fourth argument of createAsyncTask"); - auto fnType = requireObjectType(SILFunctionType, arguments[4], + requireType(arguments[4]->getType(), _object(_optional(_taskExecutor)), + "fifth argument of createAsyncTask"); + auto fnType = requireObjectType(SILFunctionType, arguments[5], "result of createAsyncTask"); auto expectedExtInfo = SILExtInfoBuilder().withAsync(true).withSendable(true).build(); @@ -2655,6 +2678,54 @@ class SILVerifier : public SILVerifierBase { "ownership"); } + void checkExtendLifetimeInst(ExtendLifetimeInst *I) { + require(!I->getOperand()->getType().isTrivial(*I->getFunction()), + "Source value should be non-trivial"); + require(F.hasOwnership(), + "extend_lifetime is only valid in functions with qualified " + "ownership"); + require(getDeadEndBlocks().isDeadEnd(I->getParent()), + "extend_lifetime in non-dead-end!?"); + auto value = I->getOperand(); + LinearLiveness linearLiveness(value, + LinearLiveness::DoNotIncludeExtensions); + linearLiveness.compute(); + auto &liveness = linearLiveness.getLiveness(); + require(!liveness.isWithinBoundary(I), + "extend_lifetime use within unextended linear liveness boundary!?"); + PrunedLivenessBoundary boundary; + liveness.computeBoundary(boundary); + BasicBlockSet boundaryEdgeTargets(value->getFunction()); + for (auto *edge : boundary.boundaryEdges) { + boundaryEdgeTargets.insert(edge); + } + BasicBlockSet deadDefBlocks(value->getFunction()); + for (auto *def : boundary.deadDefs) { + deadDefBlocks.insert(def->getParentBlock()); + } + BasicBlockSet lastUserBlocks(value->getFunction()); + for (auto *user : boundary.lastUsers) { + lastUserBlocks.insert(user->getParent()); + } + BasicBlockWorklist worklist(value->getFunction()); + worklist.push(I->getParent()); + while (auto *block = worklist.pop()) { + if (boundaryEdgeTargets.contains(block)) { + // The backwards walk reached a boundary edge; this is the correct + // behavior being checked for. + continue; + } + require(!lastUserBlocks.contains(block), + "extend_lifetime after last user block"); + require(liveness.getBlockLiveness(block) != + PrunedLiveBlocks::IsLive::LiveOut, + "extend_lifetime in a live-out block"); + for (auto *predecessor : block->getPredecessorBlocks()) { + worklist.pushIfNotVisited(predecessor); + } + } + } + void checkUncheckedValueCastInst(UncheckedValueCastInst *) { require( F.hasOwnership(), @@ -7149,7 +7220,7 @@ class SILVerifier : public SILVerifierBase { void verify(bool isCompleteOSSA) { if (!isCompleteOSSA || !F.getModule().getOptions().OSSAVerifyComplete) { - DEBlocks = std::make_unique(const_cast(&F)); + DEBlocks = std::make_shared(const_cast(&F)); } visitSILFunction(const_cast(&F)); } diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index bcbe3332560a9..982760fc61608 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -1539,6 +1539,9 @@ enum class CreateTaskOptions { /// The builtin has a non-optional TaskExecutor argument. TaskExecutor = 0x8, + + /// The builtin has a non-optional consuming TaskExecutor argument. + TaskExecutorConsuming = 0x10, // FIXME does this make sense....? }; /// Emit SIL for the various createAsyncTask builtins. @@ -1595,7 +1598,7 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc, } }(); - ManagedValue taskExecutor = [&] { + ManagedValue taskExecutorDeprecated = [&] { if (options & CreateTaskOptions::OptionalEverything) { return nextArg().getAsSingleValue(SGF); } else if (options & CreateTaskOptions::TaskExecutor) { @@ -1604,6 +1607,18 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc, return emitOptionalNone(ctx.TheExecutorType); } }(); + ManagedValue taskExecutorConsuming = [&] { + if (options & CreateTaskOptions::OptionalEverything) { + return nextArg().getAsSingleValue(SGF); + } else if (options & CreateTaskOptions::TaskExecutorConsuming) { // TODO: do we even need this branch, we're not using the flag + return emitOptionalSome(nextArg()); + } else { + auto theTaskExecutorType = + ctx.getProtocol(KnownProtocolKind::TaskExecutor) + ->getDeclaredInterfaceType(); + return emitOptionalNone(theTaskExecutorType->getCanonicalType()); + } + }(); auto functionValue = [&] { // No reabstraction required. @@ -1659,7 +1674,8 @@ static ManagedValue emitCreateAsyncTask(SILGenFunction &SGF, SILLocation loc, flags.getUnmanagedValue(), initialExecutor.getUnmanagedValue(), taskGroup.getUnmanagedValue(), - taskExecutor.getUnmanagedValue(), + taskExecutorDeprecated.getUnmanagedValue(), + taskExecutorConsuming.forward(SGF), functionValue.forward(SGF) }; diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index aa2234aa9efcc..773bff7eca002 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -2601,6 +2601,7 @@ CONSTANT_TRANSLATION(DestroyValueInst, Ignored) CONSTANT_TRANSLATION(EndAccessInst, Ignored) CONSTANT_TRANSLATION(EndBorrowInst, Ignored) CONSTANT_TRANSLATION(EndLifetimeInst, Ignored) +CONSTANT_TRANSLATION(ExtendLifetimeInst, Ignored) CONSTANT_TRANSLATION(EndUnpairedAccessInst, Ignored) CONSTANT_TRANSLATION(HopToExecutorInst, Ignored) CONSTANT_TRANSLATION(InjectEnumAddrInst, Ignored) diff --git a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp index dd76d6b05a04a..6e1834b476a8e 100644 --- a/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp +++ b/lib/SILOptimizer/Mandatory/ConsumeOperatorCopyableAddressesChecker.cpp @@ -544,6 +544,7 @@ namespace { /// and the compiler emits assigns when it reinitializes vars this early in the /// pipeline. struct ClosureArgDataflowState { + ASTContext &C; SmallVector livenessWorklist; SmallVector consumingWorklist; MultiDefPrunedLiveness livenessForConsumes; @@ -551,13 +552,15 @@ struct ClosureArgDataflowState { public: ClosureArgDataflowState(SILFunction *function, UseState &useState) - : livenessForConsumes(function), useState(useState) {} + : C(function->getASTContext()), + livenessForConsumes(function), useState(useState) {} bool process( SILArgument *arg, ClosureOperandState &state, SmallBlotSetVector &postDominatingConsumingUsers); private: + /// Perform our liveness dataflow. Returns true if we found any liveness uses /// at all. These we will need to error upon. bool performLivenessDataflow(const BasicBlockSet &initBlocks, @@ -719,7 +722,7 @@ void ClosureArgDataflowState::classifyUses(BasicBlockSet &initBlocks, for (auto *user : useState.inits) { if (upwardScanForInit(user, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found init block at: " << *user); + LLVM_DEBUG(llvm::dbgs() << " Found init block during classifyUses at: " << *user); livenessForConsumes.initializeDef(user); initBlocks.insert(user->getParent()); } @@ -727,7 +730,7 @@ void ClosureArgDataflowState::classifyUses(BasicBlockSet &initBlocks, for (auto *user : useState.livenessUses) { if (upwardScanForUseOut(user, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found use block at: " << *user); + LLVM_DEBUG(llvm::dbgs() << " Found use block during classifyUses at: " << *user); livenessBlocks.insert(user->getParent()); livenessWorklist.push_back(user); } @@ -742,7 +745,7 @@ void ClosureArgDataflowState::classifyUses(BasicBlockSet &initBlocks, assert(iter != useState.destroyToIndexMap.end()); if (upwardScanForDestroys(destroy, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found destroy block at: " << *destroy); + LLVM_DEBUG(llvm::dbgs() << " Found destroy block during classifyUses at: " << *destroy); consumingBlocks.insert(destroy->getParent()); consumingWorklist.push_back(destroy); } @@ -755,8 +758,17 @@ void ClosureArgDataflowState::classifyUses(BasicBlockSet &initBlocks, auto iter = useState.reinitToIndexMap.find(reinit); assert(iter != useState.reinitToIndexMap.end()); + // TODO: Reinitialization analysis is currently incomplete and leads + // to miscompiles. Treat reinitializations as regular uses for now. + if (!C.LangOpts.hasFeature(Feature::ReinitializeConsumeInMultiBlockDefer)) { + LLVM_DEBUG(llvm::dbgs() << " Treating reinit as use block during classifyUses at: " << *reinit); + livenessBlocks.insert(reinit->getParent()); + livenessWorklist.push_back(reinit); + continue; + } + if (upwardScanForDestroys(reinit, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found reinit block at: " << *reinit); + LLVM_DEBUG(llvm::dbgs() << " Found reinit block during classifyUses at: " << *reinit); consumingBlocks.insert(reinit->getParent()); consumingWorklist.push_back(reinit); } @@ -823,31 +835,38 @@ bool ClosureArgDataflowState::process( // parameter. We are going to change it to be an out parameter and eliminate // these when we clone the closure. if (performConsumingDataflow(initBlocks, consumingBlocks)) { + LLVM_DEBUG(llvm::dbgs() << "found single consuming use!\n"); + // Before we do anything, make sure our argument has at least one single // debug_value user. If we have many we can't handle it since something in // SILGen is emitting weird code. Our tests will ensure that SILGen does not // diverge by mistake. So we are really just being careful. if (hasMoreThanOneDebugUse(address)) { // Failing b/c more than one debug use! + LLVM_DEBUG(llvm::dbgs() << "...but argument has more than one debug use!\n"); return false; } //!!! FIXME: Why? - // auto *frontBlock = &*fn->begin(); - // livenessForConsumes.initializeDefBlock(frontBlock); + //auto *frontBlock = &*fn->begin(); + //livenessForConsumes.initializeDef(address); - for (unsigned i : indices(livenessWorklist)) { - if (auto *ptr = livenessWorklist[i]) { + for (unsigned i : indices(consumingWorklist)) { + if (auto *ptr = consumingWorklist[i]) { + LLVM_DEBUG(llvm::dbgs() << "liveness for consume: " << *ptr); state.pairedConsumingInsts.push_back(ptr); - livenessForConsumes.updateForUse(ptr, true /*is lifetime ending*/); + //livenessForConsumes.updateForUse(ptr, true /*is lifetime ending*/); } } // If our consumes do not have a linear lifetime, bail. We will error on the // move being unknown. for (auto *ptr : state.pairedConsumingInsts) { - if (livenessForConsumes.isWithinBoundary(ptr)) + /*if (livenessForConsumes.isWithinBoundary(ptr)) { + LLVM_DEBUG(llvm::dbgs() << "consuming inst within boundary; bailing: " + << *ptr); return false; + }*/ postDominatingConsumingUsers.insert(ptr); } state.result = DownwardScanResult::ClosureConsume; @@ -1835,7 +1854,7 @@ void DataflowState::init() { // mark this as an "init block". for (auto *init : useState.inits) { if (upwardScanForInit(init, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found use block at: " << *init); + LLVM_DEBUG(llvm::dbgs() << " Found use block during DataflowState::init at: " << *init); initBlocks.insert(init->getParent()); } } @@ -1843,7 +1862,7 @@ void DataflowState::init() { // Then go through all normal uses and do upwardScanForUseOut. for (auto *user : useState.livenessUses) { if (upwardScanForUseOut(user, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found liveness block at: " << *user); + LLVM_DEBUG(llvm::dbgs() << " Found liveness block during DataflowState::init at: " << *user); useBlocks[user->getParent()] = user; } } @@ -1860,7 +1879,7 @@ void DataflowState::init() { assert(iter != useState.destroyToIndexMap.end()); if (upwardScanForDestroys(destroy, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found destroy block at: " << *destroy); + LLVM_DEBUG(llvm::dbgs() << " Found destroy block during DataflowState::init at: " << *destroy); destroyBlocks[destroy->getParent()] = destroy; } } @@ -1876,7 +1895,7 @@ void DataflowState::init() { assert(iter != useState.reinitToIndexMap.end()); if (upwardScanForDestroys(reinit, useState)) { - LLVM_DEBUG(llvm::dbgs() << " Found reinit block at: " << *reinit); + LLVM_DEBUG(llvm::dbgs() << " Found reinit block during DataflowState::init at: " << *reinit); reinitBlocks[reinit->getParent()] = reinit; } } @@ -1896,14 +1915,14 @@ void DataflowState::init() { case DownwardScanResult::ClosureUse: if (upwardScanForUseOut(user, useState)) { LLVM_DEBUG(llvm::dbgs() - << " Found closure liveness block at: " << *user); + << " Found closure liveness block during DataflowState::init at: " << *user); closureUseBlocks[user->getParent()] = &state; } break; case DownwardScanResult::ClosureConsume: if (upwardScanForDestroys(user, useState)) { LLVM_DEBUG(llvm::dbgs() - << " Found closure consuming block at: " << *user); + << " Found closure consuming block during DataflowState::init at: " << *user); closureConsumeBlocks[user->getParent()] = use; } break; @@ -2019,20 +2038,20 @@ void ConsumeOperatorCopyableAddressesChecker::cloneDeferCalleeAndRewriteUses( bool ConsumeOperatorCopyableAddressesChecker::performClosureDataflow( Operand *callerOperand, ClosureOperandState &calleeOperandState) { auto fas = FullApplySite::isa(callerOperand->getUser()); - auto *func = fas.getCalleeFunction(); + auto *callee = fas.getCalleeFunction(); auto *address = - func->begin()->getArgument(fas.getCalleeArgIndex(*callerOperand)); + callee->begin()->getArgument(fas.getCalleeArgIndex(*callerOperand)); LLVM_DEBUG(llvm::dbgs() << "Performing closure dataflow on caller use: " << *callerOperand->getUser()); - LLVM_DEBUG(llvm::dbgs() << " Callee: " << func->getName() << '\n'); + LLVM_DEBUG(llvm::dbgs() << " Callee: " << callee->getName() << '\n'); LLVM_DEBUG(llvm::dbgs() << " Callee Argument: " << *address); // We emit an end closure dataflow to make it easier when reading debug output // to make it easy to see when we have returned to analyzing the caller. SWIFT_DEFER { LLVM_DEBUG(llvm::dbgs() << "Finished performing closure dataflow on Callee: " - << func->getName() << '\n';); + << callee->getName() << '\n';); }; auto accessPathWithBase = AccessPathWithBase::compute(address); auto accessPath = accessPathWithBase.accessPath; @@ -2053,10 +2072,10 @@ bool ConsumeOperatorCopyableAddressesChecker::performClosureDataflow( GatherClosureUseVisitor visitor(closureUseState); SWIFT_DEFER { visitor.clear(); }; visitor.reset(address); - if (!visitAccessPathUses(visitor, accessPath, fn)) + if (!visitAccessPathUses(visitor, accessPath, callee)) return false; - ClosureArgDataflowState closureUseDataflowState(fn, closureUseState); + ClosureArgDataflowState closureUseDataflowState(callee, closureUseState); return closureUseDataflowState.process(address, calleeOperandState, closureConsumes); } diff --git a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp index a623062a06641..d984b1093adc4 100644 --- a/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp +++ b/lib/SILOptimizer/Mandatory/OwnershipModelEliminator.cpp @@ -164,6 +164,10 @@ struct OwnershipModelEliminatorVisitor eraseInstruction(eli); return true; } + bool visitExtendLifetimeInst(ExtendLifetimeInst *eli) { + eraseInstruction(eli); + return true; + } bool visitUncheckedOwnershipConversionInst( UncheckedOwnershipConversionInst *uoci) { eraseInstructionAndRAUW(uoci, uoci->getOperand()); diff --git a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp index f91c6f90caf9f..c2d25b39dbf60 100644 --- a/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadCodeElimination.cpp @@ -63,6 +63,11 @@ static bool seemsUseful(SILInstruction *I) { if (I->mayHaveSideEffects()) return true; + if (llvm::any_of(I->getResults(), + [](auto result) { return result->isLexical(); })) { + return true; + } + if (auto *BI = dyn_cast(I)) { // Although the onFastPath builtin has no side-effects we don't want to // remove it. diff --git a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp index 353dd584f8971..1c90f1c07d58c 100644 --- a/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp +++ b/lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp @@ -301,6 +301,7 @@ static bool hasOpaqueArchetype(TypeExpansionContext context, case SILInstructionKind::MarkUnresolvedMoveAddrInst: case SILInstructionKind::DestroyAddrInst: case SILInstructionKind::EndLifetimeInst: + case SILInstructionKind::ExtendLifetimeInst: case SILInstructionKind::InjectEnumAddrInst: case SILInstructionKind::DeinitExistentialAddrInst: case SILInstructionKind::DeinitExistentialValueInst: diff --git a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp index 7aae2ed069e80..8db93617a9612 100644 --- a/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp +++ b/lib/SILOptimizer/Utils/CanonicalizeOSSALifetime.cpp @@ -265,7 +265,7 @@ void CanonicalizeOSSALifetime::extendLivenessToDeinitBarriers() { findDestroysOutsideBoundary(outsideDestroys); // OSSALifetimeCompletion: With complete lifetimes, creating completeLiveness - // and using it to visiti unreachable lifetime ends should be deleted. + // and using it to visit unreachable lifetime ends should be deleted. SmallVector discoveredBlocks(this->discoveredBlocks); SSAPrunedLiveness completeLiveness(*liveness, &discoveredBlocks); @@ -273,10 +273,12 @@ void CanonicalizeOSSALifetime::extendLivenessToDeinitBarriers() { completeLiveness.updateForUse(end, /*lifetimeEnding*/ true); } - OSSALifetimeCompletion::visitUnreachableLifetimeEnds( + OSSALifetimeCompletion::visitAvailabilityBoundary( getCurrentDef(), OSSALifetimeCompletion::DoNotAllowLeaks, - completeLiveness, [&](auto *unreachable) { - recordUnreachableLifetimeEnd(unreachable); + completeLiveness, [&](auto *unreachable, auto end) { + if (end == OSSALifetimeCompletion::LifetimeEnd::Boundary) { + recordUnreachableLifetimeEnd(unreachable); + } unreachable->visitPriorInstructions([&](auto *inst) { liveness->extendToNonUse(inst); return true; @@ -674,7 +676,7 @@ void CanonicalizeOSSALifetime::visitExtendedUnconsumedBoundary( // Add "the instruction(s) before the terminator" of the predecessor to // liveness. predecessor->getTerminator()->visitPriorInstructions([&](auto *inst) { - visitor(inst, PrunedLiveness::LifetimeEnding::NonUse()); + visitor(inst, PrunedLiveness::LifetimeEnding::Value::NonUse); return true; }); } @@ -688,7 +690,7 @@ void CanonicalizeOSSALifetime::visitExtendedUnconsumedBoundary( // hoisting it would avoid a copy. if (consumedAtExitBlocks.contains(block)) continue; - visitor(destroy, PrunedLiveness::LifetimeEnding::Ending()); + visitor(destroy, PrunedLiveness::LifetimeEnding::Value::Ending); } } diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index 541c7667236b8..d5360299a6918 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -858,6 +858,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::GlobalAddrInst: case SILInstructionKind::BaseAddrForOffsetInst: case SILInstructionKind::EndLifetimeInst: + case SILInstructionKind::ExtendLifetimeInst: case SILInstructionKind::UncheckedOwnershipConversionInst: case SILInstructionKind::BindMemoryInst: case SILInstructionKind::RebindMemoryInst: diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index dff2978aecea6..c9ece81dcf7e2 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -355,6 +355,45 @@ static bool buildObjCKeyPathString(KeyPathExpr *E, return true; } +/// Since a cast to an optional will consume a noncopyable type, check to see +/// if injecting the value into an optional here will potentially be confusing. +static bool willHaveConfusingConsumption(Type type, + ConstraintLocatorBuilder locator, + ConstraintSystem &cs) { + assert(type); + if (!type->isNoncopyable()) + return false; /// If it's a copyable type, there's no confusion. + + auto loc = cs.getConstraintLocator(locator); + if (!loc) + return true; + + auto path = loc->getPath(); + if (path.empty()) + return true; + + switch (loc->getPath().back().getKind()) { + case ConstraintLocator::FunctionResult: + case ConstraintLocator::ClosureResult: + case ConstraintLocator::ClosureBody: + case ConstraintLocator::ContextualType: + case ConstraintLocator::CoercionOperand: + return false; // These last-uses won't be confused for borrowing. + + case ConstraintLocator::ApplyArgToParam: { + auto argLoc = loc->castLastElementTo(); + auto paramFlags = argLoc.getParameterFlags(); + if (paramFlags.getOwnershipSpecifier() == ParamSpecifier::Consuming) + return false; // Parameter already declares 'consuming'. + + return true; + } + + default: + return true; + } +} + namespace { /// Rewrites an expression by applying the solution of a constraint @@ -3241,10 +3280,12 @@ namespace { } private: - /// A list of "suspicious" optional injections that come from - /// forced downcasts. + /// A list of "suspicious" optional injections. SmallVector SuspiciousOptionalInjections; + /// A list of implicit coercions of noncopyable types. + SmallVector ConsumingCoercions; + /// Create a member reference to the given constructor. Expr *applyCtorRefExpr(Expr *expr, Expr *base, SourceLoc dotLoc, DeclNameLoc nameLoc, bool implicit, @@ -4466,9 +4507,9 @@ namespace { if (choice == 0) { // Convert the subexpression. Expr *sub = expr->getSubExpr(); - - sub = solution.coerceToType(sub, expr->getCastType(), - cs.getConstraintLocator(sub)); + auto subLoc = + cs.getConstraintLocator(sub, ConstraintLocator::CoercionOperand); + sub = solution.coerceToType(sub, expr->getCastType(), subLoc); if (!sub) return nullptr; @@ -5516,41 +5557,69 @@ namespace { assert(OpenedExistentials.empty()); auto &ctx = cs.getASTContext(); + auto *module = dc->getParentModule(); // Look at all of the suspicious optional injections for (auto injection : SuspiciousOptionalInjections) { - auto *cast = findForcedDowncast(ctx, injection->getSubExpr()); - if (!cast) - continue; - - if (isa(injection->getSubExpr())) - continue; + if (auto *cast = findForcedDowncast(ctx, injection->getSubExpr())) { + if (!isa(injection->getSubExpr())) { + ctx.Diags.diagnose( + injection->getLoc(), diag::inject_forced_downcast, + cs.getType(injection->getSubExpr())->getRValueType()); + auto exclaimLoc = cast->getExclaimLoc(); + ctx.Diags + .diagnose(exclaimLoc, diag::forced_to_conditional_downcast, + cs.getType(injection)->getOptionalObjectType()) + .fixItReplace(exclaimLoc, "?"); + ctx.Diags + .diagnose(cast->getStartLoc(), + diag::silence_inject_forced_downcast) + .fixItInsert(cast->getStartLoc(), "(") + .fixItInsertAfter(cast->getEndLoc(), ")"); + } + } + } - ctx.Diags.diagnose( - injection->getLoc(), diag::inject_forced_downcast, - cs.getType(injection->getSubExpr())->getRValueType()); - auto exclaimLoc = cast->getExclaimLoc(); + // Diagnose the implicit coercions of noncopyable values that happen in + // a context where it isn't "obviously" consuming already. + for (auto *coercion : ConsumingCoercions) { + assert(coercion->isImplicit()); ctx.Diags - .diagnose(exclaimLoc, diag::forced_to_conditional_downcast, - cs.getType(injection)->getOptionalObjectType()) - .fixItReplace(exclaimLoc, "?"); + .diagnose(coercion->getLoc(), + diag::consume_expression_needed_for_cast, + cs.getType(coercion)); ctx.Diags - .diagnose(cast->getStartLoc(), diag::silence_inject_forced_downcast) - .fixItInsert(cast->getStartLoc(), "(") - .fixItInsertAfter(cast->getEndLoc(), ")"); + .diagnose(coercion->getLoc(), + diag::add_consume_to_silence) + .fixItInsert(coercion->getStartLoc(), "consume "); } } /// Diagnose an optional injection that is probably not what the - /// user wanted, because it comes from a forced downcast. - void diagnoseOptionalInjection(InjectIntoOptionalExpr *injection) { + /// user wanted, because it comes from a forced downcast, or from an + /// implicitly consumed noncopyable type. + void diagnoseOptionalInjection(InjectIntoOptionalExpr *injection, + ConstraintLocatorBuilder locator) { // Check whether we have a forced downcast. - auto *cast = - findForcedDowncast(cs.getASTContext(), injection->getSubExpr()); - if (!cast) - return; - - SuspiciousOptionalInjections.push_back(injection); + if (findForcedDowncast(cs.getASTContext(), injection->getSubExpr())) + SuspiciousOptionalInjections.push_back(injection); + + /// Check if it needs an explicit consume, due to this being a cast. + auto *module = dc->getParentModule(); + auto origType = cs.getType(injection->getSubExpr()); + if (willHaveConfusingConsumption(origType, locator, cs) && + canAddExplicitConsume(module, injection->getSubExpr())) + ConsumingCoercions.push_back(injection); + } + + void diagnoseExistentialErasureOf(Expr *fromExpr, Expr *toExpr, + ConstraintLocatorBuilder locator) { + auto *module = dc->getParentModule(); + auto fromType = cs.getType(fromExpr); + if (willHaveConfusingConsumption(fromType, locator, cs) && + canAddExplicitConsume(module, fromExpr)) { + ConsumingCoercions.push_back(toExpr); + } } }; } // end anonymous namespace @@ -5821,7 +5890,7 @@ Expr *ExprRewriter::coerceOptionalToOptional(Expr *expr, Type toType, while (diff--) { Type type = toOptionals[diff]; expr = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, type)); - diagnoseOptionalInjection(cast(expr)); + diagnoseOptionalInjection(cast(expr), locator); } return expr; @@ -6950,8 +7019,11 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, return coerceSuperclass(expr, toType); case ConversionRestrictionKind::Existential: - case ConversionRestrictionKind::MetatypeToExistentialMetatype: - return coerceExistential(expr, toType, locator); + case ConversionRestrictionKind::MetatypeToExistentialMetatype: { + auto coerced = coerceExistential(expr, toType, locator); + diagnoseExistentialErasureOf(expr, coerced, locator); + return coerced; + } case ConversionRestrictionKind::ClassMetatypeToAnyObject: { assert(ctx.LangOpts.EnableObjCInterop && @@ -6980,7 +7052,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, auto *result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, toType)); - diagnoseOptionalInjection(result); + diagnoseOptionalInjection(result, locator); return result; } @@ -7674,7 +7746,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (!expr) return nullptr; auto *result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(expr, toType)); - diagnoseOptionalInjection(result); + diagnoseOptionalInjection(result, locator); return result; } diff --git a/lib/Sema/CodeSynthesisDistributedActor.cpp b/lib/Sema/CodeSynthesisDistributedActor.cpp index e9d26da8a7fda..07c7ebe9e6851 100644 --- a/lib/Sema/CodeSynthesisDistributedActor.cpp +++ b/lib/Sema/CodeSynthesisDistributedActor.cpp @@ -692,7 +692,8 @@ static FuncDecl *createSameSignatureDistributedThunkDecl(DeclContext *DC, /*argumentNameLoc=*/SourceLoc(), funcParam->getArgumentName(), /*parameterNameLoc=*/SourceLoc(), paramName, DC); - paramDecl->setImplicit(true); + paramDecl->setImplicit(); + paramDecl->setSending(); paramDecl->setSpecifier(funcParam->getSpecifier()); paramDecl->setInterfaceType(funcParam->getInterfaceType()); diff --git a/lib/Sema/ImportResolution.cpp b/lib/Sema/ImportResolution.cpp index 8ffd8dadd5649..b3ee16614cf78 100644 --- a/lib/Sema/ImportResolution.cpp +++ b/lib/Sema/ImportResolution.cpp @@ -574,6 +574,10 @@ UnboundImport::UnboundImport(AttributedImport implicit) // MARK: Import validation (except for scoped imports) //===----------------------------------------------------------------------===// +ImportOptions getImportOptions(ImportDecl *ID) { + return ImportOptions(); +} + /// Create an UnboundImport for a user-written import declaration. UnboundImport::UnboundImport(ImportDecl *ID) : import(UnloadedImportedModule(ID->getImportPath(), ID->getImportKind()), @@ -1083,6 +1087,13 @@ CheckInconsistentAccessLevelOnImport::evaluate( return; auto otherAccessLevel = otherImport->getAccessLevel(); + + // Only report ambiguities with non-public imports as bare imports are + // public when this diagnostic is active. Do not report ambiguities + // between implicitly vs explicitly public. + if (otherAccessLevel == AccessLevel::Public) + return; + auto &diags = mod->getDiags(); { InFlightDiagnostic error = diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index cd55cee394ac3..789a6e02fc6b7 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -422,87 +422,11 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } void checkConsumeExpr(ConsumeExpr *consumeExpr) { - auto *subExpr = consumeExpr->getSubExpr(); - bool noncopyable = - subExpr->getType()->getCanonicalType()->isNoncopyable(); - - bool partial = false; - Expr *current = subExpr; - while (current) { - if (auto *dre = dyn_cast(current)) { - if (partial & !noncopyable) { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_partial_copyable); - return; - } - // The chain of member_ref_exprs and load_exprs terminates at a - // declref_expr. This is legal. - return; - } - // Look through loads. - if (auto *le = dyn_cast(current)) { - current = le->getSubExpr(); - continue; - } - auto *mre = dyn_cast(current); - if (mre) { - auto *vd = dyn_cast(mre->getMember().getDecl()); - if (!vd) { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_non_storage); - return; - } - partial = true; - AccessStrategy strategy = vd->getAccessStrategy( - mre->getAccessSemantics(), AccessKind::Read, - DC->getParentModule(), ResilienceExpansion::Minimal); - if (strategy.getKind() != AccessStrategy::Storage) { - if (noncopyable) { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_non_storage); - Ctx.Diags.diagnose( - mre->getLoc(), - diag::note_consume_expression_non_storage_property); - } else { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_partial_copyable); - } - return; - } - current = mre->getBase(); - continue; - } - auto *ce = dyn_cast(current); - if (ce) { - if (noncopyable) { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_non_storage); - Ctx.Diags.diagnose(ce->getLoc(), - diag::note_consume_expression_non_storage_call); - } else { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_partial_copyable); - } - return; - } - auto *se = dyn_cast(current); - if (se) { - if (noncopyable) { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_non_storage); - Ctx.Diags.diagnose( - se->getLoc(), - diag::note_consume_expression_non_storage_subscript); - } else { - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_partial_copyable); - } - return; - } - Ctx.Diags.diagnose(consumeExpr->getLoc(), - diag::consume_expression_not_passed_lvalue); - return; - } + auto diags = findSyntacticErrorForConsume(DC->getParentModule(), + consumeExpr->getLoc(), + consumeExpr->getSubExpr()); + for (auto &diag : diags) + diag.emit(Ctx); } void checkCopyExpr(CopyExpr *copyExpr) { @@ -1521,6 +1445,82 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC, } } +DeferredDiags swift::findSyntacticErrorForConsume( + ModuleDecl *module, SourceLoc loc, Expr *subExpr) { + assert(!isa(subExpr) && "operates on the sub-expr of a consume"); + + DeferredDiags result; + const bool noncopyable = + subExpr->getType()->getCanonicalType()->isNoncopyable(); + + bool partial = false; + Expr *current = subExpr; + while (current) { + if (auto *dre = dyn_cast(current)) { + if (partial & !noncopyable) + result.emplace_back(loc, diag::consume_expression_partial_copyable); + + // The chain of member_ref_exprs and load_exprs terminates at a + // declref_expr. This is legal. + break; + } + // Look through loads. + if (auto *le = dyn_cast(current)) { + current = le->getSubExpr(); + continue; + } + auto *mre = dyn_cast(current); + if (mre) { + auto *vd = dyn_cast(mre->getMember().getDecl()); + if (!vd) { + result.emplace_back(loc, diag::consume_expression_non_storage); + break; + } + partial = true; + AccessStrategy strategy = vd->getAccessStrategy( + mre->getAccessSemantics(), AccessKind::Read, + module, ResilienceExpansion::Minimal); + if (strategy.getKind() != AccessStrategy::Storage) { + if (noncopyable) { + result.emplace_back(loc, diag::consume_expression_non_storage); + result.emplace_back(mre->getLoc(), + diag::note_consume_expression_non_storage_property); + break; + } + result.emplace_back(loc, diag::consume_expression_partial_copyable); + break; + } + current = mre->getBase(); + continue; + } + auto *ce = dyn_cast(current); + if (ce) { + if (noncopyable) { + result.emplace_back(loc, diag::consume_expression_non_storage); + result.emplace_back(ce->getLoc(), + diag::note_consume_expression_non_storage_call); + break; + } + result.emplace_back(loc, diag::consume_expression_partial_copyable); + break; + } + auto *se = dyn_cast(current); + if (se) { + if (noncopyable) { + result.emplace_back(loc, diag::consume_expression_non_storage); + result.emplace_back(se->getLoc(), + diag::note_consume_expression_non_storage_subscript); + break; + } + result.emplace_back(loc, diag::consume_expression_partial_copyable); + break; + } + result.emplace_back(loc, diag::consume_expression_not_passed_lvalue); + break; + } + return result; +} + /// Diagnose recursive use of properties within their own accessors static void diagRecursivePropertyAccess(const Expr *E, const DeclContext *DC) { @@ -6730,3 +6730,9 @@ bool swift::diagnoseUnhandledThrowsInAsyncContext(DeclContext *dc, return false; } + +void DeferredDiag::emit(swift::ASTContext &ctx) { + assert(loc && "no loc... already emitted?"); + ctx.Diags.diagnose(loc, diag); + loc = SourceLoc(); +} diff --git a/lib/Sema/MiscDiagnostics.h b/lib/Sema/MiscDiagnostics.h index 1de84f2be8ae2..3eb78a468af3e 100644 --- a/lib/Sema/MiscDiagnostics.h +++ b/lib/Sema/MiscDiagnostics.h @@ -161,6 +161,29 @@ namespace swift { static bool shouldWalkIntoDeclInClosureContext(Decl *D); }; + // A simple, deferred diagnostic container. + struct DeferredDiag { + SourceLoc loc; + ZeroArgDiagnostic diag; + DeferredDiag(SourceLoc loc, ZeroArgDiagnostic diag) + : loc(loc), diag(diag) {} + + // Emits this diagnostic. + void emit(ASTContext &ctx); + }; + + using DeferredDiags = SmallVector; + + /// Search for syntactic errors in the given sub-expression of a ConsumeExpr, + /// collecting them without actually emitting them. + /// + /// \param loc corresponds to the location of the 'consume' for which + /// diagnostics should be collected, if any. + /// + /// \returns an empty collection if there are no errors. + DeferredDiags findSyntacticErrorForConsume(ModuleDecl *module, + SourceLoc loc, + Expr *subExpr); } // namespace swift #endif // SWIFT_SEMA_MISC_DIAGNOSTICS_H diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7c5b763d483aa..7ec53177561d9 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2317,6 +2317,10 @@ static Expr *lookThroughBridgeFromObjCCall(ASTContext &ctx, Expr *expr) { /// underlying forced downcast expression. ForcedCheckedCastExpr *swift::findForcedDowncast(ASTContext &ctx, Expr *expr) { expr = expr->getSemanticsProvidingExpr(); + + // Look through a consume, just in case. + if (auto consume = dyn_cast(expr)) + expr = consume->getSubExpr(); // Simple case: forced checked cast. if (auto forced = dyn_cast(expr)) { @@ -2368,6 +2372,18 @@ ForcedCheckedCastExpr *swift::findForcedDowncast(ASTContext &ctx, Expr *expr) { return nullptr; } +bool swift::canAddExplicitConsume(ModuleDecl *module, Expr *expr) { + expr = expr->getSemanticsProvidingExpr(); + + // Is it already wrapped in a `consume`? + if (isa(expr)) + return false; + + // Is this expression valid to wrap inside a `consume`? + auto diags = findSyntacticErrorForConsume(module, SourceLoc(), expr); + return diags.empty(); +} + void ConstraintSystem::forEachExpr( Expr *expr, llvm::function_ref callback) { struct ChildWalker : ASTWalker { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 45bc4fe02a972..2249b00ae36e6 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -5980,31 +5980,6 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { if (T->isInvalid()) return Action::SkipNode(); - // Arbitrary protocol constraints are OK on opaque types. - if (isa(T)) - return Action::SkipNode(); - - // Arbitrary protocol constraints are okay for 'any' types. - if (isa(T)) - return Action::SkipNode(); - - // Suppressed conformance needs to be within any/some. - if (auto inverse = dyn_cast(T)) { - // Find an enclosing protocol composition, if there is one, so we - // can insert 'any' before that. - SourceLoc anyLoc = inverse->getTildeLoc(); - if (!reprStack.empty()) { - if (isa(reprStack.back())) { - anyLoc = reprStack.back()->getStartLoc(); - } - } - - Ctx.Diags.diagnose(inverse->getTildeLoc(), diag::inverse_requires_any) - .highlight(inverse->getConstraint()->getSourceRange()) - .fixItInsert(anyLoc, "any "); - return Action::SkipNode(); - } - reprStack.push_back(T); auto *declRefTR = dyn_cast(T); @@ -6057,9 +6032,12 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { } private: - bool existentialNeedsParens(TypeRepr *parent) const { + /// Returns a Boolean value indicating whether the insertion of `any` before + /// a type representation with the given parent requires paretheses. + static bool anySyntaxNeedsParens(TypeRepr *parent) { switch (parent->getKind()) { case TypeReprKind::Optional: + case TypeReprKind::ImplicitlyUnwrappedOptional: case TypeReprKind::Protocol: return true; case TypeReprKind::Metatype: @@ -6074,7 +6052,6 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { case TypeReprKind::UnqualifiedIdent: case TypeReprKind::QualifiedIdent: case TypeReprKind::Dictionary: - case TypeReprKind::ImplicitlyUnwrappedOptional: case TypeReprKind::Inverse: case TypeReprKind::Tuple: case TypeReprKind::Fixed: @@ -6097,26 +6074,44 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { } void emitInsertAnyFixit(InFlightDiagnostic &diag, DeclRefTypeRepr *T) const { - TypeRepr *replaceRepr = T; + TypeRepr *replacementT = T; // Insert parens in expression context for '(any P).self' bool needsParens = (exprCount != 0); + + // Compute the replacement node (the node to which to apply `any`). if (reprStack.size() > 1) { - auto parentIt = reprStack.end() - 2; - needsParens = existentialNeedsParens(*parentIt); - - // Expand to include parenthesis before checking if the parent needs - // to be replaced. - while (parentIt != reprStack.begin() && - (*parentIt)->getWithoutParens() != *parentIt) - parentIt -= 1; - - // For existential metatypes, 'any' is applied to the metatype. - if ((*parentIt)->getKind() == TypeReprKind::Metatype) { - replaceRepr = *parentIt; - if (parentIt != reprStack.begin()) - needsParens = existentialNeedsParens(*(parentIt - 1)); + auto it = reprStack.end() - 1; + auto replacementIt = it; + + // Backtrack the stack and expand the replacement range to any parent + // inverses, compositions or `.Type` metatypes, skipping only parentheses. + // + // E.g. `(X & ~P).Type` → `any (X & ~P).Type`. + // ↑ + // We're here + do { + --it; + if ((*it)->isParenType()) { + continue; + } + + if (isa(*it) || isa(*it) || + isa(*it)) { + replacementIt = it; + continue; + } + + break; + } while (it != reprStack.begin()); + + // Whether parentheses are necessary is determined by the immediate parent + // of the replacement node. + if (replacementIt != reprStack.begin()) { + needsParens = anySyntaxNeedsParens(*(replacementIt - 1)); } + + replacementT = *replacementIt; } llvm::SmallString<64> fix; @@ -6124,13 +6119,49 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { llvm::raw_svector_ostream OS(fix); if (needsParens) OS << "("; - ExistentialTypeRepr existential(SourceLoc(), replaceRepr); + ExistentialTypeRepr existential(SourceLoc(), replacementT); existential.print(OS); if (needsParens) OS << ")"; } - diag.fixItReplace(replaceRepr->getSourceRange(), fix); + diag.fixItReplace(replacementT->getSourceRange(), fix); + } + + /// Returns a Boolean value indicating whether the type representation being + /// visited, assuming it is a constraint type demanding `any` or `some`, is + /// missing either keyword. + bool isAnyOrSomeMissing() const { + assert(isa(reprStack.back())); + + if (reprStack.size() < 2) { + return true; + } + + auto it = reprStack.end() - 1; + while (true) { + --it; + if (it == reprStack.begin()) { + break; + } + + // Look through parens, inverses, metatypes, and compositions. + if ((*it)->isParenType() || isa(*it) || + isa(*it) || isa(*it)) { + continue; + } + + // Look through '?' and '!' too; `any P?` et al. is diagnosed in the + // type resolver. + if (isa(*it) || + isa(*it)) { + continue; + } + + break; + } + + return !(isa(*it) || isa(*it)); } void checkDeclRefTypeRepr(DeclRefTypeRepr *T) const { @@ -6140,13 +6171,32 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { return; } + // Backtrack the stack, looking just through parentheses and metatypes. If + // we find an inverse (which always requires `any`), diagnose it specially. + if (reprStack.size() > 1) { + auto it = reprStack.end() - 2; + while (it != reprStack.begin() && + ((*it)->isParenType() || isa(*it))) { + --it; + continue; + } + + if (auto *inverse = dyn_cast(*it); + inverse && isAnyOrSomeMissing()) { + auto diag = Ctx.Diags.diagnose(inverse->getTildeLoc(), + diag::inverse_requires_any); + emitInsertAnyFixit(diag, T); + return; + } + } + auto *decl = T->getBoundDecl(); if (!decl) { return; } if (auto *proto = dyn_cast(decl)) { - if (proto->existentialRequiresAny()) { + if (proto->existentialRequiresAny() && isAnyOrSomeMissing()) { auto diag = Ctx.Diags.diagnose(T->getNameLoc(), diag::existential_requires_any, proto->getDeclaredInterfaceType(), @@ -6176,7 +6226,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker { if (auto *PCT = type->getAs()) diagnose |= !PCT->getInverses().empty(); - if (diagnose) { + if (diagnose && isAnyOrSomeMissing()) { auto diag = Ctx.Diags.diagnose( T->getNameLoc(), diag::existential_requires_any, alias->getDeclaredInterfaceType(), diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index dadf6344001a1..135640d62b139 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2258,6 +2258,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, UNARY_INSTRUCTION(ValueToBridgeObject) UNARY_INSTRUCTION(FixLifetime) UNARY_INSTRUCTION(EndLifetime) + UNARY_INSTRUCTION(ExtendLifetime) UNARY_INSTRUCTION(CopyBlock) UNARY_INSTRUCTION(LoadBorrow) UNARY_INSTRUCTION(EndInitLetRef) diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index ee2cfc72f88fe..c389311df45d8 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -334,6 +334,12 @@ static ValidationInfo validateControlBlock( LLVM_FALLTHROUGH; case 3: result.shortVersion = blobData.slice(0, scratch[2]); + + // If the format version doesn't match, give up after also getting the + // compiler version. This provides better diagnostics. + if (result.status != Status::Valid) + return result; + LLVM_FALLTHROUGH; case 2: case 1: diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index 5acf1b58a2441..015ec374f6e10 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -608,6 +608,21 @@ class ModuleFileSharedCore { return Dependencies; } + /// Returns the list of modules this module depends on. + ArrayRef getLinkLibraries() const { + return LinkLibraries; + } + + /// Does this module correspond to a framework. + bool isFramework() const { + return Bits.IsFramework; + } + + /// Does this module correspond to a static archive. + bool isStaticLibrary() const { + return Bits.IsStaticLibrary; + } + /// Returns \c true if this module file contains a section with incremental /// information. bool hasIncrementalInfo() const { return HasIncrementalInfo; } diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index eec82b46c9035..a87f09cdfbc06 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,8 +58,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 = - 875; // Add package field to SerializedKind_t +const uint16_t SWIFTMODULE_VERSION_MINOR = 877; // extend_lifetime instruction /// A standard hash seed used for all string hashes in a serialized module. /// @@ -862,11 +861,11 @@ namespace control_block { MODULE_NAME, TARGET, SDK_NAME, - SDK_VERSION, REVISION, - CHANNEL, IS_OSSA, ALLOWABLE_CLIENT_NAME, + CHANNEL, + SDK_VERSION, }; using MetadataLayout = BCRecordLayout< @@ -897,21 +896,11 @@ namespace control_block { BCBlob >; - using SDKVersionLayout = BCRecordLayout< - SDK_VERSION, - BCBlob - >; - using RevisionLayout = BCRecordLayout< REVISION, BCBlob >; - using ChannelLayout = BCRecordLayout< - CHANNEL, - BCBlob - >; - using IsOSSALayout = BCRecordLayout< IS_OSSA, BCFixed<1> @@ -921,6 +910,16 @@ namespace control_block { ALLOWABLE_CLIENT_NAME, BCBlob >; + + using ChannelLayout = BCRecordLayout< + CHANNEL, + BCBlob + >; + + using SDKVersionLayout = BCRecordLayout< + SDK_VERSION, + BCBlob + >; } /// The record types within the options block (a sub-block of the control diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index 543f0b558ce32..be657331dfecf 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -225,11 +225,28 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath, auto sourceFile = new (Ctx) SourceFile( *moduleDecl, SourceFileKind::Interface, bufferID, parsingOpts); moduleDecl->addAuxiliaryFile(*sourceFile); - std::vector ArgsRefs(Args.begin(), Args.end()); + std::vector compiledCandidatesRefs(compiledCandidates.begin(), + compiledCandidates.end()); + + // If this interface specified '-autolink-force-load', add it to the + // set of linked libraries for this module. + std::vector linkLibraries; + if (llvm::find(ArgsRefs, "-autolink-force-load") != ArgsRefs.end()) { + std::string linkName = realModuleName.str().str(); + auto linkNameArgIt = llvm::find(ArgsRefs, "-module-link-name"); + if (linkNameArgIt != ArgsRefs.end()) + linkName = *(linkNameArgIt+1); + linkLibraries.push_back({linkName, + isFramework ? LibraryKind::Framework : LibraryKind::Library, + true}); + } + bool isStatic = llvm::find(ArgsRefs, "-static") != ArgsRefs.end(); + Result = ModuleDependencyInfo::forSwiftInterfaceModule( - outputPathBase.str().str(), InPath, compiledCandidates, ArgsRefs, - PCMArgs, Hash, isFramework, {}, /*module-cache-key*/ ""); + outputPathBase.str().str(), InPath, compiledCandidatesRefs, + ArgsRefs, linkLibraries, PCMArgs, Hash, isFramework, isStatic, {}, + /*module-cache-key*/ ""); if (Ctx.CASOpts.EnableCaching) { std::vector clangDependencyFiles; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index d253072509890..534a1750a4c8b 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -834,11 +834,11 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(control_block, MODULE_NAME); BLOCK_RECORD(control_block, TARGET); BLOCK_RECORD(control_block, SDK_NAME); - BLOCK_RECORD(control_block, SDK_VERSION); BLOCK_RECORD(control_block, REVISION); - BLOCK_RECORD(control_block, CHANNEL); BLOCK_RECORD(control_block, IS_OSSA); BLOCK_RECORD(control_block, ALLOWABLE_CLIENT_NAME); + BLOCK_RECORD(control_block, CHANNEL); + BLOCK_RECORD(control_block, SDK_VERSION); BLOCK(OPTIONS_BLOCK); BLOCK_RECORD(options_block, SDK_PATH); diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 9832f6483a5ca..94eab6a24880f 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1542,6 +1542,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case SILInstructionKind::ValueToBridgeObjectInst: case SILInstructionKind::FixLifetimeInst: case SILInstructionKind::EndLifetimeInst: + case SILInstructionKind::ExtendLifetimeInst: case SILInstructionKind::CopyBlockInst: case SILInstructionKind::StrongReleaseInst: case SILInstructionKind::StrongRetainInst: diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 3bd010593d598..006fb055bd70c 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -499,11 +499,21 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, optionalModuleImports.push_back( ScannerImportStatementInfo(optionalImportedModule.str())); + std::vector linkLibraries; + { + linkLibraries.reserve(loadedModuleFile->getLinkLibraries().size()); + llvm::copy(loadedModuleFile->getLinkLibraries(), + std::back_inserter(linkLibraries)); + if (loadedModuleFile->isFramework()) + linkLibraries.push_back(LinkLibrary(loadedModuleFile->getName(), + LibraryKind::Framework)); + } + // Map the set of dependencies over to the "module dependencies". auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule( modulePath.str(), moduleDocPath, sourceInfoPath, moduleImports, - optionalModuleImports, importedHeader, isFramework, - /*module-cache-key*/ ""); + optionalModuleImports, linkLibraries, importedHeader, isFramework, + loadedModuleFile->isStaticLibrary(), /*module-cache-key*/ ""); return std::move(dependencies); } diff --git a/stdlib/cmake/modules/AddSwiftStdlib.cmake b/stdlib/cmake/modules/AddSwiftStdlib.cmake index e18c712f099fd..4b06963fb4972 100644 --- a/stdlib/cmake/modules/AddSwiftStdlib.cmake +++ b/stdlib/cmake/modules/AddSwiftStdlib.cmake @@ -1757,6 +1757,9 @@ endfunction() # SWIFT_MODULE_DEPENDS_WASI # Swift modules this library depends on when built for WASI. # +# SWIFT_MODULE_DEPENDS_ANDROID +# Swift modules this library depends on when built for Android. +# # FRAMEWORK_DEPENDS # System frameworks this library depends on. # @@ -1919,6 +1922,7 @@ function(add_swift_target_library name) SWIFT_COMPILE_FLAGS_XROS SWIFT_COMPILE_FLAGS_LINUX SWIFT_MODULE_DEPENDS + SWIFT_MODULE_DEPENDS_ANDROID SWIFT_MODULE_DEPENDS_CYGWIN SWIFT_MODULE_DEPENDS_FREEBSD SWIFT_MODULE_DEPENDS_FREESTANDING @@ -2146,12 +2150,15 @@ function(add_swift_target_library name) elseif(sdk STREQUAL "OPENBSD") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_OPENBSD}) - elseif(sdk STREQUAL "LINUX" OR sdk STREQUAL "ANDROID") + elseif(sdk STREQUAL "LINUX") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_LINUX}) elseif(sdk STREQUAL "LINUX_STATIC") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_LINUX_STATIC}) + elseif(sdk STREQUAL "ANDROID") + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_ANDROID}) elseif(sdk STREQUAL "CYGWIN") list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_CYGWIN}) @@ -3005,6 +3012,7 @@ function(add_swift_target_executable name) DEPENDS LINK_LIBRARIES SWIFT_MODULE_DEPENDS + SWIFT_MODULE_DEPENDS_ANDROID SWIFT_MODULE_DEPENDS_CYGWIN SWIFT_MODULE_DEPENDS_FREEBSD SWIFT_MODULE_DEPENDS_FREESTANDING @@ -3118,12 +3126,15 @@ function(add_swift_target_executable name) elseif(sdk STREQUAL "OPENBSD") list(APPEND swiftexe_module_depends_flattened ${SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS_OPENBSD}) - elseif(sdk STREQUAL "LINUX" OR sdk STREQUAL "ANDROID") + elseif(sdk STREQUAL "LINUX") list(APPEND swiftexe_module_depends_flattened ${SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS_LINUX}) elseif(sdk STREQUAL "LINUX_STATIC") list(APPEND swiftexe_module_depends_flattened ${SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS_LINUX_STATIC}) + elseif(sdk STREQUAL "ANDROID") + list(APPEND swiftexe_module_depends_flattened + ${SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS_ANDROID}) elseif(sdk STREQUAL "CYGWIN") list(APPEND swiftexe_module_depends_flattened ${SWIFTEXE_TARGET_SWIFT_MODULE_DEPENDS_CYGWIN}) diff --git a/stdlib/private/RuntimeUnittest/CMakeLists.txt b/stdlib/private/RuntimeUnittest/CMakeLists.txt index e23d3a155c869..992f90ad33d2a 100644 --- a/stdlib/private/RuntimeUnittest/CMakeLists.txt +++ b/stdlib/private/RuntimeUnittest/CMakeLists.txt @@ -8,6 +8,7 @@ add_swift_target_library(swiftRuntimeUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES ExclusivityTests.cpp SWIFT_MODULE_DEPENDS StdlibUnittest + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt b/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt index 12fc845a887ef..e063340a4e638 100644 --- a/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt +++ b/stdlib/private/StdlibCollectionUnittest/CMakeLists.txt @@ -19,6 +19,7 @@ add_swift_target_library(swiftStdlibCollectionUnittest ${SWIFT_STDLIB_LIBRARY_BU WriteBackMutableSlice.swift SWIFT_MODULE_DEPENDS StdlibUnittest + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/private/StdlibUnicodeUnittest/CMakeLists.txt b/stdlib/private/StdlibUnicodeUnittest/CMakeLists.txt index 6914812465a54..44920a8f62fa8 100644 --- a/stdlib/private/StdlibUnicodeUnittest/CMakeLists.txt +++ b/stdlib/private/StdlibUnicodeUnittest/CMakeLists.txt @@ -10,6 +10,7 @@ add_swift_target_library(swiftStdlibUnicodeUnittest ${SWIFT_STDLIB_LIBRARY_BUILD WordBreaking.swift SWIFT_MODULE_DEPENDS StdlibUnittest + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/private/StdlibUnittest/CMakeLists.txt b/stdlib/private/StdlibUnittest/CMakeLists.txt index 711ee520376c0..dfcbb067d8ff7 100644 --- a/stdlib/private/StdlibUnittest/CMakeLists.txt +++ b/stdlib/private/StdlibUnittest/CMakeLists.txt @@ -62,6 +62,7 @@ add_swift_target_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} SWIFT_MODULE_DEPENDS_XROS ${swift_stdlib_unittest_darwin_dependencies} SWIFT_MODULE_DEPENDS_MACCATALYST ${swift_stdlib_unittest_darwin_dependencies} SWIFT_MODULE_DEPENDS_FREESTANDING "${SWIFT_FREESTANDING_TEST_DEPENDENCIES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index d3aab9cd252fd..0a94d4da05ffb 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -45,6 +45,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift index 9b5ef8be2e81a..3afef278d4cd5 100644 --- a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift +++ b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift @@ -18,6 +18,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift b/stdlib/private/StdlibUnittest/StdlibUnittest.swift index 11e60e1dbad41..55171a7114414 100644 --- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift +++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift @@ -24,6 +24,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/SwiftPrivate/CMakeLists.txt b/stdlib/private/SwiftPrivate/CMakeLists.txt index 480781284ebb7..1e0bbfea54e13 100644 --- a/stdlib/private/SwiftPrivate/CMakeLists.txt +++ b/stdlib/private/SwiftPrivate/CMakeLists.txt @@ -27,6 +27,7 @@ add_swift_target_library(swiftSwiftPrivate ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I SWIFT_MODULE_DEPENDS_WATCHOS ${swift_swiftprivate_darwin_depencencies} SWIFT_MODULE_DEPENDS_MACCATALYST ${swift_swiftprivate_darwin_depencencies} SWIFT_MODULE_DEPENDS_FREESTANDING "${SWIFT_FREESTANDING_TEST_DEPENDENCIES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl SWIFT_MODULE_DEPENDS_FREEBSD Glibc diff --git a/stdlib/private/SwiftPrivate/IO.swift b/stdlib/private/SwiftPrivate/IO.swift index 9e0f3c5ddfe75..e8bf2c659fa0d 100644 --- a/stdlib/private/SwiftPrivate/IO.swift +++ b/stdlib/private/SwiftPrivate/IO.swift @@ -23,6 +23,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif canImport(WASILibc) import WASILibc #endif diff --git a/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt b/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt index db317dcdf6882..927eae491caa5 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt +++ b/stdlib/private/SwiftPrivateLibcExtras/CMakeLists.txt @@ -38,6 +38,7 @@ add_swift_target_library(swiftSwiftPrivateLibcExtras ${SWIFT_STDLIB_LIBRARY_BUIL SWIFT_MODULE_DEPENDS_XROS ${swift_private_libc_extras_darwin_depencencies} SWIFT_MODULE_DEPENDS_MACCATALYST ${swift_private_libc_extras_darwin_depencencies} SWIFT_MODULE_DEPENDS_FREESTANDING "${SWIFT_FREESTANDING_TEST_DEPENDENCIES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl SWIFT_MODULE_DEPENDS_FREEBSD Glibc diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift index 47e8972a276c2..ad15200ac7518 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift @@ -17,6 +17,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift index 146cc404931e2..27ee869f70609 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift @@ -17,6 +17,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt b/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt index d0a791ad8a47f..4002af837db10 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt +++ b/stdlib/private/SwiftPrivateThreadExtras/CMakeLists.txt @@ -19,6 +19,7 @@ add_swift_target_library(swiftSwiftPrivateThreadExtras ${SWIFT_STDLIB_LIBRARY_BU SWIFT_MODULE_DEPENDS_XROS ${swift_private_thread_extras_darwin_depencencies} SWIFT_MODULE_DEPENDS_MACCATALYST ${swift_private_thread_extras_darwin_depencencies} SWIFT_MODULE_DEPENDS_FREESTANDING "${SWIFT_FREESTANDING_TEST_DEPENDENCIES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl SWIFT_MODULE_DEPENDS_FREEBSD Glibc diff --git a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift index 20d5cdf214087..4ddf17a803136 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/SwiftPrivateThreadExtras.swift @@ -21,6 +21,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift index 97a5439d9ed4d..e7c43bf02567f 100644 --- a/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift +++ b/stdlib/private/SwiftPrivateThreadExtras/ThreadBarriers.swift @@ -16,6 +16,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/stdlib/private/SwiftReflectionTest/CMakeLists.txt b/stdlib/private/SwiftReflectionTest/CMakeLists.txt index f28b657be7d30..8ad688393765e 100644 --- a/stdlib/private/SwiftReflectionTest/CMakeLists.txt +++ b/stdlib/private/SwiftReflectionTest/CMakeLists.txt @@ -14,6 +14,7 @@ if (SWIFT_INCLUDE_TESTS AND SWIFT_BUILD_DYNAMIC_STDLIB) SWIFT_MODULE_DEPENDS_TVOS ${swift_reflection_test_darwin_depencencies} SWIFT_MODULE_DEPENDS_WATCHOS ${swift_reflection_test_darwin_depencencies} SWIFT_MODULE_DEPENDS_XROS ${swift_reflection_test_darwin_depencencies} + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl SWIFT_MODULE_DEPENDS_FREEBSD Glibc diff --git a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift index 44175a187da1b..041206cd4244e 100644 --- a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift +++ b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift @@ -131,6 +131,8 @@ import SwiftShims import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #endif let rtldDefault: UnsafeMutableRawPointer? = nil diff --git a/stdlib/public/Concurrency/CMakeLists.txt b/stdlib/public/Concurrency/CMakeLists.txt index ab19162eb7ced..260744e8829bf 100644 --- a/stdlib/public/Concurrency/CMakeLists.txt +++ b/stdlib/public/Concurrency/CMakeLists.txt @@ -156,6 +156,7 @@ add_swift_target_library(swift_Concurrency ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} I ${SWIFT_RUNTIME_CONCURRENCY_C_SOURCES} ${SWIFT_RUNTIME_CONCURRENCY_SWIFT_SOURCES} + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/public/Concurrency/Executor.swift b/stdlib/public/Concurrency/Executor.swift index b09d89b2cea05..c153988c3159c 100644 --- a/stdlib/public/Concurrency/Executor.swift +++ b/stdlib/public/Concurrency/Executor.swift @@ -498,8 +498,9 @@ internal func _task_serialExecutor_getExecutorRef(_ executor: E) -> Builtin.E /// The obtained executor ref will have all the user-defined flags set on the executor. @_unavailableInEmbedded @available(SwiftStdlib 6.0, *) -@_silgen_name("_task_executor_getTaskExecutorRef") -internal func _task_executor_getTaskExecutorRef(_ taskExecutor: any TaskExecutor) -> Builtin.Executor { +@_silgen_name("_task_taskExecutor_getTaskExecutorRef") +internal func _task_taskExecutor_getTaskExecutorRef(_ taskExecutor: E) -> Builtin.Executor + where E: TaskExecutor { return taskExecutor.asUnownedTaskExecutor().executor } diff --git a/stdlib/public/Concurrency/GlobalExecutor.cpp b/stdlib/public/Concurrency/GlobalExecutor.cpp index b0d0d4334c411..f4c8ed1ee05ff 100644 --- a/stdlib/public/Concurrency/GlobalExecutor.cpp +++ b/stdlib/public/Concurrency/GlobalExecutor.cpp @@ -161,18 +161,6 @@ SerialExecutorRef _task_serialExecutor_getExecutorRef( const SerialExecutorWitnessTable *wtable); #pragma clang diagnostic pop -// Implemented in Swift because we need to obtain the user-defined flags on the executor ref. -// -// We could inline this with effort, though. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" -extern "C" SWIFT_CC(swift) -TaskExecutorRef _task_executor_getTaskExecutorRef( - HeapObject *executor, const Metadata *selfType, - const SerialExecutorWitnessTable *wtable); -#pragma clang diagnostic pop - - /// WARNING: This method is expected to CRASH in new runtimes, and cannot be /// used to implement "log warnings" mode. We would need a new entry point to /// implement a "only log warnings" actor isolation checking mode, and it would diff --git a/stdlib/public/Concurrency/PartialAsyncTask.swift b/stdlib/public/Concurrency/PartialAsyncTask.swift index f18e650210bf3..cf8ab155c3be3 100644 --- a/stdlib/public/Concurrency/PartialAsyncTask.swift +++ b/stdlib/public/Concurrency/PartialAsyncTask.swift @@ -505,7 +505,7 @@ public struct UnsafeContinuation: Sendable { /// The task continues executing /// when its executor schedules it. @_alwaysEmitIntoClient - public func resume(returning value: __owned T) where E == Never { + public func resume(returning value: sending T) where E == Never { #if compiler(>=5.5) && $BuiltinContinuation Builtin.resumeNonThrowingContinuationReturning(context, value) #else @@ -527,7 +527,7 @@ public struct UnsafeContinuation: Sendable { /// The task continues executing /// when its executor schedules it. @_alwaysEmitIntoClient - public func resume(returning value: __owned T) { + public func resume(returning value: sending T) { #if compiler(>=5.5) && $BuiltinContinuation Builtin.resumeThrowingContinuationReturning(context, value) #else @@ -549,7 +549,7 @@ public struct UnsafeContinuation: Sendable { /// The task continues executing /// when its executor schedules it. @_alwaysEmitIntoClient - public func resume(throwing error: __owned E) { + public func resume(throwing error: consuming E) { #if compiler(>=5.5) && $BuiltinContinuation Builtin.resumeThrowingContinuationThrowing(context, error) #else @@ -577,7 +577,7 @@ extension UnsafeContinuation { /// The task continues executing /// when its executor schedules it. @_alwaysEmitIntoClient - public func resume(with result: Result) where E == Error { + public func resume(with result: __shared sending Result) where E == Error { switch result { case .success(let val): self.resume(returning: val) @@ -603,7 +603,7 @@ extension UnsafeContinuation { /// The task continues executing /// when its executor schedules it. @_alwaysEmitIntoClient - public func resume(with result: Result) { + public func resume(with result: __shared sending Result) { switch result { case .success(let val): self.resume(returning: val) @@ -635,7 +635,7 @@ extension UnsafeContinuation { @_alwaysEmitIntoClient internal func _resumeUnsafeContinuation( _ continuation: UnsafeContinuation, - _ value: __owned T + _ value: sending T ) { continuation.resume(returning: value) } @@ -644,7 +644,7 @@ internal func _resumeUnsafeContinuation( @_alwaysEmitIntoClient internal func _resumeUnsafeThrowingContinuation( _ continuation: UnsafeContinuation, - _ value: __owned T + _ value: sending T ) { continuation.resume(returning: value) } @@ -653,7 +653,7 @@ internal func _resumeUnsafeThrowingContinuation( @_alwaysEmitIntoClient internal func _resumeUnsafeThrowingContinuationWithError( _ continuation: UnsafeContinuation, - _ error: __owned Error + _ error: consuming Error ) { continuation.resume(throwing: error) } @@ -689,7 +689,7 @@ internal func _resumeUnsafeThrowingContinuationWithError( public func withUnsafeContinuation( isolation: isolated (any Actor)? = #isolation, _ fn: (UnsafeContinuation) -> Void -) async -> T { +) async -> sending T { return await Builtin.withUnsafeContinuation { fn(UnsafeContinuation($0)) } @@ -725,7 +725,7 @@ public func withUnsafeContinuation( public func withUnsafeThrowingContinuation( isolation: isolated (any Actor)? = #isolation, _ fn: (UnsafeContinuation) -> Void -) async throws -> T { +) async throws -> sending T { return try await Builtin.withUnsafeThrowingContinuation { fn(UnsafeContinuation($0)) } diff --git a/stdlib/public/Concurrency/Task+TaskExecutor.swift b/stdlib/public/Concurrency/Task+TaskExecutor.swift index ec0003d6542f1..18eee082a8e93 100644 --- a/stdlib/public/Concurrency/Task+TaskExecutor.swift +++ b/stdlib/public/Concurrency/Task+TaskExecutor.swift @@ -221,7 +221,7 @@ extension Task where Failure == Never { @discardableResult @_alwaysEmitIntoClient public init( - executorPreference taskExecutor: (any TaskExecutor)?, + executorPreference taskExecutor: consuming (any TaskExecutor)?, priority: TaskPriority? = nil, operation: __owned @Sendable @escaping () async -> Success ) { @@ -229,7 +229,7 @@ extension Task where Failure == Never { self = Self.init(priority: priority, operation: operation) return } - #if $BuiltinCreateAsyncTaskWithExecutor + #if $BuiltinCreateAsyncTaskWithExecutor && $BuiltinCreateTask // Set up the job flags for a new task. let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: true, @@ -237,15 +237,14 @@ extension Task where Failure == Never { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - // Create the asynchronous task. - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor + let (task, _) = Builtin.createTask( + flags: flags, + initialTaskExecutorConsuming: taskExecutor, + operation: operation) - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) self._task = task #else - fatalError("Unsupported Swift compiler, missing support for BuiltinCreateAsyncTaskWithExecutor") + fatalError("Unsupported Swift compiler, missing support for BuiltinCreateAsyncTaskWithExecutor or $BuiltinCreateTask") #endif } } @@ -282,7 +281,7 @@ extension Task where Failure == Error { @discardableResult @_alwaysEmitIntoClient public init( - executorPreference taskExecutor: (any TaskExecutor)?, + executorPreference taskExecutor: consuming (any TaskExecutor)?, priority: TaskPriority? = nil, operation: __owned @Sendable @escaping () async throws -> Success ) { @@ -290,7 +289,7 @@ extension Task where Failure == Error { self = Self.init(priority: priority, operation: operation) return } - #if $BuiltinCreateAsyncTaskWithExecutor + #if $BuiltinCreateAsyncTaskWithExecutor && $BuiltinCreateTask // Set up the job flags for a new task. let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: true, @@ -298,14 +297,14 @@ extension Task where Failure == Error { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - // Create the asynchronous task. - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) + let (task, _) = Builtin.createTask( + flags: flags, + initialTaskExecutorConsuming: taskExecutor, + operation: operation) + self._task = task #else - fatalError("Unsupported Swift compiler, missing support for $BuiltinCreateAsyncTaskWithExecutor") + fatalError("Unsupported Swift compiler, missing support for BuiltinCreateAsyncTaskWithExecutor or $BuiltinCreateTask") #endif } } @@ -348,7 +347,7 @@ extension Task where Failure == Never { guard let taskExecutor else { return Self.detached(priority: priority, operation: operation) } - #if $BuiltinCreateAsyncTaskWithExecutor + #if $BuiltinCreateAsyncTaskWithExecutor && $BuiltinCreateTask // Set up the job flags for a new task. let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: false, @@ -356,15 +355,15 @@ extension Task where Failure == Never { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - // Create the asynchronous task. - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) + let (task, _) = Builtin.createTask( + flags: flags, + // initialTaskExecutor: executorBuiltin, deprecated + initialTaskExecutorConsuming: taskExecutor, + operation: operation) return Task(task) #else - fatalError("Unsupported Swift compiler") + fatalError("Unsupported Swift compiler, missing support for BuiltinCreateAsyncTaskWithExecutor or $BuiltinCreateTask") #endif } } @@ -407,7 +406,7 @@ extension Task where Failure == Error { guard let taskExecutor else { return Self.detached(priority: priority, operation: operation) } - #if $BuiltinCreateAsyncTaskWithExecutor + #if $BuiltinCreateAsyncTaskWithExecutor && $BuiltinCreateTask // Set up the job flags for a new task. let flags = taskCreateFlags( priority: priority, isChildTask: false, copyTaskLocals: false, @@ -415,15 +414,14 @@ extension Task where Failure == Error { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - // Create the asynchronous task. - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - let (task, _) = Builtin.createAsyncTaskWithExecutor( - flags, executorBuiltin, operation) + let (task, _) = Builtin.createTask( + flags: flags, + initialTaskExecutorConsuming: taskExecutor, + operation: operation) return Task(task) #else - fatalError("Unsupported Swift compiler") + fatalError("Unsupported Swift compiler, missing support for BuiltinCreateAsyncTaskWithExecutor or $BuiltinCreateTask") #endif } } diff --git a/stdlib/public/Concurrency/Task.cpp b/stdlib/public/Concurrency/Task.cpp index 13f8f19e759e7..70314bf1677ce 100644 --- a/stdlib/public/Concurrency/Task.cpp +++ b/stdlib/public/Concurrency/Task.cpp @@ -192,6 +192,27 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask, } } +// Implemented in Swift because we need to obtain the user-defined flags on the executor ref. +// +// We could inline this with effort, though. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" SWIFT_CC(swift) +TaskExecutorRef _task_taskExecutor_getTaskExecutorRef( + HeapObject *executor, const Metadata *selfType, + const TaskExecutorWitnessTable *wtable); +#pragma clang diagnostic pop + +TaskExecutorRef +InitialTaskExecutorOwnedPreferenceTaskOptionRecord::getExecutorRefFromUnownedTaskExecutor() const { + TaskExecutorRef executorRef = _task_taskExecutor_getTaskExecutorRef( + Identity, + /*selfType=*/swift_getObjectType(Identity), + /*wtable=*/WitnessTable); + return executorRef; +} + + void NullaryContinuationJob::process(Job *_job) { auto *job = cast(_job); @@ -652,6 +673,7 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, // Collect the options we know about. SerialExecutorRef serialExecutor = SerialExecutorRef::generic(); TaskExecutorRef taskExecutor = TaskExecutorRef::undefined(); + bool taskExecutorIsOwned = false; TaskGroup *group = nullptr; AsyncLet *asyncLet = nullptr; bool hasAsyncLetResultBuffer = false; @@ -663,10 +685,18 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, ->getExecutorRef(); break; - case TaskOptionRecordKind::InitialTaskExecutor: - taskExecutor = cast(option) + case TaskOptionRecordKind::InitialTaskExecutorUnowned: + taskExecutor = cast(option) ->getExecutorRef(); jobFlags.task_setHasInitialTaskExecutorPreference(true); + taskExecutorIsOwned = false; + break; + + case TaskOptionRecordKind::InitialTaskExecutorOwned: + taskExecutor = cast(option) + ->getExecutorRefFromUnownedTaskExecutor(); + taskExecutorIsOwned = true; + jobFlags.task_setHasInitialTaskExecutorPreference(true); break; case TaskOptionRecordKind::TaskGroup: @@ -1078,7 +1108,8 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags, // Implementation note: we must do this AFTER `swift_taskGroup_attachChild` // because the group takes a fast-path when attaching the child record. assert(jobFlags.task_hasInitialTaskExecutorPreference()); - task->pushInitialTaskExecutorPreference(taskExecutor); + task->pushInitialTaskExecutorPreference( + taskExecutor, /*owned=*/taskExecutorIsOwned); } // If we're supposed to enqueue the task, do so now. diff --git a/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift b/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift index 199c90ba6afcc..20a5a6d885a7e 100644 --- a/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift +++ b/stdlib/public/Concurrency/TaskGroup+TaskExecutor.swift @@ -47,9 +47,6 @@ extension TaskGroup { addPendingGroupTaskUnconditionally: true, isDiscardingTask: false) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -58,7 +55,7 @@ extension TaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -105,9 +102,6 @@ extension TaskGroup { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -116,7 +110,7 @@ extension TaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -162,9 +156,6 @@ extension ThrowingTaskGroup { addPendingGroupTaskUnconditionally: true, isDiscardingTask: false) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -173,7 +164,7 @@ extension ThrowingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -216,9 +207,6 @@ extension ThrowingTaskGroup { addPendingGroupTaskUnconditionally: false, isDiscardingTask: false) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -227,7 +215,7 @@ extension ThrowingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -273,9 +261,6 @@ extension DiscardingTaskGroup { addPendingGroupTaskUnconditionally: true, isDiscardingTask: true) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -284,7 +269,7 @@ extension DiscardingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncDiscardingTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -332,9 +317,6 @@ extension DiscardingTaskGroup { addPendingGroupTaskUnconditionally: false, isDiscardingTask: true ) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -343,7 +325,7 @@ extension DiscardingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncDiscardingTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -389,9 +371,6 @@ extension ThrowingDiscardingTaskGroup { addPendingGroupTaskUnconditionally: true, isDiscardingTask: true) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -400,7 +379,7 @@ extension ThrowingDiscardingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncDiscardingTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) @@ -448,9 +427,6 @@ extension ThrowingDiscardingTaskGroup { addPendingGroupTaskUnconditionally: false, isDiscardingTask: true ) - let executorBuiltin: Builtin.Executor = - taskExecutor.asUnownedTaskExecutor().executor - // Create the task in this group with an executor preference. #if $BuiltinCreateTask let builtinSerialExecutor = @@ -459,7 +435,7 @@ extension ThrowingDiscardingTaskGroup { _ = Builtin.createTask(flags: flags, initialSerialExecutor: builtinSerialExecutor, taskGroup: _group, - initialTaskExecutor: executorBuiltin, + initialTaskExecutorConsuming: taskExecutor, operation: operation) #else _ = Builtin.createAsyncDiscardingTaskInGroupWithExecutor(flags, _group, executorBuiltin, operation) diff --git a/stdlib/public/Concurrency/TaskPrivate.h b/stdlib/public/Concurrency/TaskPrivate.h index a7f9ed4af703b..247ecc51cdec5 100644 --- a/stdlib/public/Concurrency/TaskPrivate.h +++ b/stdlib/public/Concurrency/TaskPrivate.h @@ -791,7 +791,7 @@ struct AsyncTask::PrivateStorage { // elements are destroyed; in order to respect stack-discipline of // the task-local allocator. if (task->hasInitialTaskExecutorPreferenceRecord()) { - task->dropInitialTaskExecutorPreferenceRecord(); + task->dropInitialTaskExecutorPreferenceRecord(); } // Drain unlock the task and remove any overrides on thread as a diff --git a/stdlib/public/Concurrency/TaskStatus.cpp b/stdlib/public/Concurrency/TaskStatus.cpp index 6e8ff908308a7..d195ac66c807d 100644 --- a/stdlib/public/Concurrency/TaskStatus.cpp +++ b/stdlib/public/Concurrency/TaskStatus.cpp @@ -464,8 +464,8 @@ void swift::removeStatusRecordWhere( llvm::function_ref condition, llvm::function_ref updateStatus) { assert(condition && "condition is required"); - SWIFT_TASK_DEBUG_LOG("remove status record = %p, from task = %p", - record, task); + SWIFT_TASK_DEBUG_LOG("remove status record where(), from task = %p", + task); if (oldStatus.isStatusRecordLocked() && waitForStatusRecordUnlockIfNotSelfLocked(task, oldStatus)) { @@ -595,7 +595,7 @@ static bool swift_task_hasTaskGroupStatusRecordImpl() { ///************************** TASK EXECUTORS ********************************/ ///**************************************************************************/ -TaskExecutorRef AsyncTask::getPreferredTaskExecutor() { +TaskExecutorRef AsyncTask::getPreferredTaskExecutor(bool assumeHasRecord) { // We first check the executor preference status flag, in order to avoid // having to scan through the records of the task checking if there was // such record. @@ -644,7 +644,14 @@ swift_task_pushTaskExecutorPreferenceImpl(TaskExecutorRef taskExecutor) { void *allocation = _swift_task_alloc_specific( task, sizeof(class TaskExecutorPreferenceStatusRecord)); auto record = - ::new (allocation) TaskExecutorPreferenceStatusRecord(taskExecutor); + ::new (allocation) TaskExecutorPreferenceStatusRecord( + taskExecutor, + // we don't retain the executor by the task/record, because the "push" + // is implemented as a scope which keeps the executor alive by itself + // already, so we save the retain/release pair by the task doing it + // as well. In contrast, unstructured task creation always retains + // the executor. + /*retainedExecutor=*/false); SWIFT_TASK_DEBUG_LOG("[TaskExecutorPreference] Create task executor " "preference record %p for task:%p", allocation, task); @@ -669,7 +676,7 @@ static void swift_task_popTaskExecutorPreferenceImpl( TaskExecutorPreferenceStatusRecord *record) { SWIFT_TASK_DEBUG_LOG("[TaskExecutorPreference] Remove task executor " "preference record %p from task:%p", - allocation, swift_task_getCurrent()); + record, swift_task_getCurrent()); // We keep count of how many records there are because if there is more than // one, it means the task status flag should still be "has task preference". int preferenceRecordsCount = 0; @@ -703,11 +710,12 @@ static void swift_task_popTaskExecutorPreferenceImpl( } void AsyncTask::pushInitialTaskExecutorPreference( - TaskExecutorRef preferredExecutor) { + TaskExecutorRef preferredExecutor, bool owned) { void *allocation = _swift_task_alloc_specific( this, sizeof(class TaskExecutorPreferenceStatusRecord)); auto record = - ::new (allocation) TaskExecutorPreferenceStatusRecord(preferredExecutor); + ::new (allocation) TaskExecutorPreferenceStatusRecord( + preferredExecutor, /*ownsExecutor=*/owned); SWIFT_TASK_DEBUG_LOG("[InitialTaskExecutorPreference] Create a task " "preference record %p for task:%p", record, this); @@ -733,10 +741,20 @@ void AsyncTask::dropInitialTaskExecutorPreferenceRecord() { this); assert(this->hasInitialTaskExecutorPreferenceRecord()); + HeapObject *executorIdentityToRelease = nullptr; withStatusRecordLock(this, [&](ActiveTaskStatus status) { for (auto r : status.records()) { if (r->getKind() == TaskStatusRecordKind::TaskExecutorPreference) { auto record = cast(r); + + if (record->hasRetainedExecutor()) { + // Some tasks own their executor (i.e. take it consuming and guarantee + // its lifetime dynamically), while strictly structured tasks like + // async let do not retain it + executorIdentityToRelease = + record->getPreferredExecutor().getIdentity(); + } + removeStatusRecordLocked(status, record); _swift_task_dealloc_specific(this, record); return; @@ -748,6 +766,13 @@ void AsyncTask::dropInitialTaskExecutorPreferenceRecord() { assert(false && "dropInitialTaskExecutorPreferenceRecord must be " "guaranteed to drop the last preference"); }); + + // Release the "initial" preferred task executor, because it was specifically + // set in a Task initializer, which retained it. + // + // This should not be done for withTaskExecutorPreference executors, + // however in that case, we would not enter this function here to clean up. + swift_release(executorIdentityToRelease); } /**************************************************************************/ diff --git a/stdlib/public/Cxx/std/CMakeLists.txt b/stdlib/public/Cxx/std/CMakeLists.txt index 85087204882ae..be5807902e877 100644 --- a/stdlib/public/Cxx/std/CMakeLists.txt +++ b/stdlib/public/Cxx/std/CMakeLists.txt @@ -45,6 +45,7 @@ add_swift_target_library(swiftCxxStdlib STATIC NO_LINK_NAME IS_STDLIB IS_SWIFT_O SWIFT_MODULE_DEPENDS_WATCHOS ${swift_cxxstdlib_darwin_dependencies} SWIFT_MODULE_DEPENDS_XROS ${swift_cxxstdlib_darwin_dependencies} SWIFT_MODULE_DEPENDS_MACCATALYST ${swift_cxxstdlib_darwin_dependencies} + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_COMPILE_FLAGS ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} -cxx-interoperability-mode=default @@ -56,7 +57,7 @@ add_swift_target_library(swiftCxxStdlib STATIC NO_LINK_NAME IS_STDLIB IS_SWIFT_O DEPLOYMENT_VERSION_OSX ${COMPATIBILITY_MINIMUM_DEPLOYMENT_VERSION_OSX} LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" - TARGET_SDKS ALL_APPLE_PLATFORMS LINUX WINDOWS + TARGET_SDKS ALL_APPLE_PLATFORMS LINUX WINDOWS ANDROID INSTALL_IN_COMPONENT compiler INSTALL_WITH_SHARED DEPENDS libstdcxx-modulemap libcxxshim_modulemap CxxStdlib-apinotes) diff --git a/stdlib/public/Differentiation/CMakeLists.txt b/stdlib/public/Differentiation/CMakeLists.txt index 64e0ec3ee15e8..16a296bbbe772 100644 --- a/stdlib/public/Differentiation/CMakeLists.txt +++ b/stdlib/public/Differentiation/CMakeLists.txt @@ -42,6 +42,7 @@ add_swift_target_library(swift_Differentiation ${SWIFT_STDLIB_LIBRARY_BUILD_TYPE SWIFT_MODULE_DEPENDS_TVOS ${swiftDifferentiationDarwinDependencies} SWIFT_MODULE_DEPENDS_WATCHOS ${swiftDifferentiationDarwinDependencies} SWIFT_MODULE_DEPENDS_XROS ${swiftDifferentiationDarwinDependencies} + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_LINUX_STATIC Musl SWIFT_MODULE_DEPENDS_FREEBSD Glibc diff --git a/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb b/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb index a517dade14502..52600d71be9ee 100644 --- a/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb +++ b/stdlib/public/Differentiation/TgmathDerivatives.swift.gyb @@ -18,12 +18,14 @@ import Swift import Darwin.C.tgmath #elseif canImport(Musl) import Musl -#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) +#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(PS4) || os(Cygwin) || os(Haiku) import Glibc #elseif os(WASI) import WASILibc #elseif os(Windows) import CRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/stdlib/public/Distributed/CMakeLists.txt b/stdlib/public/Distributed/CMakeLists.txt index 3a0dcb21d9832..5dbea7d12f822 100644 --- a/stdlib/public/Distributed/CMakeLists.txt +++ b/stdlib/public/Distributed/CMakeLists.txt @@ -34,6 +34,7 @@ add_swift_target_library(swiftDistributed ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS SWIFT_MODULE_DEPENDS_OSX ${swift_distributed_darwin_depencencies} SWIFT_MODULE_DEPENDS_TVOS ${swift_distributed_darwin_depencencies} SWIFT_MODULE_DEPENDS_WATCHOS ${swift_distributed_darwin_depencencies} + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift b/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift index 47e31d9019800..33c208bff38ea 100644 --- a/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift +++ b/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift @@ -18,6 +18,8 @@ import Darwin import Glibc #elseif canImport(Musl) import Musl +#elseif canImport(Android) +import Android #elseif os(Windows) import WinSDK #endif diff --git a/stdlib/public/Platform/Android.swift b/stdlib/public/Platform/Android.swift new file mode 100644 index 0000000000000..cb15c356a8d12 --- /dev/null +++ b/stdlib/public/Platform/Android.swift @@ -0,0 +1,13 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@_exported import SwiftAndroid // Clang module diff --git a/stdlib/public/Platform/CMakeLists.txt b/stdlib/public/Platform/CMakeLists.txt index 31419b092c057..7e709923ffcd0 100644 --- a/stdlib/public/Platform/CMakeLists.txt +++ b/stdlib/public/Platform/CMakeLists.txt @@ -127,9 +127,9 @@ if(SWIFT_SHOULD_BUILD_EMBEDDED_STDLIB) endforeach() endif() -set(swiftGlibc_target_sdks ANDROID CYGWIN FREEBSD OPENBSD LINUX HAIKU) +set(swiftGlibc_target_sdks CYGWIN FREEBSD OPENBSD LINUX HAIKU) if(SWIFT_FREESTANDING_FLAVOR STREQUAL "linux") - set(swiftGlibc_target_sdks ANDROID CYGWIN FREEBSD OPENBSD LINUX HAIKU FREESTANDING) + set(swiftGlibc_target_sdks CYGWIN FREEBSD OPENBSD LINUX HAIKU FREESTANDING) endif() add_swift_target_library(swiftGlibc ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY ${swift_platform_sources} @@ -273,12 +273,42 @@ add_custom_target(musl_modulemap DEPENDS ${musl_modulemap_target_list}) set_property(TARGET musl_modulemap PROPERTY FOLDER "Miscellaneous") add_dependencies(sdk-overlay musl_modulemap) +# Add a system 'math' module overlay, which applies only to platforms that +# have a top level '_math' module. +add_swift_target_library(swift_math ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY + Math.swift + + SWIFT_COMPILE_FLAGS + ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} + ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + ${swift_platform_compile_flags} + LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" + TARGET_SDKS "ANDROID" + INSTALL_IN_COMPONENT sdk-overlay + DEPENDS android_modulemap) + +add_swift_target_library(swiftAndroid ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY + Android.swift + ${swift_platform_sources} + POSIXError.swift + + GYB_SOURCES + ${swift_platform_gyb_sources} + + SWIFT_COMPILE_FLAGS + ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} + ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS} + ${swift_platform_compile_flags} + LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}" + TARGET_SDKS "ANDROID" + INSTALL_IN_COMPONENT sdk-overlay + DEPENDS android_modulemap) + set(glibc_modulemap_target_list) foreach(sdk ${SWIFT_SDKS}) if(NOT "${sdk}" STREQUAL "LINUX" AND NOT "${sdk}" STREQUAL "FREEBSD" AND NOT "${sdk}" STREQUAL "OPENBSD" AND - NOT "${sdk}" STREQUAL "ANDROID" AND NOT "${sdk}" STREQUAL "CYGWIN" AND NOT "${sdk}" STREQUAL "HAIKU") continue() @@ -334,11 +364,9 @@ foreach(sdk ${SWIFT_SDKS}) ${copy_glibc_modulemap_header_static}) endif() - # If this SDK is a target for a non-native host, except if it's for Android - # with its own native sysroot, create a native modulemap without a sysroot - # prefix. This is the one we'll install instead. - if(NOT "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${arch}_PATH}" STREQUAL "/" AND - NOT (sdk STREQUAL "ANDROID" AND NOT "${SWIFT_ANDROID_NATIVE_SYSROOT}" STREQUAL "")) + # If this SDK is a target for a non-native host, create a native modulemap + # without a sysroot prefix. This is the one we'll install instead. + if(NOT "${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_ARCH_${arch}_PATH}" STREQUAL "/") set(glibc_sysroot_relative_modulemap_out "${module_dir}/sysroot-relative-modulemaps/glibc.modulemap") handle_gyb_source_single(glibc_modulemap_native_target @@ -376,6 +404,79 @@ add_custom_target(glibc_modulemap DEPENDS ${glibc_modulemap_target_list}) set_property(TARGET glibc_modulemap PROPERTY FOLDER "Miscellaneous") add_dependencies(sdk-overlay glibc_modulemap) +set(android_modulemap_target_list) +if("ANDROID" IN_LIST SWIFT_SDKS) + set(android_modulemap_source "android.modulemap") + set(android_ndk_header_source "SwiftAndroidNDK.h") + set(android_bionic_header_source "SwiftBionic.h") + + foreach(arch ${SWIFT_SDK_ANDROID_ARCHITECTURES}) + set(arch_subdir "${SWIFT_SDK_ANDROID_LIB_SUBDIR}/${arch}") + set(module_dir "${SWIFTLIB_DIR}/${arch_subdir}") + set(module_dir_static "${SWIFTSTATICLIB_DIR}/${arch_subdir}") + + add_custom_command_target( + copy_android_modulemap_resource + COMMAND + "${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir} ${module_dir_static} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_modulemap_source}" ${module_dir} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_modulemap_source}" ${module_dir_static} + OUTPUT ${module_dir}/${android_modulemap_source} ${module_dir_static}/${android_modulemap_source} + COMMENT "Copying Android modulemap to resource directories") + add_custom_command_target( + copy_android_ndk_header_resource + COMMAND + "${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir} ${module_dir_static} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_ndk_header_source}" ${module_dir} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_ndk_header_source}" ${module_dir_static} + OUTPUT ${module_dir}/${android_ndk_header_source} ${module_dir_static}/${android_ndk_header_source} + COMMENT "Copying Android NDK header to resource directories") + add_custom_command_target( + copy_android_bionic_header_resource + COMMAND + "${CMAKE_COMMAND}" "-E" "make_directory" ${module_dir} ${module_dir_static} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_bionic_header_source}" ${module_dir} + COMMAND + "${CMAKE_COMMAND}" "-E" "copy_if_different" + "${CMAKE_CURRENT_SOURCE_DIR}/${android_bionic_header_source}" ${module_dir_static} + OUTPUT ${module_dir}/${android_bionic_header_source} ${module_dir_static}/${android_bionic_header_source} + COMMENT "Copying Android NDK header to resource directories") + + add_dependencies(sdk-overlay ${copy_android_modulemap_resource} + ${copy_android_ndk_header_resource} + ${copy_android_bionic_header_resource}) + list(APPEND android_modulemap_target_list ${copy_android_modulemap_resource} + ${copy_android_ndk_header_resource} + ${copy_android_bionic_header_resource}) + + swift_install_in_component(FILES "${android_modulemap_source}" + "${android_ndk_header_source}" + "${android_bionic_header_source}" + DESTINATION "lib/swift/${arch_subdir}" + COMPONENT sdk-overlay) + if(SWIFT_BUILD_STATIC_STDLIB) + swift_install_in_component(FILES "${android_modulemap_source}" + "${android_ndk_header_source}" + "${android_bionic_header_source}" + DESTINATION "lib/swift_static/${arch_subdir}" + COMPONENT sdk-overlay) + endif() + endforeach() +endif() +add_custom_target(android_modulemap DEPENDS ${android_modulemap_target_list}) +set_property(TARGET android_modulemap PROPERTY FOLDER "Miscellaneous") +add_dependencies(sdk-overlay android_modulemap) + set(wasilibc_modulemap_target_list) if("WASI" IN_LIST SWIFT_SDKS) set(wasilibc_modulemap_source "wasi-libc.modulemap") diff --git a/stdlib/public/Platform/Math.swift b/stdlib/public/Platform/Math.swift new file mode 100644 index 0000000000000..545a6cca36a89 --- /dev/null +++ b/stdlib/public/Platform/Math.swift @@ -0,0 +1,17 @@ +@_exported import _math + +// Constants defined by +@available(swift, deprecated: 3.0, message: "Please use 'Double.pi' or '.pi' to get the value of correct type and avoid casting.") +public let M_PI = Double.pi + +@available(swift, deprecated: 3.0, message: "Please use 'Double.pi / 2' or '.pi / 2' to get the value of correct type and avoid casting.") +public let M_PI_2 = Double.pi / 2 + +@available(swift, deprecated: 3.0, message: "Please use 'Double.pi / 4' or '.pi / 4' to get the value of correct type and avoid casting.") +public let M_PI_4 = Double.pi / 4 + +@available(swift, deprecated: 3.0, message: "Please use '2.squareRoot()'.") +public let M_SQRT2 = 2.squareRoot() + +@available(swift, deprecated: 3.0, message: "Please use '0.5.squareRoot()'.") +public let M_SQRT1_2 = 0.5.squareRoot() diff --git a/stdlib/public/Platform/SwiftAndroidNDK.h b/stdlib/public/Platform/SwiftAndroidNDK.h new file mode 100644 index 0000000000000..791ac40ec4336 --- /dev/null +++ b/stdlib/public/Platform/SwiftAndroidNDK.h @@ -0,0 +1,148 @@ +//===--- SwiftAndroidNDK.h ------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_ANDROID_NDK_MODULE +#define SWIFT_ANDROID_NDK_MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// C headers that are included with the compiler. +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#endif // SWIFT_ANDROID_NDK_MODULE diff --git a/stdlib/public/Platform/SwiftBionic.h b/stdlib/public/Platform/SwiftBionic.h new file mode 100644 index 0000000000000..b3e173030f18b --- /dev/null +++ b/stdlib/public/Platform/SwiftBionic.h @@ -0,0 +1,38 @@ +//===--- SwiftBionic.h ----------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BIONIC_MODULE +#define SWIFT_BIONIC_MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // SWIFT_BIONIC_MODULE diff --git a/stdlib/public/Platform/android.modulemap b/stdlib/public/Platform/android.modulemap new file mode 100644 index 0000000000000..9a0591488cd83 --- /dev/null +++ b/stdlib/public/Platform/android.modulemap @@ -0,0 +1,683 @@ +//===--- android.modulemap ------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// The module map for the Android NDK. +// A portion of the modules in this file are prefixed +// with an underscore, to discourage users from importing them from +// Swift directly, as these modules might be overriden by the C++ stdlib. +// Instead, users should import 'Android' or another +// umbrella module that includes these headers. + +// The top level 'Android' module can be included from Swift. +module SwiftAndroid [system] { + header "SwiftAndroidNDK.h" + export * +} + +// The top level 'Bionic' module is the C standard library +// used in the Android NDK. +module Bionic [system] { + header "SwiftBionic.h" + export * +} + +// The individual modules for the Bionic C standard library used +// by the Android NDK. +module _assert [system] { + // 's use of NDEBUG requires textual inclusion. + textual header "assert.h" +} +module _complex [system] { + header "complex.h" + export * +} +module _ctype [system] { + header "ctype.h" + export * +} +module _errno [system] { + header "errno.h" + export * +} +module _fenv [system] { + header "fenv.h" + export * +} +// Use 'no_undeclared_includes' to avoid pulling in the libc++ headers. +// FIXME: this can be dropped once NDK's libc++ 'std' module is split +// into individual submodules. +module _inttypes [system] [no_undeclared_includes] { + header "inttypes.h" + export * + use _stdint + use _sys_cdefs +} +module _limits [system] { + header "limits.h" + export * + explicit module posix_limits { + header "bits/posix_limits.h" + export * + } +} +module _locale [system] { + header "locale.h" + export * +} +module _malloc [system] { + header "malloc.h" + export * +} +module _math [system] { + header "math.h" + export * + link "m" +} +module _setjmp [system] { + header "setjmp.h" + export * +} +module _signal [system] { + header "signal.h" + // The 'signal.h' header unfortunately has a circular include + // with 'sys/ucontext.h' and thus it must be part of this module. + header "sys/ucontext.h" + export * + explicit module bits_signaltypes { + header "bits/signal_types.h" + export * + } +} +module _stdatomic [system] { + header "stdatomic.h" + export * +} +module _stdint [system] { + header "stdint.h" + export * +} +module _stdio [system] { + header "stdio.h" + export * + explicit module stdio_ext { + header "stdio_ext.h" + export * + } +} +module _stdlib [system] { + header "stdlib.h" + export * +} +module _string [system] { + header "string.h" + export * +} +module _threads [system] { + header "threads.h" + export * + explicit module threads_inlines { + header "bits/threads_inlines.h" + export * + } +} +module _time [system] { + header "time.h" + export * + explicit module sys_time { + header "sys/time.h" + export * + } + explicit module sys_times { + header "sys/times.h" + export * + } +} +module _uchar [system] { + header "uchar.h" + export * +} +module _wchar [system] { + header "wchar.h" + export * + explicit module mbstate_t { + header "bits/mbstate_t.h" + export * + } +} + +// POSIX and another android NDK headers. +module alloca [system] { + header "alloca.h" + export * +} + +module ar [system] { + header "ar.h" + export * +} + +module cpio [system] { + header "cpio.h" + export * +} + +module posix_filesystem [system] { + // This module groups all file, paths and filesystem + // operations into one module. + explicit module dirent { + header "dirent.h" + export * + } + explicit module fcntl { + header "fcntl.h" + // Note: Do not re-export imported modules + // to prevent exporting constants from linux/stat.h . + } + explicit module fnmatch { + header "fnmatch.h" + export * + } + explicit module fts { + header "fts.h" + export * + } + explicit module ftw { + header "ftw.h" + export * + } + explicit module glob { + header "glob.h" + export * + } + explicit module mntent { + header "mntent.h" + export * + } + explicit module libgen { + header "libgen.h" + export * + } + explicit module nl_types { + header "nl_types.h" + export * + } + explicit module paths { + header "paths.h" + export * + } + explicit module poll { + header "poll.h" + export * + } + explicit module pwd { + header "pwd.h" + export * + } + explicit module utime { + header "utime.h" + export * + } + explicit module bits_ioctl { + header "bits/ioctl.h" + export * + } + explicit module linux_stat { + private header "linux/stat.h" + export * + } + explicit module sys_epoll { + header "sys/epoll.h" + export * + } + explicit module sys_eventfd { + header "sys/eventfd.h" + export * + } + explicit module sys_fcntl { + header "sys/fcntl.h" + export * + } + explicit module sys_file { + header "sys/file.h" + export * + } + explicit module sys_inotify { + header "sys/inotify.h" + export * + } + explicit module sys_ioctl { + header "sys/ioctl.h" + export * + } + explicit module sys_mount { + header "sys/mount.h" + export * + } + explicit module sys_sendfile { + header "sys/sendfile.h" + export * + } + explicit module sys_stat { + header "sys/stat.h" + // Note: Do not re-export imported modules + // to prevent exporting constants from linux/stat.h . + } + explicit module sys_statvfs { + header "sys/statvfs.h" + export * + } + explicit module sys_vfs { + header "sys/vfs.h" + export * + } + explicit module sys_uio { + header "sys/uio.h" + export * + } +} + +module dl [system] { + // This module groups all dl* based operations + // into one module. + explicit module dlfcn { + header "dlfcn.h" + export * + } + explicit module link_ { + header "link.h" + export * + } +} + +module error [system] { + header "error.h" + export * + explicit module err { + header "err.h" + export * + } +} + +module execinfo [system] { + header "execinfo.h" + export * +} + +module features [system] { + header "features.h" + export * +} + +module getopt [system] { + header "getopt.h" + export * +} + +module grp [system] { + header "grp.h" + export * +} + +module iconv [system] { + header "iconv.h" + export * +} + +module inet [system] { + // This module groups headers related to inet + // and networking. + explicit module ifaddrs { + header "ifaddrs.h" + export * + } + explicit module netdb { + header "netdb.h" + export * + } + explicit module arpa_inet { + header "arpa/inet.h" + export * + } + explicit module net_if { + header "net/if.h" + export * + } + explicit module netinet_in { + header "netinet/in.h" + export * + } + explicit module netinet_in6 { + header "netinet/in6.h" + export * + } + explicit module netinet_tcp { + header "netinet/tcp.h" + export * + } + explicit module bits_ip_mreq_source { + header "bits/ip_mreq_source.h" + export * + } + explicit module bits_ip_msfilter { + header "bits/ip_msfilter.h" + export * + } + explicit module bits_in_addr { + header "bits/in_addr.h" + export * + } + explicit module linux_if { + header "linux/if.h" + export * + } + explicit module sys_socket { + header "sys/socket.h" + export * + } +} + +module jni [system] { + header "jni.h" + export * +} + +module langinfo [system] { + header "langinfo.h" + export * +} + +module pthread [system] { + header "pthread.h" + export * +} + +module pty [system] { + header "pty.h" + export * +} + +module regex [system] { + header "regex.h" + export * +} + +module resolv [system] { + header "resolv.h" + export * +} + +module sched [system] { + header "sched.h" + export * +} + +module search [system] { + header "search.h" + export * +} + +module semaphore [system] { + header "semaphore.h" + export * +} + +module spawn [system] { + header "spawn.h" + export * +} + +module strings [system] { + header "strings.h" + export * +} + +module sys [system] { + explicit module syscall { + header "syscall.h" + export * + } + explicit module sysexits { + header "sysexits.h" + export * + } + explicit module syslog { + header "syslog.h" + export * + } +} + +module tar [system] { + header "tar.h" + export * +} + +module termio [system] { + explicit module termio { + header "termio.h" + export * + } + explicit module termios { + header "termios.h" + export * + } +} + +module uconfig_local [system] { + header "uconfig_local.h" + export * +} + +module ucontext [system] { + header "ucontext.h" + export * +} + +module unistd [system] { + header "unistd.h" + export * + explicit module sys_unistd { + header "sys/unistd.h" + export * + } +} + +module utmp [system] { + explicit module utmp { + header "utmp.h" + export * + } + explicit module utmpx { + header "utmpx.h" + export * + } +} + +module wait [system] { + header "wait.h" + export * + explicit module sys_wait { + header "sys/wait.h" + export * + } +} + +module xlocale [system] { + header "xlocale.h" + export * +} + +// Additional modules in the 'android' subdirectory. +module android_defs [system] { + explicit module ndk_version { + header "android/ndk-version.h" + export * + } + explicit module versioning { + header "android/versioning.h" + export * + } +} + +module android_apis [system] { + explicit module asset_manager_jni { + header "android/asset_manager_jni.h" + export * + } + explicit module asset_manager { + header "android/asset_manager.h" + export * + } + explicit module log { + header "android/log.h" + export * + } + explicit module trace { + header "android/trace.h" + export * + } +} + +// Additional modules in the 'bits' subdirectory. +module _bits_sa_family_t [system] { + // Note: this module is not part of 'inet' + // to prevent a circular modular dependency. + header "bits/sa_family_t.h" + export * +} +module _bits_stdatomic [system] { + // Note: this module is not part of 'stdatomic' + // as it depends on libc++ and forcing it to + // be in the same module breaks that modularization + // chain. + header "bits/stdatomic.h" + export * +} + +// Additional modules in the 'linux' subdirectory. +module _linux_time [system] { + // Note: this module is not part of '_time' + // to prevent a circular modular dependency + // between linux_time and sys modules. + header "linux/time.h" + header "linux/time_types.h" + export * + explicit module bits_timespec { + header "bits/timespec.h" + export * + } +} + +// Additional modules in the 'sys' subdirectory. +module _sys_cdefs [system] { + header "sys/cdefs.h" + // Circular included header, so combine them + // into the same module. + header "android/api-level.h" + export * +} +module _sys_core [system] { + explicit module endian { + header "sys/endian.h" + export * + } + explicit module errno { + header "sys/errno.h" + export * + } + explicit module ifunc { + header "sys/ifunc.h" + export * + } + explicit module ipc { + header "sys/ipc.h" + export * + } + explicit module mman { + header "sys/mman.h" + export * + } + explicit module mman_common { + header "asm-generic/mman-common.h" + export * + } + explicit module msg { + header "sys/msg.h" + export * + } + explicit module random { + header "sys/random.h" + export * + } + explicit module resource { + header "sys/resource.h" + export * + } + explicit module sem { + header "sys/sem.h" + export * + } + explicit module shm { + header "sys/shm.h" + export * + } + explicit module un { + header "sys/un.h" + export * + } + explicit module utsname { + header "sys/utsname.h" + export * + } +} +module _sys_select [system] { + // Note: this module is not part of + // 'sys_core' to prevent circular dependency error. + header "sys/select.h" + export * +} +// Use 'no_undeclared_includes' to avoid pulling in the libc++ module. +// This module depends on 'stdint.h', which is defined in libc++. +// We can't import libc++ as that would cause circular dependency +// between libc++ and this module. Using 'no_undeclared_includes' +// ensures that we include 'stdint.h' from usr/include instead of libc++. +module _sys_types [system] [no_undeclared_includes] { + header "sys/types.h" + // The 'sys/types.h' header has a circular include + // with 'bits/pthread_types.h' and thus it must be in the same module. + header "bits/pthread_types.h" + export * + use _stdint + use _sys_cdefs + use _Builtin_stddef +} +// Use 'no_undeclared_includes' to avoid pulling in the libc++ module. +// This module depends on 'stdint.h', which is defined in libc++. +// We can't import libc++ as that would cause circular dependency +// between libc++ and this module. Using 'no_undeclared_includes' +// ensures that we include 'stdint.h' from usr/include instead of libc++. +module _sys_user [system] [no_undeclared_includes] { + header "sys/user.h" + export * + use _stdint + use _sys_cdefs + use _Builtin_stddef +} + +// Module for zlib headers. +module zlib [system] { + header "zlib.h" + explicit module zconf { + header "zconf.h" + export * + } + export * + link "z" +} diff --git a/stdlib/public/RegexBuilder/CMakeLists.txt b/stdlib/public/RegexBuilder/CMakeLists.txt index 8db5dae116602..117cb57ee7f60 100644 --- a/stdlib/public/RegexBuilder/CMakeLists.txt +++ b/stdlib/public/RegexBuilder/CMakeLists.txt @@ -27,6 +27,7 @@ message(STATUS "Using Experimental String Processing library for RegexBuilder ($ add_swift_target_library(swiftRegexBuilder ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB "${REGEX_BUILDER_SOURCES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/public/StringProcessing/CMakeLists.txt b/stdlib/public/StringProcessing/CMakeLists.txt index 408e019e46644..c767dcff59f42 100644 --- a/stdlib/public/StringProcessing/CMakeLists.txt +++ b/stdlib/public/StringProcessing/CMakeLists.txt @@ -41,6 +41,7 @@ message(STATUS "Using Experimental String Processing library for _StringProcessi add_swift_target_library(swift_StringProcessing ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB "${STRING_PROCESSING_SOURCES}" + SWIFT_MODULE_DEPENDS_ANDROID Android SWIFT_MODULE_DEPENDS_LINUX Glibc SWIFT_MODULE_DEPENDS_FREEBSD Glibc SWIFT_MODULE_DEPENDS_OPENBSD Glibc diff --git a/stdlib/public/SwiftShims/swift/shims/RefCount.h b/stdlib/public/SwiftShims/swift/shims/RefCount.h index f218948704f10..9e1d04b0fedee 100644 --- a/stdlib/public/SwiftShims/swift/shims/RefCount.h +++ b/stdlib/public/SwiftShims/swift/shims/RefCount.h @@ -33,40 +33,40 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; #include #include +#include "HeapObject.h" #include "swift/Basic/type_traits.h" #include "swift/Runtime/Atomic.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Debug.h" #include "swift/Runtime/Heap.h" - /* - An object conceptually has three refcounts. These refcounts + An object conceptually has three refcounts. These refcounts are stored either "inline" in the field following the isa or in a "side table entry" pointed to by the field following the isa. - - The strong RC counts strong references to the object. When the strong RC - reaches zero the object is deinited, unowned reference reads become errors, + + The strong RC counts strong references to the object. When the strong RC + reaches zero the object is deinited, unowned reference reads become errors, and weak reference reads become nil. The strong RC is stored as an extra count: when the physical field is 0 the logical value is 1. - The unowned RC counts unowned references to the object. The unowned RC - also has an extra +1 on behalf of the strong references; this +1 is - decremented after deinit completes. When the unowned RC reaches zero + The unowned RC counts unowned references to the object. The unowned RC + also has an extra +1 on behalf of the strong references; this +1 is + decremented after deinit completes. When the unowned RC reaches zero the object's allocation is freed. - The weak RC counts weak references to the object. The weak RC also has an - extra +1 on behalf of the unowned references; this +1 is decremented - after the object's allocation is freed. When the weak RC reaches zero + The weak RC counts weak references to the object. The weak RC also has an + extra +1 on behalf of the unowned references; this +1 is decremented + after the object's allocation is freed. When the weak RC reaches zero the object's side table entry is freed. Objects initially start with no side table. They can gain a side table when: - * a weak reference is formed + * a weak reference is formed and pending future implementation: * strong RC or unowned RC overflows (inline RCs will be small on 32-bit) * associated object storage is needed on an object * etc - Gaining a side table entry is a one-way operation; an object with a side + Gaining a side table entry is a one-way operation; an object with a side table entry never loses it. This prevents some thread races. Strong and unowned variables point at the object. @@ -92,7 +92,7 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; atomic { strong RC + unowned RC + weak RC + flags } - } + } } InlineRefCounts and SideTableRefCounts share some implementation @@ -101,10 +101,10 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; InlineRefCountBits and SideTableRefCountBits share some implementation via RefCountBitsT. - In general: The InlineRefCounts implementation tries to perform the - operation inline. If the object has a side table it calls the - HeapObjectSideTableEntry implementation which in turn calls the - SideTableRefCounts implementation. + In general: The InlineRefCounts implementation tries to perform the + operation inline. If the object has a side table it calls the + HeapObjectSideTableEntry implementation which in turn calls the + SideTableRefCounts implementation. Downside: this code is a bit twisted. Upside: this code has less duplication than it might otherwise @@ -115,11 +115,11 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; The object is alive. Object's refcounts are initialized as 1 strong, 1 unowned, 1 weak. No side table. No weak RC storage. - Strong variable operations work normally. + Strong variable operations work normally. Unowned variable operations work normally. Weak variable load can't happen. Weak variable store adds the side table, becoming LIVE with side table. - When the strong RC reaches zero deinit() is called and the object + When the strong RC reaches zero deinit() is called and the object becomes DEINITING. LIVE with side table @@ -133,14 +133,14 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; Unowned variable store works normally. Weak variable load can't happen. Weak variable store stores nil. - When deinit() completes, the generated code calls swift_deallocObject. - swift_deallocObject calls canBeFreedNow() checking for the fast path - of no weak or unowned references. - If canBeFreedNow() the object is freed and it becomes DEAD. + When deinit() completes, the generated code calls swift_deallocObject. + swift_deallocObject calls canBeFreedNow() checking for the fast path + of no weak or unowned references. + If canBeFreedNow() the object is freed and it becomes DEAD. Otherwise, it decrements the unowned RC and the object becomes DEINITED. DEINITING with side table - Weak variable load returns nil. + Weak variable load returns nil. Weak variable store stores nil. canBeFreedNow() is always false, so it never transitions directly to DEAD. Everything else is the same as DEINITING. @@ -156,7 +156,7 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; DEINITED with side table Weak variable load returns nil. Weak variable store can't happen. - When the unowned RC reaches zero, the object is freed, the weak RC is + When the unowned RC reaches zero, the object is freed, the weak RC is decremented, and the object becomes FREED. Everything else is the same as DEINITED. @@ -169,7 +169,7 @@ typedef InlineRefCountsPlaceholder InlineRefCounts; Unowned variable operations can't happen. Weak variable load returns nil. Weak variable store can't happen. - When the weak RC reaches zero, the side table entry is freed and + When the weak RC reaches zero, the side table entry is freed and the object becomes DEAD. DEAD diff --git a/stdlib/public/Synchronization/Mutex/WasmImpl.swift b/stdlib/public/Synchronization/Mutex/WasmImpl.swift index 807eb3d8c64a9..8fa84b0ff4828 100644 --- a/stdlib/public/Synchronization/Mutex/WasmImpl.swift +++ b/stdlib/public/Synchronization/Mutex/WasmImpl.swift @@ -23,7 +23,7 @@ internal func _swift_stdlib_wait( @_extern(c, "llvm.wasm32.memory.atomic.notify") internal func _swift_stdlib_wake(on: UnsafePointer, count: UInt32) -extension Atomic where Value == UInt32 { +extension Atomic where Value == _MutexHandle.State { internal borrowing func _wait(expected: _MutexHandle.State) { _swift_stdlib_wait( on: .init(_rawAddress), diff --git a/test/AutoDiff/SILOptimizer/pullback_inlining.swift b/test/AutoDiff/SILOptimizer/pullback_inlining.swift index 431dd98064f58..fc0cc7f9f14f9 100644 --- a/test/AutoDiff/SILOptimizer/pullback_inlining.swift +++ b/test/AutoDiff/SILOptimizer/pullback_inlining.swift @@ -9,6 +9,8 @@ import _Differentiation #if canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #else import Foundation #endif diff --git a/test/AutoDiff/compiler_crashers_fixed/issue-56600-symbol-in-ir-file-not-tbd-file.swift b/test/AutoDiff/compiler_crashers_fixed/issue-56600-symbol-in-ir-file-not-tbd-file.swift index fe65a165c4f53..7a5e395dd6551 100644 --- a/test/AutoDiff/compiler_crashers_fixed/issue-56600-symbol-in-ir-file-not-tbd-file.swift +++ b/test/AutoDiff/compiler_crashers_fixed/issue-56600-symbol-in-ir-file-not-tbd-file.swift @@ -12,6 +12,8 @@ import _Differentiation import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/AutoDiff/stdlib/tgmath_derivatives.swift.gyb b/test/AutoDiff/stdlib/tgmath_derivatives.swift.gyb index 39535f5f1fb55..a4a81a6a28ac8 100644 --- a/test/AutoDiff/stdlib/tgmath_derivatives.swift.gyb +++ b/test/AutoDiff/stdlib/tgmath_derivatives.swift.gyb @@ -5,6 +5,8 @@ import Darwin.C.tgmath #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/AutoDiff/validation-test/custom_derivatives.swift b/test/AutoDiff/validation-test/custom_derivatives.swift index f28a233dd34b6..233c5819f40dd 100644 --- a/test/AutoDiff/validation-test/custom_derivatives.swift +++ b/test/AutoDiff/validation-test/custom_derivatives.swift @@ -6,6 +6,8 @@ import StdlibUnittest import Darwin.C #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/AutoDiff/validation-test/separate_tangent_type.swift b/test/AutoDiff/validation-test/separate_tangent_type.swift index 3770e240777e6..87796d5da6b5a 100644 --- a/test/AutoDiff/validation-test/separate_tangent_type.swift +++ b/test/AutoDiff/validation-test/separate_tangent_type.swift @@ -6,6 +6,8 @@ import StdlibUnittest import Darwin.C #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/CAS/module_deps.swift b/test/CAS/module_deps.swift index fd2957394c6df..7dab6878cf021 100644 --- a/test/CAS/module_deps.swift +++ b/test/CAS/module_deps.swift @@ -131,7 +131,8 @@ import SubE // CHECK-DAG: "swift": "Swift" // CHECK-DAG: "swift": "SwiftOnoneSupport" // CHECK: ], -// CHECK-NEXT: "details": { +// CHECK-NEXT: "linkLibraries": [ +// CHECK: "details": { // CHECK: "commandLine": [ // CHECK: "-compile-module-from-interface" diff --git a/test/CAS/module_deps_include_tree.swift b/test/CAS/module_deps_include_tree.swift index 813dd8a1a7782..ef5c38284ef20 100644 --- a/test/CAS/module_deps_include_tree.swift +++ b/test/CAS/module_deps_include_tree.swift @@ -130,7 +130,8 @@ import SubE // CHECK-DAG: "swift": "Swift" // CHECK-DAG: "swift": "SwiftOnoneSupport" // CHECK: ], -// CHECK-NEXT: "details": { +// CHECK-NEXT: "linkLibraries": [ +// CHECK: "details": { // CHECK: "commandLine": [ // CHECK: "-compile-module-from-interface" diff --git a/test/CAS/plugin_cas.swift b/test/CAS/plugin_cas.swift index a31f66b071f6f..78a592863cb6c 100644 --- a/test/CAS/plugin_cas.swift +++ b/test/CAS/plugin_cas.swift @@ -113,7 +113,8 @@ import SubE // CHECK-DAG: "swift": "Swift" // CHECK-DAG: "swift": "SwiftOnoneSupport" // CHECK: ], -// CHECK-NEXT: "details": { +// CHECK-NEXT: "linkLibraries": [ +// CHECK: "details": { // CHECK: "commandLine": [ // CHECK: "-compile-module-from-interface" diff --git a/test/ClangImporter/clang_builtins.swift b/test/ClangImporter/clang_builtins.swift index 4b73e96a45be1..24b83bcd6abd8 100644 --- a/test/ClangImporter/clang_builtins.swift +++ b/test/ClangImporter/clang_builtins.swift @@ -4,6 +4,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/test/Concurrency/Runtime/async.swift b/test/Concurrency/Runtime/async.swift index ad787c0d874ea..965819cbdf078 100644 --- a/test/Concurrency/Runtime/async.swift +++ b/test/Concurrency/Runtime/async.swift @@ -16,6 +16,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #endif var asyncTests = TestSuite("Async") diff --git a/test/Concurrency/Runtime/async_task_executor_and_serial_executor_nonisolated_async_func.swift b/test/Concurrency/Runtime/async_task_executor_and_serial_executor_nonisolated_async_func.swift index 0b41d5b39ce66..6da9272f2ce52 100644 --- a/test/Concurrency/Runtime/async_task_executor_and_serial_executor_nonisolated_async_func.swift +++ b/test/Concurrency/Runtime/async_task_executor_and_serial_executor_nonisolated_async_func.swift @@ -51,29 +51,29 @@ actor Worker { } func test(_ expectedExecutor: NaiveQueueExecutor) async { - // we are isolated to the serial-executor (!) - dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) - expectedExecutor.preconditionIsolated() - - // the nonisolated async func properly executes on the task-executor - await nonisolatedFunc(expectedExecutor: expectedExecutor) - - /// the task-executor preference is inherited properly: - async let val = { - dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) - expectedExecutor.preconditionIsolated() - return 12 - }() - _ = await val - +// // we are isolated to the serial-executor (!) +// dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) +// expectedExecutor.preconditionIsolated() +// +// // the nonisolated async func properly executes on the task-executor +// await nonisolatedFunc(expectedExecutor: expectedExecutor) +// +// /// the task-executor preference is inherited properly: +// async let val = { +// dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) +// expectedExecutor.preconditionIsolated() +// return 12 +// }() +// _ = await val +// // as expected not-inheriting _ = await Task.detached { dispatchPrecondition(condition: .notOnQueue(expectedExecutor.queue)) }.value - - // we properly came back to the serial executor, just to make sure - dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) - expectedExecutor.preconditionIsolated() +// +// // we properly came back to the serial executor, just to make sure +// dispatchPrecondition(condition: .onQueue(expectedExecutor.queue)) +// expectedExecutor.preconditionIsolated() } } @@ -84,8 +84,12 @@ actor Worker { let executor = NaiveQueueExecutor(queue) await Task(executorPreference: executor) { + print(">>> INSIDE TASK") let worker = Worker(on: executor) + print(">> AFTER WORKER") await worker.test(executor) + print(">> AFTER TEST()") }.value + print(">> AFTER TASK.VALUE") } } diff --git a/test/Concurrency/Runtime/async_task_executor_structured_concurrency.swift b/test/Concurrency/Runtime/async_task_executor_structured_concurrency.swift index 3d2805bf8274b..2122c20a69c8c 100644 --- a/test/Concurrency/Runtime/async_task_executor_structured_concurrency.swift +++ b/test/Concurrency/Runtime/async_task_executor_structured_concurrency.swift @@ -215,8 +215,8 @@ func expect(_ expected: MyTaskExecutor) { await testTaskGroup(firstExecutor, secondExecutor) - await testAsyncLet(firstExecutor, secondExecutor) - - await testGroupAsyncLet(firstExecutor, secondExecutor) +// await testAsyncLet(firstExecutor, secondExecutor) +// +// await testGroupAsyncLet(firstExecutor, secondExecutor) } } diff --git a/test/Concurrency/Runtime/async_task_executor_unstructured_task_ownership.swift b/test/Concurrency/Runtime/async_task_executor_unstructured_task_ownership.swift new file mode 100644 index 0000000000000..99b97844f85ac --- /dev/null +++ b/test/Concurrency/Runtime/async_task_executor_unstructured_task_ownership.swift @@ -0,0 +1,81 @@ +// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking %import-libdispatch -parse-as-library ) | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: concurrency +// REQUIRES: libdispatch + +// REQUIRES: concurrency_runtime +// UNSUPPORTED: back_deployment_runtime + +import Dispatch +import StdlibUnittest +import _Concurrency + +final class NaiveQueueExecutor: TaskExecutor { + let queue: DispatchQueue + + init(_ queue: DispatchQueue) { + print("init \(Self.self)") + self.queue = queue + } + + deinit { + print("deinit \(Self.self)") + } + + public func enqueue(_ _job: consuming ExecutorJob) { + print("Enqueue on \(Self.self)!") + let job = UnownedJob(_job) + queue.async { + job.runSynchronously(on: self.asUnownedTaskExecutor()) + } + } + + @inlinable + public func asUnownedTaskExecutor() -> UnownedTaskExecutor { + print("\(Self.self).\(#function)") + return UnownedTaskExecutor(ordinary: self) + } +} + +nonisolated func nonisolatedFunc(expectedQueue queue: DispatchQueue) async { +// dispatchPrecondition(condition: .onQueue(queue)) + print("Invoked: \(#function)") +} + +@main struct Main { + + static func main() async { + let queue = DispatchQueue(label: "example-queue") + var executor: NaiveQueueExecutor? = NaiveQueueExecutor(queue) + + // Task retains the executor, so it should never deinit before the task completes + // CHECK: init NaiveQueueExecutor + + // The concurrency runtime invokes the... + // CHECK: NaiveQueueExecutor.asUnownedTaskExecutor + + // And we enqueue on the task executor... + // CHECK: Enqueue on NaiveQueueExecutor + // CHECK: Task start + + let task = Task(executorPreference: executor!) { + print("Task start") + // CHECK: Invoked: nonisolatedFunc + await nonisolatedFunc(expectedQueue: queue) + print("Task done") + } + + executor = nil + print("In main: executor = nil") + + await task.value + // The executor is ONLY released after the task has completed, + // regardless when the reference in main() was released. + // CHECK: Task done + // CHECK-NEXT: deinit NaiveQueueExecutor + + print("Done") + // CHECK: Done + } +} diff --git a/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift b/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift index c0f7bda2805d7..bdb37734d35c0 100644 --- a/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift +++ b/test/Concurrency/Runtime/async_task_locals_copy_to_sync.swift @@ -18,6 +18,8 @@ import Dispatch import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #endif enum TL { diff --git a/test/Concurrency/Runtime/async_task_withUnsafeCurrentTask.swift b/test/Concurrency/Runtime/async_task_withUnsafeCurrentTask.swift index 8ac4ad2f1579e..d22049945b751 100644 --- a/test/Concurrency/Runtime/async_task_withUnsafeCurrentTask.swift +++ b/test/Concurrency/Runtime/async_task_withUnsafeCurrentTask.swift @@ -10,6 +10,8 @@ import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) +import Android #else import Darwin #endif @@ -36,4 +38,4 @@ func test_withUnsafeCurrentTask() async { static func main() async { await test_withUnsafeCurrentTask() } -} \ No newline at end of file +} diff --git a/test/Concurrency/Runtime/cancellation_handler.swift b/test/Concurrency/Runtime/cancellation_handler.swift index ba221c8592687..3cefaa5134469 100644 --- a/test/Concurrency/Runtime/cancellation_handler.swift +++ b/test/Concurrency/Runtime/cancellation_handler.swift @@ -12,6 +12,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif canImport(WASILibc) import WASILibc #elseif os(Windows) diff --git a/test/Concurrency/Runtime/data_race_detection_crash.swift b/test/Concurrency/Runtime/data_race_detection_crash.swift index 47238ede23127..2ab3ec805aa46 100644 --- a/test/Concurrency/Runtime/data_race_detection_crash.swift +++ b/test/Concurrency/Runtime/data_race_detection_crash.swift @@ -24,6 +24,8 @@ import Dispatch import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #endif @MainActor func onMainActor() { diff --git a/test/Concurrency/Runtime/data_race_detection_legacy_warning.swift b/test/Concurrency/Runtime/data_race_detection_legacy_warning.swift index dc891057d22f2..d7c270be925c4 100644 --- a/test/Concurrency/Runtime/data_race_detection_legacy_warning.swift +++ b/test/Concurrency/Runtime/data_race_detection_legacy_warning.swift @@ -25,6 +25,8 @@ import Dispatch import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #endif @MainActor func onMainActor() { @@ -66,14 +68,14 @@ actor MyActor { struct Runner { static func main() async { print("Launching a main-actor task") - // CHECK: data race detected: @MainActor function at main/data_race_detection_legacy_warning.swift:30 was not called on the main thread + // CHECK: data race detected: @MainActor function at main/data_race_detection_legacy_warning.swift:32 was not called on the main thread launchFromMainThread() sleep(1) let actor = MyActor() let actorFn = await actor.getTaskOnMyActor() print("Launching an actor-instance task") - // CHECK: data race detected: actor-isolated function at main/data_race_detection_legacy_warning.swift:59 was not called on the same actor + // CHECK: data race detected: actor-isolated function at main/data_race_detection_legacy_warning.swift:61 was not called on the same actor launchTask(actorFn) sleep(1) diff --git a/test/Concurrency/Runtime/exclusivity.swift b/test/Concurrency/Runtime/exclusivity.swift index 7e07776900f35..6bd44273e6bb0 100644 --- a/test/Concurrency/Runtime/exclusivity.swift +++ b/test/Concurrency/Runtime/exclusivity.swift @@ -31,6 +31,8 @@ var global3: Int = 7 import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #elseif canImport(CRT) import CRT #endif diff --git a/test/Concurrency/Runtime/exclusivity_custom_executors.swift b/test/Concurrency/Runtime/exclusivity_custom_executors.swift index 5e5d62fe495c1..f9f44d87aa6ec 100644 --- a/test/Concurrency/Runtime/exclusivity_custom_executors.swift +++ b/test/Concurrency/Runtime/exclusivity_custom_executors.swift @@ -26,6 +26,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #elseif canImport(CRT) import CRT #endif diff --git a/test/Concurrency/Runtime/executor_deinit3.swift b/test/Concurrency/Runtime/executor_deinit3.swift index 302ab4c67e91c..f6063c985157b 100644 --- a/test/Concurrency/Runtime/executor_deinit3.swift +++ b/test/Concurrency/Runtime/executor_deinit3.swift @@ -14,6 +14,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #endif @available(SwiftStdlib 5.1, *) diff --git a/test/Concurrency/async_main.swift b/test/Concurrency/async_main.swift index 08aee73185859..a962a4617e6c1 100644 --- a/test/Concurrency/async_main.swift +++ b/test/Concurrency/async_main.swift @@ -69,12 +69,13 @@ func asyncFunc() async { // CHECK-SIL-NEXT: [[FLAGS:%.*]] = struct $Int ([[T0]] : $Builtin.Int64) // CHECK-SIL-NEXT: [[OPT_SERIAL_EXECUTOR:%.*]] = enum $Optional, #Optional.none // CHECK-SIL-NEXT: [[GROUP:%.*]] = enum $Optional, #Optional.none -// CHECK-SIL-NEXT: [[TASK_EXECUTOR:%.*]] = enum $Optional, #Optional.none +// CHECK-SIL-NEXT: [[TASK_EXECUTOR_UNOWNED:%.*]] = enum $Optional, #Optional.none +// CHECK-SIL-NEXT: [[TASK_EXECUTOR_OWNED:%.*]] = enum $Optional, #Optional.none // CHECK-SIL-NEXT: // function_ref thunk for @escaping @convention(thin) @async () -> () // CHECK-SIL-NEXT: [[THUNK_FN:%.*]] = function_ref @$sIetH_yts5Error_pIeghHrzo_TR : $@convention(thin) @Sendable @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error) // CHECK-SIL-NEXT: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[ASYNC_MAIN_FN]]) : $@convention(thin) @Sendable @async (@convention(thin) @async () -> ()) -> (@out (), @error any Error) // CHECK-SIL-NEXT: [[CONVERTED_THUNK:%.*]] = convert_function [[THUNK]] : $@Sendable @async @callee_guaranteed () -> (@out (), @error any Error) to $@Sendable @async @callee_guaranteed @substituted <Ï„_0_0> () -> (@out Ï„_0_0, @error any Error) for <()> -// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR]] : $Optional, [[CONVERTED_THUNK]] : $@Sendable @async @callee_guaranteed @substituted <Ï„_0_0> () -> (@out Ï„_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) +// CHECK-SIL-NEXT: [[TASK_RESULT:%.*]] = builtin "createAsyncTask"<()>([[FLAGS]] : $Int, [[OPT_SERIAL_EXECUTOR]] : $Optional, [[GROUP]] : $Optional, [[TASK_EXECUTOR_UNOWNED]] : $Optional, [[TASK_EXECUTOR_OWNED]] : $Optional, [[CONVERTED_THUNK]] : $@Sendable @async @callee_guaranteed @substituted <Ï„_0_0> () -> (@out Ï„_0_0, @error any Error) for <()>) : $(Builtin.NativeObject, Builtin.RawPointer) // CHECK-SIL-NEXT: [[TASK:%.*]] = tuple_extract [[TASK_RESULT]] : $(Builtin.NativeObject, Builtin.RawPointer), 0 // CHECK-SIL-NEXT: // function_ref swift_job_run // CHECK-SIL-NEXT: [[RUN_FN:%.*]] = function_ref @swift_job_run : $@convention(thin) (UnownedJob, UnownedSerialExecutor) -> () diff --git a/test/Concurrency/async_task_base_priority.swift b/test/Concurrency/async_task_base_priority.swift index 76febb58c5887..763ef3ad14a14 100644 --- a/test/Concurrency/async_task_base_priority.swift +++ b/test/Concurrency/async_task_base_priority.swift @@ -21,6 +21,8 @@ import Dispatch import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #elseif os(WASI) import WASILibc #elseif os(Windows) diff --git a/test/Concurrency/sending_continuation.swift b/test/Concurrency/sending_continuation.swift index 211fd6bd1aa45..0f47af4cadae5 100644 --- a/test/Concurrency/sending_continuation.swift +++ b/test/Concurrency/sending_continuation.swift @@ -23,6 +23,12 @@ func withCheckedContinuation_1() async -> NonSendableKlass { } } +func withCheckedContinuation_1a() async -> NonSendableKlass { + await withCheckedContinuation { continuation in + continuation.resume(returning: NonSendableKlass()) + } +} + @MainActor func withCheckedContinuation_2() async -> NonSendableKlass { await withCheckedContinuation { continuation in @@ -34,6 +40,16 @@ func withCheckedContinuation_2() async -> NonSendableKlass { } } +func withCheckedContinuation_2a() async -> NonSendableKlass { + await withCheckedContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } +} + @MainActor func withCheckedContinuation_3() async { // x is main actor isolated since withCheckedContinuation is #isolated. @@ -49,6 +65,19 @@ func withCheckedContinuation_3() async { // expected-note @-2 {{sending main actor-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } +func withCheckedContinuation_3a() async { + let x = await withCheckedContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } + + // This is ok since x is disconnected. + await useValueAsync(x) +} + @MainActor func withCheckedContinuation_4() async { // x is main actor isolated since withCheckedContinuation is #isolated. @@ -64,6 +93,18 @@ func withCheckedContinuation_4() async { // expected-note @-2 {{sending main actor-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} } +func withCheckedContinuation_4a() async { + // x is main actor isolated since withCheckedContinuation is #isolated. + let y = NonSendableKlass() + let x = await withCheckedContinuation { continuation in + continuation.resume(returning: y) + // expected-error @-1 {{sending 'y' risks causing data races}} + // expected-note @-2 {{task-isolated 'y' is passed as a 'sending' parameter}} + useValue(y) + } + await useValueAsync(x) +} + @MainActor func testAsyncStream() { let (_, continuation) = AsyncStream.makeStream(of: NonSendableKlass.self) @@ -103,3 +144,90 @@ func withCheckedContinuation_4() async { useValue(x) // expected-note {{access can happen concurrently}} } } + +@MainActor +func withUnsafeContinuation_1() async -> NonSendableKlass { + await withUnsafeContinuation { continuation in + continuation.resume(returning: NonSendableKlass()) + } +} + +func withUnsafeContinuation_1a() async -> NonSendableKlass { + await withUnsafeContinuation { continuation in + continuation.resume(returning: NonSendableKlass()) + } +} + +@MainActor +func withUnsafeContinuation_2() async -> NonSendableKlass { + await withUnsafeContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } +} + +func withUnsafeContinuation_2a() async -> NonSendableKlass { + await withUnsafeContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } +} + +@MainActor +func withUnsafeContinuation_3() async { + // x is main actor isolated since withUnsafeContinuation is #isolated. + let x = await withUnsafeContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } + await useValueAsync(x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{sending main actor-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} +} + +func withUnsafeContinuation_3a() async { + let x = await withUnsafeContinuation { continuation in + let x = NonSendableKlass() + continuation.resume(returning: x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{'x' used after being passed as a 'sending' parameter}} + useValue(x) // expected-note {{access can happen concurrently}} + } + await useValueAsync(x) +} + +@MainActor +func withUnsafeContinuation_4() async { + // x is main actor isolated since withUnsafeContinuation is #isolated. + let y = NonSendableKlass() + let x = await withUnsafeContinuation { continuation in + continuation.resume(returning: y) + // expected-error @-1 {{sending 'y' risks causing data races}} + // expected-note @-2 {{main actor-isolated 'y' is passed as a 'sending' parameter}} + useValue(y) + } + await useValueAsync(x) + // expected-error @-1 {{sending 'x' risks causing data races}} + // expected-note @-2 {{sending main actor-isolated 'x' to nonisolated global function 'useValueAsync' risks causing data races between nonisolated and main actor-isolated uses}} +} + +func withUnsafeContinuation_4a() async { + // x is main actor isolated since withUnsafeContinuation is #isolated. + let y = NonSendableKlass() + let x = await withUnsafeContinuation { continuation in + continuation.resume(returning: y) + // expected-error @-1 {{sending 'y' risks causing data races}} + // expected-note @-2 {{task-isolated 'y' is passed as a 'sending' parameter}} + useValue(y) + } + await useValueAsync(x) +} diff --git a/test/IRGen/builtin_math.swift b/test/IRGen/builtin_math.swift index 3426c1ee085c4..956b2e2e0c5b2 100644 --- a/test/IRGen/builtin_math.swift +++ b/test/IRGen/builtin_math.swift @@ -6,6 +6,8 @@ import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/IRGen/marker_protocol.swift b/test/IRGen/marker_protocol.swift index 47612c50c4274..0cc2608bb81b2 100644 --- a/test/IRGen/marker_protocol.swift +++ b/test/IRGen/marker_protocol.swift @@ -14,7 +14,7 @@ extension Int: P { } extension Array: P where Element: P { } // No mention of the marker protocol for runtime type instantiation. -// CHECK-LABEL: @"$sSS_yptMD" = +// CHECK-LABEL: @"$sSS_15marker_protocol1P_ptMD" = // CHECK-SAME: @"symbolic SS_ypt" // CHECK-LABEL: @"$s15marker_protocol1QMp" = {{(dllexport |protected )?}}constant @@ -47,7 +47,7 @@ struct HasMarkers { // Note: no mention of marker protocols when forming a dictionary. // CHECK-LABEL: define{{.*}}@"$s15marker_protocol0A12InDictionaryypyF" -// CHECK: call ptr @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSS_yptMD") +// CHECK: call ptr @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSS_15marker_protocol1P_ptMD") public func markerInDictionary() -> Any { let dict: [String: P] = ["answer" : 42] return dict @@ -92,7 +92,7 @@ let v1 = (any C & P).self let v2 = C.self // CHECK-LABEL: define hidden swiftcc void @"$s15marker_protocol23testProtocolCompositionyyF"() -// CHECK: [[V1:%.*]] = call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s15marker_protocol1CCMD") +// CHECK: [[V1:%.*]] = call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s15marker_protocol1P_AA1CCXcMD") // CHECK: [[V2:%.*]] = load ptr, ptr @"$s15marker_protocol2v2AA1CCmvp" func testProtocolComposition() { print(v1 == v2) diff --git a/test/IRGen/marker_protocol_backdeploy.swift b/test/IRGen/marker_protocol_backdeploy.swift index cfbcf74f381c6..2e7f623dadf4a 100644 --- a/test/IRGen/marker_protocol_backdeploy.swift +++ b/test/IRGen/marker_protocol_backdeploy.swift @@ -20,8 +20,8 @@ protocol R { } // Suppress marker protocols when forming existentials at runtime public func takeAnyType(_: T.Type) { } -// CHECK-LABEL: define {{.*}}@"$s26marker_protocol_backdeploy1Q_AA1RpMa" -// CHECK: $s26marker_protocol_backdeploy1Q_AA1RpML +// CHECK-LABEL: define {{.*}}@"$ss8Sendable_26marker_protocol_backdeploy1QAB1RpMa" +// CHECK: ss8Sendable_26marker_protocol_backdeploy1QAB1RpML // CHECK-NOT: Sendable // CHECK: s26marker_protocol_backdeploy1QMp // CHECK-NOT: Sendable diff --git a/test/IRGen/sanitize_coverage.swift b/test/IRGen/sanitize_coverage.swift index af28df7424155..e7090acaab692 100644 --- a/test/IRGen/sanitize_coverage.swift +++ b/test/IRGen/sanitize_coverage.swift @@ -15,6 +15,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/Interop/Cxx/libc/include-glibc.swift b/test/Interop/Cxx/libc/include-libc.swift similarity index 58% rename from test/Interop/Cxx/libc/include-glibc.swift rename to test/Interop/Cxx/libc/include-libc.swift index 2d1dcdc6ea227..807e5681cc558 100644 --- a/test/Interop/Cxx/libc/include-glibc.swift +++ b/test/Interop/Cxx/libc/include-libc.swift @@ -3,12 +3,18 @@ // REQUIRES: executable_test // REQUIRES: OS=linux-gnu || OS=linux-android +#if canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android +#else +#error ("unsupported platform") +#endif import StdlibUnittest -var GlibcTests = TestSuite("GlibcTests") +var LibcTests = TestSuite("LibcTests") -GlibcTests.test("abs") { +LibcTests.test("abs") { expectEqual(42, abs(-42)) } diff --git a/test/Interpreter/dynamicReplacement_property_observer.swift b/test/Interpreter/dynamicReplacement_property_observer.swift index 9c3313e36c144..bbf47ecf410fe 100644 --- a/test/Interpreter/dynamicReplacement_property_observer.swift +++ b/test/Interpreter/dynamicReplacement_property_observer.swift @@ -17,6 +17,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT import WinSDK diff --git a/test/Interpreter/dynamic_replacement.swift b/test/Interpreter/dynamic_replacement.swift index 80f572e634fce..426532a1951d5 100644 --- a/test/Interpreter/dynamic_replacement.swift +++ b/test/Interpreter/dynamic_replacement.swift @@ -109,6 +109,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT import WinSDK diff --git a/test/Interpreter/dynamic_replacement_chaining.swift b/test/Interpreter/dynamic_replacement_chaining.swift index bd5579ed88528..940a361072bd2 100644 --- a/test/Interpreter/dynamic_replacement_chaining.swift +++ b/test/Interpreter/dynamic_replacement_chaining.swift @@ -30,6 +30,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT import WinSDK diff --git a/test/Interpreter/dynamic_replacement_without_previous_calls.swift b/test/Interpreter/dynamic_replacement_without_previous_calls.swift index a9dc7254d836a..233f52a6aa572 100644 --- a/test/Interpreter/dynamic_replacement_without_previous_calls.swift +++ b/test/Interpreter/dynamic_replacement_without_previous_calls.swift @@ -16,6 +16,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT import WinSDK diff --git a/test/Interpreter/protocol_composition_with_markers.swift b/test/Interpreter/protocol_composition_with_markers.swift index 9c45ef687a77b..c200dacbd843c 100644 --- a/test/Interpreter/protocol_composition_with_markers.swift +++ b/test/Interpreter/protocol_composition_with_markers.swift @@ -27,3 +27,34 @@ do { print(v1 == v2) // CHECK: true } + +@_marker +protocol Marker { +} + +do { + print(G.self) + // CHECK: G + + class D { + } + + print((D & Sendable).self) + // CHECK: D + + print((D & Sendable).self) + // CHECK: D + + print((any Marker & Sendable).self) + // CHECK: Any + + print((AnyObject & Sendable & Marker).self) + // CHECK: AnyObject + + func generic(_: T.Type) { + print((D & Sendable).self) + } + + generic(Int.self) + // CHECK: D +} diff --git a/test/Interpreter/rdar128667580.swift b/test/Interpreter/rdar128667580.swift new file mode 100644 index 0000000000000..428f5277eef5e --- /dev/null +++ b/test/Interpreter/rdar128667580.swift @@ -0,0 +1,27 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-clang %t/Impl.m -c -o %t/Test.o +// RUN: %target-build-swift %t/main.swift -import-objc-header %t/Test.h %t/Test.o -Xfrontend -disable-concrete-type-metadata-mangled-name-accessors -o %t/main +// RUN: %target-codesign %t/main +// RUN: %target-run %t/main | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: objc_interop +// REQUIRES: concurrency + +//--- Test.h +#import "Foundation/Foundation.h" + +@interface Test : NSObject { } +@end + +//--- Impl.m +#import "Test.h" + +@implementation Test +@end + +//--- main.swift +print((any Test & Sendable).self) +// CHECK: Test diff --git a/test/ModuleInterface/clang-args-transitive-availability.swift b/test/ModuleInterface/clang-args-transitive-availability.swift index dfc4df497cb38..61b5fa4c5d6ed 100644 --- a/test/ModuleInterface/clang-args-transitive-availability.swift +++ b/test/ModuleInterface/clang-args-transitive-availability.swift @@ -49,7 +49,8 @@ import ImportsMacroSpecificClangModule // CHECK-NEXT: ], // CHECK-NEXT: "directDependencies": [ // CHECK-NEXT: ], -// CHECK-NEXT: "details": { +// CHECK-NEXT: "linkLibraries": [ +// CHECK: "details": { // CHECK-NEXT: "clang": { // CHECK-NEXT: "moduleMapPath": "{{.*}}module.modulemap", // CHECK-NEXT: "contextHash": "{{.*}}", diff --git a/test/ModuleInterface/clang-session-transitive.swift b/test/ModuleInterface/clang-session-transitive.swift index 8bf1cd8314245..a1f2f27640aea 100644 --- a/test/ModuleInterface/clang-session-transitive.swift +++ b/test/ModuleInterface/clang-session-transitive.swift @@ -30,7 +30,8 @@ import TestModule // CHECK-NEXT: "swift": "SwiftOnoneSupport" // CHECK-NEXT: } // CHECK-NEXT: ], - // CHECK-NEXT: "details": { + // CHECK-NEXT: "linkLibraries": [ + // CHECK: "details": { // CHECK-NEXT: "swift": { // CHECK-NEXT: "moduleInterfacePath": // CHECK-NEXT: "compiledModuleCandidates": [ diff --git a/test/ModuleInterface/extension-transitive-availability.swift b/test/ModuleInterface/extension-transitive-availability.swift index a677fc4d6292c..201a74dafb6cf 100644 --- a/test/ModuleInterface/extension-transitive-availability.swift +++ b/test/ModuleInterface/extension-transitive-availability.swift @@ -31,7 +31,8 @@ func foo() { // CHECK-NEXT: "swift": "SwiftOnoneSupport" // CHECK-NEXT: } // CHECK-NEXT: ], -// CHECK-NEXT: "details": { +// CHECK-NEXT: "linkLibraries": [ +// CHECK: "details": { // CHECK-NEXT: "swift": { // CHECK-NEXT: "moduleInterfacePath": // CHECK-NEXT: "compiledModuleCandidates": [ diff --git a/test/Parse/inverses.swift b/test/Parse/inverses.swift index 0d92571e05d0f..3ddafa9340574 100644 --- a/test/Parse/inverses.swift +++ b/test/Parse/inverses.swift @@ -92,8 +92,6 @@ func what(one: ~Copyable..., // expected-error {{noncopyable type '~Copyable' ca struct A { struct B { struct C {} } } -typealias Z0 = (~Copyable).Type // expected-error{{constraint that suppresses conformance requires 'any'}}{{17-17=any }} -typealias Z1 = ~Copyable.Type // expected-error{{constraint that suppresses conformance requires 'any'}}{{16-16=any }} typealias Z2 = ~A.B.C // expected-error {{type 'A.B.C' cannot be suppressed}} typealias Z3 = ~A? // expected-error {{type 'A?' cannot be suppressed}} typealias Z4 = ~Rope // expected-error {{type 'Rope' cannot be suppressed}} @@ -120,13 +118,8 @@ func typeInExpression() { _ = X<(borrowing any ~Copyable) -> Void>() _ = ~Copyable.self // expected-error{{unary operator '~' cannot be applied to an operand of type '(any Copyable).Type'}} - _ = (~Copyable).self // expected-error{{constraint that suppresses conformance requires 'any'}}{{8-8=any }} _ = (any ~Copyable).self } -func param1(_ t: borrowing ~Copyable) {} // expected-error{{constraint that suppresses conformance requires 'any'}}{{28-28=any }} -func param2(_ t: ~Copyable.Type) {} // expected-error{{constraint that suppresses conformance requires 'any'}}{{18-18=any }} func param3(_ t: borrowing any ~Copyable) {} func param4(_ t: any ~Copyable.Type) {} - -func param3(_ t: borrowing ExtraNoncopyProto & ~Copyable) {} // expected-error{{constraint that suppresses conformance requires 'any'}}{{28-28=any }} diff --git a/test/Prototypes/BigInt.swift b/test/Prototypes/BigInt.swift index 532f926bffb7b..ca7725cede255 100644 --- a/test/Prototypes/BigInt.swift +++ b/test/Prototypes/BigInt.swift @@ -22,6 +22,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/SIL/OwnershipVerifier/extend_lifetime.sil b/test/SIL/OwnershipVerifier/extend_lifetime.sil new file mode 100644 index 0000000000000..b163880e17319 --- /dev/null +++ b/test/SIL/OwnershipVerifier/extend_lifetime.sil @@ -0,0 +1,224 @@ +// RUN: %target-sil-opt \ +// RUN: %s \ +// RUN: -enable-sil-verify-all=0 \ +// RUN: -enable-ossa-verify-complete \ +// RUN: -verify-continue-on-failure \ +// RUN: -sil-ownership-verifier-enable-testing \ +// RUN: -ownership-verifier-textual-error-dumper \ +// RUN: -o /dev/null \ +// RUN: 2>&1 | %FileCheck %s +// REQUIRES: asserts + +sil_stage canonical + +import Builtin + +class C {} + +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consume__before +// CHECK: SIL verification failed: extend_lifetime in non-dead-end +// CHECK: Verifying instruction: +// CHECK: [[C:%[^,]+]] = argument of bb0 +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consume__before +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consume__before +// CHECK: SIL verification failed: extend_lifetime use within unextended linear liveness boundary +// CHECK: Verifying instruction: +// CHECK: [[C]] +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consume__before +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consume__before +// CHECK-LABEL: SIL verification failed: extend_lifetime after last user block +// CHECK: Verifying instruction: +// CHECK: [[C]] +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consume__before +sil [ossa] @invalid__single__usefree_consume__before : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + extend_lifetime %c : $C + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consume__after +// CHECK: SIL verification failed: extend_lifetime in non-dead-end +// CHECK: Verifying instruction: +// CHECK: [[C:%[^,]+]] = argument of bb0 +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consume__after +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consume__after +// CHECK: SIL verification failed: extend_lifetime after last user block +// CHECK: Verifying instruction: +// CHECK: [[C]] = argument of bb0 +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consume__after +sil [ossa] @invalid__single__usefree_consume__after : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + destroy_value %c : $C + extend_lifetime %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: Begin Error in function invalid__single__usefree_consumefree +// CHECK: SIL verification failed: extend_lifetime in non-dead-end +// CHECK: Verifying instruction: +// CHECK: [[C:%[^,]+]] = argument of bb0 +// CHECK: -> extend_lifetime [[C]] +// CHECK-LABEL: End Error in function invalid__single__usefree_consumefree +sil [ossa] @invalid__single__usefree_consumefree : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + extend_lifetime %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-NOT: valid__loop_conditional__header_uses__after +sil [ossa] @valid__loop_conditional__header_uses__after : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + %b = begin_borrow %c : $C + end_borrow %b : $C + extend_lifetime %c : $C + br loop + +loop: + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: Error#: 0. Begin Error in Function: 'invalid__loop_conditional__header_uses__before' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C:%[^,]+]] = argument of bb0 +// CHECK: User: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK-LABEL: Error#: 0. End Error in Function: 'invalid__loop_conditional__header_uses__before' +// CHECK-LABEL: Error#: 1. Begin Error in Function: 'invalid__loop_conditional__header_uses__before' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C]] +// CHECK: User: end_borrow [[B]] +// CHECK-LABEL: Error#: 1. End Error in Function: 'invalid__loop_conditional__header_uses__before' +// CHECK-NOT: invalid__loop_conditional__header_uses__before +sil [ossa] @invalid__loop_conditional__header_uses__before : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + extend_lifetime %c : $C + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +loop: + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +sil [ossa] @invalid__loop_conditional__header_uses__between : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + %b = begin_borrow %c : $C + extend_lifetime %c : $C + end_borrow %b : $C + br loop + +loop: + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-NOT: valid__loop_conditional__loop_uses__after +sil [ossa] @valid__loop_conditional__loop_uses__after : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + extend_lifetime %c : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// TODO: Maybe this should be allowed. +// CHECK-LABEL: Error#: 0. Begin Error in Function: 'invalid__loop_conditional__loop_uses__before' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C:%[^,]+]] = argument of bb0 +// CHECK: User: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK-LABEL: Error#: 0. End Error in Function: 'invalid__loop_conditional__loop_uses__before' +// CHECK-LABEL: Error#: 1. Begin Error in Function: 'invalid__loop_conditional__loop_uses__before' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C]] = argument of bb0 +// CHECK: User: end_borrow [[B]] +// CHECK-LABEL: Error#: 1. End Error in Function: 'invalid__loop_conditional__loop_uses__before' +sil [ossa] @invalid__loop_conditional__loop_uses__before : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + br loop + +loop: + extend_lifetime %c : $C + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// TODO: Maybe this should be allowed. +// CHECK-LABEL: Error#: 0. Begin Error in Function: 'invalid__loop_conditional__loop_uses__between' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C:%[^,]+]] = argument of bb0 +// CHECK: User: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK-LABEL: Error#: 0. End Error in Function: 'invalid__loop_conditional__loop_uses__between' +// CHECK-LABEL: Error#: 1. Begin Error in Function: 'invalid__loop_conditional__loop_uses__between' +// CHECK: Found outside of lifetime use! +// CHECK: Value: [[C]] = argument of bb0 +// CHECK: User: end_borrow [[B]] +// CHECK-LABEL: Error#: 1. End Error in Function: 'invalid__loop_conditional__loop_uses__between' +sil [ossa] @invalid__loop_conditional__loop_uses__between : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + cond_br undef, exit, header + +header: + br loop + +loop: + %b = begin_borrow %c : $C + extend_lifetime %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} diff --git a/test/SIL/Parser/basic2.sil b/test/SIL/Parser/basic2.sil index d46ab403e596e..e86c8c0f5453d 100644 --- a/test/SIL/Parser/basic2.sil +++ b/test/SIL/Parser/basic2.sil @@ -332,3 +332,18 @@ bb0(%0 : @guaranteed $Klass): %9999 = tuple() return %9999 : $() } + +// CHECK-LABEL: sil [ossa] @test_extend_lifetime : {{.*}} { +// CHECK: bb0([[K:%[^,]+]] : +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: extend_lifetime [[K]] +// CHECK: br [[LOOP]] +// CHECK-LABEL: } // end sil function 'test_extend_lifetime' +sil [ossa] @test_extend_lifetime : $@convention(thin) (@owned Klass) -> () { +entry(%k : @owned $Klass): + br bb1 +bb1: + extend_lifetime %k : $Klass + br bb1 +} diff --git a/test/SIL/Serialization/basic2.sil b/test/SIL/Serialization/basic2.sil index 0ceb91db51ba9..2aa65d68c4f26 100644 --- a/test/SIL/Serialization/basic2.sil +++ b/test/SIL/Serialization/basic2.sil @@ -89,6 +89,21 @@ bb0(%0 : @owned $Builtin.NativeObject): return %9999 : $() } +// CHECK-LABEL: sil [ossa] @test_extend_lifetime : {{.*}} { +// CHECK: bb0([[K:%[^,]+]] : +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: extend_lifetime [[K]] +// CHECK: br [[LOOP]] +// CHECK-LABEL: } // end sil function 'test_extend_lifetime' +sil [ossa] @test_extend_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { +entry(%k : @owned $Builtin.NativeObject): + br bb1 +bb1: + extend_lifetime %k : $Builtin.NativeObject + br bb1 +} + // CHECK-LABEL: sil [ossa] @test_mark_dependence : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { // CHECK: [[MD1:%.*]] = mark_dependence %1 : $Builtin.NativeObject on %0 : $Builtin.NativeObject // CHECK: [[MD2:%.*]] = mark_dependence [nonescaping] [[MD1]] : $Builtin.NativeObject on %0 : $Builtin.NativeObject diff --git a/test/SIL/cloning.sil b/test/SIL/cloning.sil index 63734edab01a8..0aebe8ff30281 100644 --- a/test/SIL/cloning.sil +++ b/test/SIL/cloning.sil @@ -206,3 +206,23 @@ sil [ossa] @caller_specify_test : $@convention(thin) () -> () { %retval = apply %callee() : $@convention(thin) () -> () return %retval : $() } + + +// CHECK-LABEL: sil [ossa] @caller_extend_lifetime : {{.*}} { +// CHECK: bb0([[O:%[^,]+]] : +// CHECK: extend_lifetime [[O]] +// CHECK-LABEL: } // end sil function 'caller_extend_lifetime' +sil [always_inline] [ossa] @callee_extend_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { +entry(%o : @owned $Builtin.NativeObject): + br loop +loop: + extend_lifetime %o : $Builtin.NativeObject + br loop +} + +sil [ossa] @caller_extend_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { +entry(%o : @owned $Builtin.NativeObject): + %callee = function_ref @callee_extend_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () + %retval = apply %callee(%o) : $@convention(thin) (@owned Builtin.NativeObject) -> () + return %retval : $() +} diff --git a/test/SILOptimizer/c_string_optimization.swift b/test/SILOptimizer/c_string_optimization.swift index f859063c77d6d..2173bd0b4d122 100644 --- a/test/SILOptimizer/c_string_optimization.swift +++ b/test/SILOptimizer/c_string_optimization.swift @@ -10,6 +10,8 @@ import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/SILOptimizer/consume_operator_reinit_in_defer.swift b/test/SILOptimizer/consume_operator_reinit_in_defer.swift new file mode 100644 index 0000000000000..c3fcfc4f97e19 --- /dev/null +++ b/test/SILOptimizer/consume_operator_reinit_in_defer.swift @@ -0,0 +1,52 @@ +// RUN: %target-swift-frontend -emit-sil -verify %s + +func consume(_: consuming T) {} + +func testSingleBlock(x: inout T, y: T) { + defer { x = y } + consume(consume x) +} + +func cond() -> Bool { fatalError() } + +// TODO: should be accepted +func testAlwaysReinitAfterConditional(x: inout T, y: T) { // not-really expected-error{{used after consume}} + defer { + if cond() { } + x = y // not-really expected-note{{}} + } + consume(consume x) // not-really expected-note{{}} +} + +// TODO: should be accepted +func testAlwaysReinitBeforeConditional(x: inout T, y: T) { // not-really expected-error{{used after consume}} + defer { + x = y // not-really expected-note{{}} + if cond() { } + } + consume(consume x) // not-really expected-note{{}} +} + +// TODO: should be accepted +func testAlwaysReinitInBothBranchesOfConditional(x: inout T, y: T) { // not-really expected-error{{used after consume}} + defer { + if cond() { + x = y // not-really expected-note{{}} + } else { + x = y + } + } + consume(consume x) // not-really expected-note{{}} +} + +// TODO: should raise an error about inout not being reinitialized on all paths +func testSometimesReinitInConditional(x: inout T, y: T) { // not-really expected-error{{used after consume}} + defer { + if cond() { + x = y // not-really expected-note{{}} + } else { + // ex/pected-note {{not initialized on this path}} + } + } + consume(consume x) // not-really expected-note{{}} +} diff --git a/test/SILOptimizer/dead_code_elimination_ossa.sil b/test/SILOptimizer/dead_code_elimination_ossa.sil index 4032835de62f8..7f7e5d7cef1f6 100644 --- a/test/SILOptimizer/dead_code_elimination_ossa.sil +++ b/test/SILOptimizer/dead_code_elimination_ossa.sil @@ -13,6 +13,9 @@ typealias Int1 = Builtin.Int1 class C {} +sil @getC : $@convention(thin) () -> @owned C +sil @barrier : $@convention(thin) () -> () + struct CAndBit { var c: C var bit: Int1 @@ -468,3 +471,20 @@ bb3: %22 = tuple () return %22 : $() } + +// CHECK-LABEL: sil [ossa] @dont_delete_move_value_lexical : {{.*}} { +// CHECK: [[LEXICAL:%[^,]+]] = move_value [lexical] +// CHECK: [[DUMMY:%[^,]+]] = function_ref @dummy +// CHECK: apply [[DUMMY]]() +// CHECK: destroy_value [[LEXICAL]] +// CHECK-LABEL: } // end sil function 'dont_delete_move_value_lexical' +sil [ossa] @dont_delete_move_value_lexical : $@convention(thin) () -> () { + %getC = function_ref @getC : $@convention(thin) () -> @owned C + %c = apply %getC() : $@convention(thin) () -> @owned C + %m = move_value [lexical] %c : $C + %dummy = function_ref @dummy : $@convention(thin) () -> () + apply %dummy() : $@convention(thin) () -> () + destroy_value %m : $C + %retval = tuple () + return %retval : $() +} diff --git a/test/SILOptimizer/definite_init_inout_super_init.swift b/test/SILOptimizer/definite_init_inout_super_init.swift index 3979aa3875763..e744b56286804 100644 --- a/test/SILOptimizer/definite_init_inout_super_init.swift +++ b/test/SILOptimizer/definite_init_inout_super_init.swift @@ -1,4 +1,4 @@ -// RUN: %target-swiftc_driver -Xfrontend -disable-sil-ownership-verifier -emit-sil %s -o /dev/null -Xfrontend -verify +// RUN: %target-swiftc_driver -emit-sil %s -o /dev/null -Xfrontend -verify // TODO: Change this back to using target-swift-frontend once we move errors to // type checker and SILGen. diff --git a/test/SILOptimizer/ossa_lifetime_completion.sil b/test/SILOptimizer/ossa_lifetime_completion.sil index 3a56916259c70..eade9246275c1 100644 --- a/test/SILOptimizer/ossa_lifetime_completion.sil +++ b/test/SILOptimizer/ossa_lifetime_completion.sil @@ -27,6 +27,10 @@ case none case some(Wrapped) } +typealias AnyObject = Builtin.AnyObject + +protocol P : AnyObject {} + // CHECK-LABEL: begin running test 1 of 1 on eagerConsumneOwnedArg: ossa_lifetime_completion with: @argument // CHECK-LABEL: OSSA lifetime completion on liveness boundary: %0 = argument of bb0 : $C // CHECK: sil [ossa] @eagerConsumneOwnedArg : $@convention(thin) (@owned C) -> () { @@ -442,8 +446,8 @@ indirect enum IndirectEnumNontrivialPayload { // CHECK: [[ONE_CASE]]([[BOX:%[^,]+]] : // CHECK: [[C_ADDR:%[^,]+]] = project_box [[BOX]] // CHECK: [[C:%[^,]+]] = load_borrow [[C_ADDR]] -// CHECK: cond_br undef, {{bb[0-9]+}}, [[BASIC_BLOCK4:bb[0-9]+]] -// CHECK: [[BASIC_BLOCK4]]: +// CHECK: cond_br undef, {{bb[0-9]+}}, [[RIGHT:bb[0-9]+]] +// CHECK: [[RIGHT]]: // CHECK: end_borrow [[C]] // CHECK: dealloc_box [[BOX]] // CHECK: unreachable @@ -537,3 +541,186 @@ left: right: unreachable } + +// CHECK-LABEL: begin running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o +// CHECK: end_borrow +// CHECK-LABEL: end running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o +// CHECK-LABEL: begin running test {{.*}} on loopy: ossa_lifetime_completion +// CHECK-LABEL: sil [ossa] @loopy : {{.*}} { +// CHECK: [[O:%[^,]+]] = apply undef +// CHECK: [[B:%[^,]+]] = begin_borrow [[O]] +// CHECK: end_borrow [[B]] +// CHECK: extend_lifetime [[O]] +// CHECK: br bb1 +// CHECK: bb1: +// CHECK: br bb1 +// CHECK-LABEL: } // end sil function 'loopy' +// CHECK-LABEL: end running test {{.*}} on loopy: ossa_lifetime_completion +// CHECK-LABEL: begin running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o +// CHECK-NEXT: end running test {{.*}} on loopy: liveness_partial_boundary_outside_users with: %o +sil [ossa] @loopy : $@convention(thin) () -> () { + %o = apply undef() : $@convention(thin) () -> (@owned C) + specify_test "liveness_partial_boundary_outside_users %o" + specify_test "ossa_lifetime_completion %o availability" + specify_test "liveness_partial_boundary_outside_users %o" + %b = begin_borrow %o : $C + end_borrow %b : $C + br loop + +loop: + br loop +} + +sil [ossa] @loopyComplete : $@convention(thin) () -> () { + %o = apply undef() : $@convention(thin) () -> (@owned C) + specify_test "ossa_lifetime_completion %o availability" + specify_test "liveness_partial_boundary_outside_users %o" + %b = begin_borrow %o : $C + end_borrow %b : $C + extend_lifetime %o : $C + br loop + +loop: + br loop +} + +// When there are no users in the loop, do not extend the lifetime into it. +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes: ossa_lifetime_completion with: %c, availability +// CHECK-LABEL: sil [ossa] @loopy_sometimes : {{.*}} { +// CHECK-NOT: extend_lifetime +// CHECK-LABEL: } // end sil function 'loopy_sometimes' +// CHECK-LABEL: end running test {{.*}} on loopy_sometimes: ossa_lifetime_completion with: %c, availability +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes: liveness_partial_boundary_outside_users with: %c +// CHECK-NEXT: end running test {{.*}} on loopy_sometimes: liveness_partial_boundary_outside_users with: %c +sil [ossa] @loopy_sometimes : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "ossa_lifetime_completion %c availability" + specify_test "liveness_partial_boundary_outside_users %c" + cond_br undef, header, exit + +header: + br loop + +loop: + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// When there are no users in the loop, do not extend the lifetime into it. +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_guaranteed: ossa_lifetime_completion with: %b, availability +// CHECK-LABEL: sil [ossa] @loopy_sometimes_guaranteed : {{.*}} { +// CHECK-NOT: extend_lifetime +// CHECK-LABEL: } // end sil function 'loopy_sometimes_guaranteed' +// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_guaranteed: ossa_lifetime_completion with: %b, availability +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_guaranteed: liveness_partial_boundary_outside_users with: %b +// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_guaranteed: liveness_partial_boundary_outside_users with: %b +sil [ossa] @loopy_sometimes_guaranteed : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + %b = begin_borrow %c : $C + specify_test "ossa_lifetime_completion %b availability" + specify_test "liveness_partial_boundary_outside_users %b" + cond_br undef, header, exit + +header: + br loop + +loop: + br loop + +exit: + end_borrow %b : $C + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2: ossa_lifetime_completion with: %c, availability +// CHECK-LABEL: sil [ossa] @loopy_sometimes_2 : {{.*}} { +// CHECK: bb0([[O:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[O]] +// CHECK: end_borrow [[B]] +// CHECK: extend_lifetime [[O]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[O]] +// CHECK-LABEL: } // end sil function 'loopy_sometimes_2' +// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_2: ossa_lifetime_completion with: %c, availability +sil [ossa] @loopy_sometimes_2 : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "ossa_lifetime_completion %c availability" + specify_test "liveness_partial_boundary_outside_users %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2_guaranteed: ossa_lifetime_completion with: %c, availability +// CHECK-LABEL: sil [ossa] @loopy_sometimes_2_guaranteed : {{.*}} { +// CHECK: bb0([[C:%[^,]+]] : +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[I:%[^,]+]] = begin_borrow [[B]] +// CHECK: end_borrow [[I]] +// CHECK: extend_lifetime [[B]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: end_borrow [[B]] +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'loopy_sometimes_2_guaranteed' +// CHECK-LABEL: end running test {{.*}} on loopy_sometimes_2_guaranteed: ossa_lifetime_completion with: %c, availability +// CHECK-LABEL: begin running test {{.*}} on loopy_sometimes_2_guaranteed: liveness_partial_boundary_outside_users with: %c +// CHECK-NEXT: end running test {{.*}} on loopy_sometimes_2_guaranteed: liveness_partial_boundary_outside_users with: %c +sil [ossa] @loopy_sometimes_2_guaranteed : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + %b = begin_borrow %c : $C + specify_test "ossa_lifetime_completion %c availability" + specify_test "liveness_partial_boundary_outside_users %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %i = begin_borrow %b : $C + end_borrow %i : $C + br loop + +exit: + end_borrow %b : $C + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on type_dependent_operand: liveness_partial_boundary_outside_users +// There should be no out-of-boundary users. +// CHECK-NEXT: end running test {{.*}} on type_dependent_operand: liveness_partial_boundary_outside_users +sil [ossa] @type_dependent_operand : $@convention(thin) (@owned any P) -> @owned AnyObject { +bb0(%existential : @owned $any P): + %opened = open_existential_ref %existential : $any P to $@opened("00000000-0000-0000-0000-000000000000", any P) Self + specify_test "liveness_partial_boundary_outside_users %opened" + %ref_existential = init_existential_ref %opened : $@opened("00000000-0000-0000-0000-000000000000", any P) Self : $@opened("00000000-0000-0000-0000-000000000000", any P) Self, $AnyObject + return %ref_existential : $AnyObject +} diff --git a/test/SILOptimizer/ownership_liveness_unit.sil b/test/SILOptimizer/ownership_liveness_unit.sil index 058e4fd44012a..da72cdc2d3530 100644 --- a/test/SILOptimizer/ownership_liveness_unit.sil +++ b/test/SILOptimizer/ownership_liveness_unit.sil @@ -192,6 +192,109 @@ bb3(%outer : @guaranteed $C, %inner : @guaranteed $C): return %99 : $() } +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_incomplete_linear: linear-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_incomplete_linear : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: end_borrow [[B]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'testLoopConditional_incomplete_linear' +// CHECK: Linear liveness: [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: last user: destroy_value [[C]] +// CHECK: boundary edge: [[HEADER]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_incomplete_linear: linear-liveness +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_incomplete_linear: linear_liveness_swift +// CHECK: Linear liveness: [[C]] +// CHECK: Live blocks: +// CHECK: begin: cond_br undef, [[HEADER]], [[EXIT]] +// CHECK: ends: destroy_value [[C]] +// CHECK: exits: br [[LOOP]] +// CHECK: interiors: +// CHECK: last user: destroy_value [[C]] +// CHECK: boundary edge: +// CHECK-NEXT: [[HEADER]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_incomplete_linear: linear_liveness_swift +sil [ossa] @testLoopConditional_incomplete_linear : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "linear-liveness %c" + specify_test "linear_liveness_swift %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_complete_linear: linear-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_complete_linear : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: end_borrow [[B]] +// CHECK: extend_lifetime [[C]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'testLoopConditional_complete_linear' +// CHECK: Linear liveness: [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: [[LOOP]]: LiveOut +// CHECK: [[HEADER]]: LiveOut +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: regular user: extend_lifetime [[C]] +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_complete_linear: linear-liveness +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_complete_linear: linear_liveness_swift +// CHECK: Linear liveness: [[C]] +// CHECK: Live blocks: +// CHECK: begin: cond_br undef, [[HEADER]], [[EXIT]] +// CHECK: ends: destroy_value [[C]] +// CHECK: interiors: extend_lifetime [[C]] +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_complete_linear: linear_liveness_swift +sil [ossa] @testLoopConditional_complete_linear : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "linear-liveness %c" + specify_test "linear_liveness_swift %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + extend_lifetime %c : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + // ============================================================================= // visitInnerAdjacentPhis // ============================================================================= @@ -348,6 +451,123 @@ bb0(%0 : @owned $NCInt): return %99 : $() } +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_incomplete_interior: interior-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_incomplete_interior : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: end_borrow [[B]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'testLoopConditional_incomplete_interior' +// CHECK: Interior liveness: [[C]] +// CHECK: Inner scope: [[B]] = begin_borrow [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: [[LOOP]]: LiveOut +// CHECK: [[HEADER]]: LiveOut +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: regular user: end_borrow [[B]] +// CHECK: Complete liveness +// CHECK: Unenclosed phis { +// CHECK-NEXT: } +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_incomplete_interior: interior-liveness +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_incomplete_interior: interior_liveness_swift +// CHECK: Interior liveness: [[C]] +// CHECK: begin: cond_br undef, [[HEADER]], [[EXIT]] +// CHECK: ends: destroy_value [[C]] +// CHECK: exits: +// CHECK: interiors: end_borrow [[B]] +// CHECK: Unenclosed phis { +// CHECK-NEXT: } +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_incomplete_interior: interior_liveness_swift +sil [ossa] @testLoopConditional_incomplete_interior : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "interior-liveness %c" + specify_test "interior_liveness_swift %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_complete_interior: interior-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_complete_interior : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] : $C +// CHECK: end_borrow [[B]] : $C +// CHECK: extend_lifetime [[C]] : $C +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] : $C +// CHECK-LABEL: } // end sil function 'testLoopConditional_complete_interior' +// CHECK: Interior liveness: [[C]] +// CHECK: Inner scope: [[B]] = begin_borrow [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: [[LOOP]]: LiveOut +// CHECK: [[HEADER]]: LiveOut +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: regular user: extend_lifetime [[C]] +// CHECK: regular user: end_borrow [[B]] +// CHECK: Complete liveness +// CHECK: Unenclosed phis { +// CHECK-NEXT: } +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_complete_interior: interior-liveness + +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_complete_interior: interior_liveness_swift +// CHECK: Interior liveness: [[C]] +// CHECK: begin: cond_br undef, [[HEADER]], [[EXIT]] +// CHECK: ends: destroy_value [[C]] +// CHECK: exits: +// CHECK: interiors: extend_lifetime [[C]] +// CHECK: end_borrow [[B]] +// CHECK: Unenclosed phis { +// CHECK-NEXT: } +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_complete_interior: interior_liveness_swift +sil [ossa] @testLoopConditional_complete_interior : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "interior-liveness %c" + specify_test "interior_liveness_swift %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + extend_lifetime %c : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + // ============================================================================= // InteriorLiveness and visitAdjacentPhis // ============================================================================= @@ -1172,3 +1392,85 @@ bb3(%phi : @owned $C, %reborrow : @guaranteed $C): %99 = tuple() return %99 : $() } + +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_incomplete_extended: extended-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_incomplete_extended : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: end_borrow [[B]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'testLoopConditional_incomplete_extended' +// CHECK: Extended liveness: [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: last user: destroy_value [[C]] +// CHECK: boundary edge: [[HEADER]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_incomplete_extended: extended-liveness +sil [ossa] @testLoopConditional_incomplete_extended : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "extended-liveness %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} + +// CHECK-LABEL: begin running test {{.*}} on testLoopConditional_complete_extended: extended-liveness +// CHECK-LABEL: sil [ossa] @testLoopConditional_complete_extended : {{.*}} { +// CHECK: [[ENTRY:bb[0-9]+]]([[C:%[^,]+]] : +// CHECK: cond_br undef, [[HEADER:bb[0-9]+]], [[EXIT:bb[0-9]+]] +// CHECK: [[HEADER]]: +// CHECK: br [[LOOP:bb[0-9]+]] +// CHECK: [[LOOP]]: +// CHECK: [[B:%[^,]+]] = begin_borrow [[C]] +// CHECK: end_borrow [[B]] +// CHECK: extend_lifetime [[C]] +// CHECK: br [[LOOP]] +// CHECK: [[EXIT]]: +// CHECK: destroy_value [[C]] +// CHECK-LABEL: } // end sil function 'testLoopConditional_complete_extended' +// CHECK: Extended liveness: [[C]] +// CHECK: [[ENTRY]]: LiveOut +// CHECK: [[EXIT]]: LiveWithin +// CHECK: [[LOOP]]: LiveOut +// CHECK: [[HEADER]]: LiveOut +// CHECK: lifetime-ending user: destroy_value [[C]] +// CHECK: regular user: extend_lifetime [[C]] +// CHECK: last user: destroy_value [[C]] +// CHECK-LABEL: end running test {{.*}} on testLoopConditional_complete_extended: extended-liveness +sil [ossa] @testLoopConditional_complete_extended : $@convention(thin) (@owned C) -> () { +entry(%c : @owned $C): + specify_test "extended-liveness %c" + cond_br undef, header, exit + +header: + br loop + +loop: + %b = begin_borrow %c : $C + end_borrow %b : $C + extend_lifetime %c : $C + br loop + +exit: + destroy_value %c : $C + %retval = tuple () + return %retval : $() +} diff --git a/test/ScanDependencies/Inputs/CHeaders/module.modulemap b/test/ScanDependencies/Inputs/CHeaders/module.modulemap index c02240190d4e8..fb4fdf315dc9c 100644 --- a/test/ScanDependencies/Inputs/CHeaders/module.modulemap +++ b/test/ScanDependencies/Inputs/CHeaders/module.modulemap @@ -11,6 +11,7 @@ module B { module C [system] { header "C.h" export * + link framework "nonSwiftyLibC" } module D { diff --git a/test/ScanDependencies/Inputs/Swift/E.swiftinterface b/test/ScanDependencies/Inputs/Swift/E.swiftinterface index 824fe883f6b8d..d1fb4b2cb0a5f 100644 --- a/test/ScanDependencies/Inputs/Swift/E.swiftinterface +++ b/test/ScanDependencies/Inputs/Swift/E.swiftinterface @@ -1,4 +1,4 @@ // swift-interface-format-version: 1.0 -// swift-module-flags: -module-name E +// swift-module-flags: -module-name E -autolink-force-load -module-link-name swiftyLibE import Swift -public func funcE() { } \ No newline at end of file +public func funcE() { } diff --git a/test/ScanDependencies/module_deps_cache_reuse.swift b/test/ScanDependencies/module_deps_cache_reuse.swift index 51718ede38662..e8f3ebaa92cf2 100644 --- a/test/ScanDependencies/module_deps_cache_reuse.swift +++ b/test/ScanDependencies/module_deps_cache_reuse.swift @@ -94,6 +94,8 @@ import SubE // CHECK-DAG: "swift": "Swift" // CHECK-DAG: "swift": "SwiftOnoneSupport" // CHECK: ], +// CHECK-NEXT: "linkLibraries": [ +// CHECK-NEXT: ], // CHECK-NEXT: "details": { // CHECK: "commandLine": [ diff --git a/test/ScanDependencies/module_deps_different_paths_no_reuse.swift b/test/ScanDependencies/module_deps_different_paths_no_reuse.swift index 0afa3bab97918..f0d76411b46d0 100644 --- a/test/ScanDependencies/module_deps_different_paths_no_reuse.swift +++ b/test/ScanDependencies/module_deps_different_paths_no_reuse.swift @@ -27,6 +27,8 @@ import A // CHECK-INITIAL-SCAN-DAG: "swift": "Swift" // CHECK-INITIAL-SCAN-DAG: "swift": "SwiftOnoneSupport" // CHECK-INITIAL-SCAN: ], +// CHECK-INITIAL-SCAN-NEXT: "linkLibraries": [ +// CHECK-INITIAL-SCAN-NEXT: ], // CHECK-INITIAL-SCAN-NEXT: "details": { // CHECK-INITIAL-SCAN-NEXT: "swift": { // CHECK-INITIAL-SCAN-NEXT: "moduleInterfacePath": "{{.*}}/Swift/A.swiftinterface", @@ -39,6 +41,8 @@ import A // CHECK-DIFFERENT-DAG: "swift": "Swift" // CHECK-DIFFERENT-DAG: "swift": "SwiftOnoneSupport" // CHECK-DIFFERENT: ], +// CHECK-DIFFERENT-NEXT: "linkLibraries": [ +// CHECK-DIFFERENT-NEXT: ], // CHECK-DIFFERENT-NEXT: "details": { // CHECK-DIFFERENT-NEXT: "swift": { // CHECK-DIFFERENT-NEXT: "moduleInterfacePath": "{{.*}}/SwiftDifferent/A.swiftinterface", diff --git a/test/ScanDependencies/module_deps_link_libs.swift b/test/ScanDependencies/module_deps_link_libs.swift new file mode 100644 index 0000000000000..6b27388bc54cd --- /dev/null +++ b/test/ScanDependencies/module_deps_link_libs.swift @@ -0,0 +1,38 @@ +// RUN: %empty-directory(%t) +// REQUIRES: objc_interop + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift +// Check the contents of the JSON output +// RUN: %validate-json %t/deps.json | %FileCheck %s + +import C +import E +import G +import SubE + +// CHECK: "mainModuleName": "deps" + +// CHECK: "linkLibraries": [ +// CHECK-DAG: "linkName": "objc", +// CHECK-NEXT: "isFramework": false, +// CHECK-NEXT: "shouldForceLoad": false + +// CHECK-DAG: "linkName": "swiftCompatibilityConcurrency", +// CHECK-NEXT: "isFramework": false, +// CHECK-NEXT: "shouldForceLoad": true + +// CHECK-DAG: "linkName": "swiftCompatibility56", +// CHECK-NEXT: "isFramework": false, +// CHECK-NEXT: "shouldForceLoad": true + +// CHECK-DAG: "linkName": "swiftCompatibilityPacks", +// CHECK-NEXT: "isFramework": false, +// CHECK-NEXT: "shouldForceLoad": false + +// CHECK-DAG: "linkName": "swiftyLibE", +// CHECK-NEXT: "isFramework": false, +// CHECK-NEXT: "shouldForceLoad": true + +// CHECK-DAG: "linkName": "nonSwiftyLibC", +// CHECK-NEXT: "isFramework": true, +// CHECK-NEXT: "shouldForceLoad": false diff --git a/test/Sema/access-level-import-inconsistencies.swift b/test/Sema/access-level-import-inconsistencies.swift index 237f28203ac45..671babdf558df 100644 --- a/test/Sema/access-level-import-inconsistencies.swift +++ b/test/Sema/access-level-import-inconsistencies.swift @@ -8,7 +8,7 @@ /// Don't report any mismatch. // RUN: %empty-directory(%t) -// RUN: split-file %s %t +// RUN: split-file --leading-lines %s %t /// Build the library. // RUN: %target-swift-frontend -emit-module %t/Lib.swift -o %t @@ -68,6 +68,14 @@ import Lib //--- ManyFiles_AmbiguitySwift6_FileB.swift internal import Lib +/// Don't report an ambiguity between an explicitly vs implicitly public import. +// RUN: %target-swift-frontend -typecheck %t/ManyFiles_AmbiguityPublicExplicitVsImplicit_File?.swift -I %t \ +// RUN: -verify +//--- ManyFiles_AmbiguityPublicExplicitVsImplicit_FileA.swift +import Lib +//--- ManyFiles_AmbiguityPublicExplicitVsImplicit_FileB.swift +public import Lib // expected-warning {{public import of 'Lib' was not used in public declarations or inlinable code}} + /// Don't report inconsistencies from a file generated by Xcode. // RUN: %target-swift-frontend -typecheck -I %t \ // RUN -primary-file %t/GeneratedAssetSymbols.swift \ diff --git a/test/Sema/access-level-import-inconsistent-same-file.swift b/test/Sema/access-level-import-inconsistent-same-file.swift index a8e72c7ef8ebc..8fdf0d84dbc9c 100644 --- a/test/Sema/access-level-import-inconsistent-same-file.swift +++ b/test/Sema/access-level-import-inconsistent-same-file.swift @@ -63,10 +63,7 @@ internal import Lib1 // expected-warning {{module 'Lib1' is imported as 'public' // There's no warning about "will be ignored" for a matching implicit access level. public import Lib2 -// expected-note @-1 {{imported 'public' here}} import Lib2 -// expected-error @-1 {{ambiguous implicit access level for import of 'Lib2'; it is imported as 'public' elsewhere}} -// expected-note @-2 {{silence these warnings by adopting the upcoming feature 'InternalImportsByDefault'}} public func dummyAPI(t: Lib1.Type1, t2: Lib2.Type1) {} diff --git a/test/Sema/moveonly_casts.swift b/test/Sema/moveonly_casts.swift new file mode 100644 index 0000000000000..0762c7a44ac68 --- /dev/null +++ b/test/Sema/moveonly_casts.swift @@ -0,0 +1,125 @@ +// RUN: %target-typecheck-verify-swift + +struct NC: ~Copyable {} + +func testBorrowing(_ v: borrowing NC?) {} +func testConsuming(_ v: consuming NC?) {} +func testInout(_ v: inout NC?) {} + +class MethodSir { + func borrow(_ v: borrowing NC?) {} + func consume(_ v: consuming NC?) {} +} + +func testExplicitCasts() { + let nc = NC() + _ = nc as NC? +} + +func testCalls() { + let method = MethodSir() + let foo = NC() + testBorrowing(foo) // expected-error {{implicit conversion to 'NC?' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{17-17=consume }} + testBorrowing(consume foo) + testBorrowing(foo as NC?) + + method.borrow(foo) // expected-error {{implicit conversion to 'NC?' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{17-17=consume }} + method.borrow(consume foo) + + testConsuming(foo) + testConsuming(consume foo) + + var optNC: NC? = NC() // ConstraintLocator::ContextualType + testInout(&optNC) +} + +func testReturn() -> NC? { + let foo = NC() + return foo // ConstraintLocator::ContextualType +} + +func higherOrder(_ f: () -> NC?) -> NC? { + if let nc = f() { + nc // ConstraintLocator::ContextualType + } else { + nil + } +} +func callHigherOrder() { + let nc = NC() + let _ = higherOrder { nc } // ConstraintLocator::ClosureBody + + let _ = higherOrder { return nc } // ConstraintLocator::ClosureBody +} + + +func delay(_ f: @autoclosure () -> NC?) -> NC? { f() } + +func testDelay() { + let nc = NC() + let _ = delay(nc) // expected-error {{implicit conversion to 'NC?' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{17-17=consume }} +} + +struct PropCity { + var harmless1: NC? { NC() } + var harmless2: NC? { + get { return NC() } + } + + subscript(_ i: Int) -> NC? { return NC() } + + func chk(_ t: borrowing NC!) {} + func chkWithDefaultArg(_ oath: borrowing NC? = NC()) {} + func test(_ nc: consuming NC) { + chk(nc) // expected-error {{implicit conversion to 'NC?' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{9-9=consume }} + + chk(consume nc) + + chkWithDefaultArg() + chkWithDefaultArg(nc) // expected-error {{implicit conversion to 'NC?' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{23-23=consume }} + } +} + +protocol Veggie: ~Copyable {} +struct Carrot: ~Copyable, Veggie {} + +func restockBorrow(_ x: borrowing any Veggie & ~Copyable) {} +func restockConsume(_ x: consuming any Veggie & ~Copyable) {} + +func checkExistential() { + let carrot = Carrot() + restockBorrow(carrot) // expected-error {{implicit conversion to 'any Veggie & ~Copyable' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{17-17=consume }} + restockBorrow(consume carrot) + + restockConsume(carrot) +} + +func genericErasure(_ veg: consuming T) { + restockBorrow(veg) // expected-error {{implicit conversion to 'any Veggie & ~Copyable' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{17-17=consume }} + restockBorrow(consume veg) + restockBorrow(veg as any Veggie & ~Copyable) + restockConsume(veg) + + let _ = veg as any Veggie & ~Copyable +} + +extension Veggie where Self: ~Copyable { + func inspect(_ b: borrowing any Veggie & ~Copyable) {} +} +extension Carrot { + consuming func check() { + inspect(self) // expected-error {{implicit conversion to 'any Veggie & ~Copyable' is consuming}} + // expected-note@-1 {{add 'consume' to make consumption explicit}} {{13-13=consume }} + inspect(consume self) + inspect(self as any Veggie & ~Copyable) + + let _: any Veggie & ~Copyable = self + } +} diff --git a/test/Sema/superfluously-public-imports.swift b/test/Sema/superfluously-public-imports.swift index db3cfee2d23f2..e65eef4d93fc4 100644 --- a/test/Sema/superfluously-public-imports.swift +++ b/test/Sema/superfluously-public-imports.swift @@ -123,10 +123,8 @@ public struct Extended { //--- Client_Swift5.swift /// No diagnostics should be raised on the implicit access level. -import UnusedImport // expected-error {{ambiguous implicit access level for import of 'UnusedImport'; it is imported as 'public' elsewhere}} -// expected-note @-1 {{silence these warnings by adopting the upcoming feature 'InternalImportsByDefault'}} +import UnusedImport public import UnusedImport // expected-warning {{public import of 'UnusedImport' was not used in public declarations or inlinable code}} {{1-7=internal}} -// expected-note @-1 {{imported 'public' here}} //--- Client.swift public import DepUsedFromInlinableCode diff --git a/test/decl/protocol/protocols.swift b/test/decl/protocol/protocols.swift index 7458f99c2a421..b89db8820f24b 100644 --- a/test/decl/protocol/protocols.swift +++ b/test/decl/protocol/protocols.swift @@ -103,9 +103,9 @@ struct DoesNotConform : Up { // Circular protocols protocol CircleMiddle : CircleStart { func circle_middle() } -// expected-note@-1 2 {{protocol 'CircleMiddle' declared here}} -protocol CircleStart : CircleEnd { func circle_start() } // expected-error 2 {{protocol 'CircleStart' refines itself}} -protocol CircleEnd : CircleMiddle { func circle_end()} // expected-note 2 {{protocol 'CircleEnd' declared here}} +// expected-note@-1 3 {{protocol 'CircleMiddle' declared here}} +protocol CircleStart : CircleEnd { func circle_start() } // expected-error 3 {{protocol 'CircleStart' refines itself}} +protocol CircleEnd : CircleMiddle { func circle_end()} // expected-note 3 {{protocol 'CircleEnd' declared here}} protocol CircleEntry : CircleTrivial { } protocol CircleTrivial : CircleTrivial { } // expected-error {{protocol 'CircleTrivial' refines itself}} diff --git a/test/multifile/protocol-conformance-redundant.swift b/test/multifile/protocol-conformance-redundant.swift index f27a8a346b5d6..9a8814221e264 100644 --- a/test/multifile/protocol-conformance-redundant.swift +++ b/test/multifile/protocol-conformance-redundant.swift @@ -17,6 +17,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) +import Android #else #error("Unsupported platform") #endif diff --git a/test/stdlib/FloatConstants.swift b/test/stdlib/FloatConstants.swift index 3ed928a9d8848..0067e7df79cb0 100644 --- a/test/stdlib/FloatConstants.swift +++ b/test/stdlib/FloatConstants.swift @@ -6,6 +6,8 @@ import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/stdlib/MathConstants.swift b/test/stdlib/MathConstants.swift index 9cc0cd776a07f..bef16ab430d6b 100644 --- a/test/stdlib/MathConstants.swift +++ b/test/stdlib/MathConstants.swift @@ -6,6 +6,8 @@ import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/stdlib/POSIX.swift b/test/stdlib/POSIX.swift index c60aa771c0000..42b9edb5f4123 100644 --- a/test/stdlib/POSIX.swift +++ b/test/stdlib/POSIX.swift @@ -9,6 +9,8 @@ import SwiftPrivateLibcExtras import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/test/stdlib/PrintFloat.swift.gyb b/test/stdlib/PrintFloat.swift.gyb index 78d51cd67abae..5377a6d2b2467 100644 --- a/test/stdlib/PrintFloat.swift.gyb +++ b/test/stdlib/PrintFloat.swift.gyb @@ -19,6 +19,8 @@ import SwiftPrivateLibcExtras import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/stdlib/Runtime.swift.gyb b/test/stdlib/Runtime.swift.gyb index c4f872f1961e7..6d5ef26e90559 100644 --- a/test/stdlib/Runtime.swift.gyb +++ b/test/stdlib/Runtime.swift.gyb @@ -17,6 +17,8 @@ import SwiftShims import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT import WinSDK diff --git a/test/stdlib/VarArgs.swift b/test/stdlib/VarArgs.swift index 139f66c8bfb90..b3f65d0bd6b03 100644 --- a/test/stdlib/VarArgs.swift +++ b/test/stdlib/VarArgs.swift @@ -27,6 +27,9 @@ runAllTests() #elseif os(WASI) import WASILibc typealias CGFloat = Double +#elseif canImport(Android) + import Android + typealias CGFloat = Double #elseif os(Windows) import CRT #if arch(x86_64) || arch(arm64) diff --git a/test/stdlib/mmap.swift b/test/stdlib/mmap.swift index cf335bf81810f..2695875543911 100644 --- a/test/stdlib/mmap.swift +++ b/test/stdlib/mmap.swift @@ -8,6 +8,10 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android + // MAP_FAILED is not available on android. + let MAP_FAILED = UnsafeMutableRawPointer(bitPattern: -1) #else #error("Unsupported platform") #endif diff --git a/test/stdlib/tgmath_optimized.swift b/test/stdlib/tgmath_optimized.swift index 1d6de6ba3b7ee..369a7e8ab1266 100644 --- a/test/stdlib/tgmath_optimized.swift +++ b/test/stdlib/tgmath_optimized.swift @@ -10,6 +10,8 @@ import Glibc #elseif os(WASI) import WASILibc +#elseif canImport(Android) + import Android #elseif os(Windows) import CRT #else diff --git a/test/type/explicit_existential.swift b/test/type/explicit_existential.swift index 7075d0fbe88da..1b9f8632cd97c 100644 --- a/test/type/explicit_existential.swift +++ b/test/type/explicit_existential.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -enable-experimental-feature NoncopyableGenerics protocol HasSelfRequirements { func foo(_ x: Self) @@ -57,6 +57,9 @@ typealias T2 = any Pub & Bar protocol HasAssoc { associatedtype Assoc func foo() + + typealias HasAssoc_Alias = HasAssoc + typealias Int_Alias = Int } do { @@ -279,61 +282,214 @@ do { let _: Codable } -func testAnyFixIt() { - struct ConformingType : HasAssoc { - typealias Assoc = Int - func foo() {} +protocol HasAssocGeneric { + associatedtype Assoc +} - func method() -> any HasAssoc {} +protocol NonCopyableHasAssoc: ~Copyable { + associatedtype Assoc +} + +func testAnyFixIt() { + struct S { + typealias HasAssoc_Alias = HasAssoc + typealias HasAssocGeneric_Alias = HasAssocGeneric + typealias Copyable_Alias = Copyable + + typealias G = Self + typealias NonCopyable_G = Self + typealias S = Self } + typealias G = S + typealias NonCopyable_G = S // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=any HasAssoc}} - let _: HasAssoc = ConformingType() + let _: HasAssoc + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-19=any ~Copyable}} + let _: ~Copyable + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} + let _: (HasAssoc) + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-21=any ~(Copyable)}} + let _: ~(Copyable) // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{19-27=any HasAssoc}} - let _: Optional = nil + let _: Optional + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{19-28=any ~Copyable}} + let _: Optional<~Copyable> + // FIXME: No fix-it + generic argument not diagnosed. + // expected-error@+1 {{use of protocol 'HasAssocGeneric' as a type must be written 'any HasAssocGeneric'}}{{none}} + let _: HasAssocGeneric + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{14-22=any HasAssoc}} + let _: S.G + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{26-35=any ~Copyable}} + let _: S.NonCopyable_G<~Copyable> + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + let _: G.S + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.S + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{24-32=any HasAssoc}} + let _: G.G + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{49-58=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.NonCopyable_G<~Copyable> + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{24-32=any HasAssoc}} + let _: G.G.S + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{49-58=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.NonCopyable_G<~Copyable>.S + // expected-error@+1 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{10-26=any S.HasAssoc_Alias}} + let _: S.HasAssoc_Alias + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-27=any ~S.Copyable_Alias}} + let _: ~S.Copyable_Alias + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{10-36=any G.HasAssoc_Alias}} + let _: G.HasAssoc_Alias + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{13-21=any HasAssoc}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-37=any ~G.Copyable_Alias}} + let _: ~G.Copyable_Alias + // FIXME: No fix-it + generic argument not diagnosed. + // expected-error@+1 {{use of 'HasAssocGeneric' as a type must be written 'any HasAssocGeneric}}{{none}} + let _: S.HasAssocGeneric_Alias + // FIXME: No diagnostic. + let _: HasAssoc.Int_Alias + let _: HasAssoc.HasAssoc_Alias.Int_Alias // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=any HasAssoc.Type}} - let _: HasAssoc.Type = ConformingType.self + let _: HasAssoc.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-24=any ~Copyable.Type}} + let _: ~Copyable.Type + // expected-error@+1 {{type 'any Copyable.Type' cannot be suppressed}} + let _: ~(Copyable.Type) // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-25=any (HasAssoc).Type}} - let _: (HasAssoc).Type = ConformingType.self + let _: (HasAssoc).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=any (~Copyable).Type}} + let _: (~Copyable).Type // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-27=any ((HasAssoc)).Type}} - let _: ((HasAssoc)).Type = ConformingType.self + let _: ((HasAssoc)).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-28=any ((~Copyable)).Type}} + let _: ((~Copyable)).Type + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-28=any HasAssoc.Type.Type}} + let _: HasAssoc.Type.Type + // expected-error@+1 {{type 'any Copyable.Type.Type' cannot be suppressed}} + let _: ~Copyable.Type.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=any (~Copyable).Type.Type}} + let _: (~Copyable).Type.Type + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-30=any (HasAssoc.Type).Type}} + let _: (HasAssoc.Type).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=any (~Copyable.Type).Type}} + let _: (~Copyable.Type).Type // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}} let _: HasAssoc.Protocol = HasAssoc.self + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{33-41=any HasAssoc}} + let _: (HasAssoc).Protocol = (HasAssoc).self + // expected-error@+1 {{type '(any Copyable).Type' cannot be suppressed}} + let _: ~Copyable.Protocol + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{34-43=any ~Copyable}} + let _: (~Copyable).Protocol = (~Copyable).self + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} + let _: HasAssoc.Protocol.Type.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable).Protocol.Type.Type do { - struct Wrapper { - typealias HasAssocAlias = HasAssoc - } - let wrapperMeta: Wrapper.Type + let meta: S.Type // FIXME: What is the correct fix-it for the initializer? // - // expected-error@+2:20 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{12-33=(any Wrapper.HasAssocAlias)}} - // expected-error@+1:57 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{57-70=(any HasAssocAlias)}} - let _: Wrapper.HasAssocAlias.Protocol = wrapperMeta.HasAssocAlias.self + // expected-error@+2:14 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{12-28=(any S.HasAssoc_Alias)}} + // expected-error@+1:45 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{45-59=(any HasAssoc_Alias)}} + let _: S.HasAssoc_Alias.Protocol = meta.HasAssoc_Alias.self } + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=(any HasAssoc.Type)}} + let _: HasAssoc.Type.Protocol + // expected-error@+1 {{type '(any Copyable.Type).Type' cannot be suppressed}} + let _: ~Copyable.Type.Protocol + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=(any (~Copyable).Type)}} + let _: (~Copyable).Type.Protocol + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-28=(any HasAssoc.Type.Type)}} + let _: HasAssoc.Type.Type.Protocol + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=(any (~Copyable).Type.Type)}} + let _: (~Copyable).Type.Type.Protocol + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} + let _: HasAssoc? + // expected-error@+1 {{type '(any Copyable)?' cannot be suppressed}} + let _: ~Copyable? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} - let _: (HasAssoc).Protocol = (any HasAssoc).self + let _: (HasAssoc)? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable)? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} - let _: HasAssoc? = ConformingType() + let _: HasAssoc! + // expected-error@+2 {{type '(any Copyable)?' cannot be suppressed}} + // expected-warning@+1 {{using '!' is not allowed here; treating this as '?' instead}} + let _: ~Copyable! + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable)! // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=(any HasAssoc.Type)}} - let _: HasAssoc.Type? = ConformingType.self + let _: HasAssoc.Type? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=(any (~Copyable).Type)}} + let _: (~Copyable).Type? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} - let _: HasAssoc.Protocol? = (any HasAssoc).self + let _: HasAssoc.Protocol? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable).Protocol? + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{21-29=any HasAssoc}} + let _: (borrowing HasAssoc) -> Void + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{21-30=any ~Copyable}} + let _: (borrowing ~Copyable) -> Void + // https://github.com/apple/swift/issues/72588 + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=any HasAssoc}} + let _: any HasAssocGeneric + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{30-39=any ~Copyable}} + let _: any HasAssocGeneric<~Copyable> + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{16-24=any HasAssoc}} + let _: any G.HasAssoc_Alias + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{17-25=any HasAssoc}} + let _: any ~G.Copyable_Alias + do { + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{22-30=any HasAssoc}} + func f(_: some G.HasAssoc_Alias) {} + } + // https://github.com/apple/swift/issues/65027 + // expected-error@+2:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}} + // expected-error@+1:21 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}} + let _: HasAssoc & HasAssoc + // expected-error@+2:10 {{constraint that suppresses conformance requires 'any'}}{{10-31=any ~Copyable & ~Copyable}} + // expected-error@+1:22 {{constraint that suppresses conformance requires 'any'}}{{10-31=any ~Copyable & ~Copyable}} + let _: ~Copyable & ~Copyable + // expected-error@+3:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + // expected-error@+2:22 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + // expected-error@+1:33 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + let _: HasAssoc & (HasAssoc & HasAssoc) + // expected-error@+3:10 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + // expected-error@+2:23 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + // expected-error@+1:35 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + let _: ~Copyable & (~Copyable & ~Copyable) + + // Misc. compound cases. + + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{21-52=any NonCopyableHasAssoc & ~Copyable}} + // expected-error@+1 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{21-52=any NonCopyableHasAssoc & ~Copyable}} + let _: (borrowing NonCopyableHasAssoc & ~Copyable) -> Void + // expected-error@+3:15 {{constraint that suppresses conformance requires 'any'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + // expected-error@+2:28 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + // expected-error@+1:51 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + let _: (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type? + let _: any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type // OK + + // Misplaced '?'. // expected-error@+1 {{optional 'any' type must be written '(any HasAssoc)?'}}{{10-23=(any HasAssoc)?}} - let _: any HasAssoc? = nil + let _: any HasAssoc? + // FIXME: Better recovery + // expected-error@+1 {{type '(any Copyable)?' cannot be suppressed}} + let _: any ~Copyable? // expected-error@+1 {{optional 'any' type must be written '(any HasAssoc.Type)?'}}{{10-28=(any HasAssoc.Type)?}} - let _: any HasAssoc.Type? = nil - - do { - struct Outer { - struct Inner {} - } - - // expected-error@+2:18 {{must be written 'any HasAssoc'}} - // expected-error@+1:34 {{must be written 'any HasAssoc'}} - let _: Outer.Inner - } + let _: any HasAssoc.Type? + // FIXME: Better recovery + // expected-error@+1 {{type '(any Copyable.Type)?' cannot be suppressed}} + let _: any ~Copyable.Type? } func testNestedMetatype() { diff --git a/test/type/explicit_existential_swift6.swift b/test/type/explicit_existential_swift6.swift index 90e98414fc3b0..212a4c37e63b7 100644 --- a/test/type/explicit_existential_swift6.swift +++ b/test/type/explicit_existential_swift6.swift @@ -62,6 +62,9 @@ typealias T2 = any Pub & Bar protocol HasAssoc { associatedtype Assoc func foo() + + typealias HasAssoc_Alias = HasAssoc + typealias Int_Alias = Int } do { @@ -91,7 +94,7 @@ func testHasAssoc(_ x: Any, _: any HasAssoc) { func method() -> any HasAssoc {} func existentialArray() -> [any HasAssoc] {} - func existentialcSequence() -> any Sequence {} + func existentialcSequence() -> any Sequence {} } } @@ -311,61 +314,214 @@ do { let _: Codable } -func testAnyFixIt() { - struct ConformingType : HasAssoc { - typealias Assoc = Int - func foo() {} +protocol HasAssocGeneric { + associatedtype Assoc +} - func method() -> any HasAssoc {} +protocol NonCopyableHasAssoc: ~Copyable { + associatedtype Assoc +} + +func testAnyFixIt() { + struct S { + typealias HasAssoc_Alias = HasAssoc + typealias HasAssocGeneric_Alias = HasAssocGeneric + typealias Copyable_Alias = Copyable + + typealias G = Self + typealias NonCopyable_G = Self + typealias S = Self } + typealias G = S + typealias NonCopyable_G = S // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=any HasAssoc}} - let _: HasAssoc = ConformingType() + let _: HasAssoc + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-19=any ~Copyable}} + let _: ~Copyable + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} + let _: (HasAssoc) + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-21=any ~(Copyable)}} + let _: ~(Copyable) // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{19-27=any HasAssoc}} - let _: Optional = nil + let _: Optional + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{19-28=any ~Copyable}} + let _: Optional<~Copyable> + // FIXME: No fix-it + generic argument not diagnosed. + // expected-error@+1 {{use of protocol 'HasAssocGeneric' as a type must be written 'any HasAssocGeneric'}}{{none}} + let _: HasAssocGeneric + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{14-22=any HasAssoc}} + let _: S.G + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{26-35=any ~Copyable}} + let _: S.NonCopyable_G<~Copyable> + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + let _: G.S + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.S + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{24-32=any HasAssoc}} + let _: G.G + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{49-58=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.NonCopyable_G<~Copyable> + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{24-32=any HasAssoc}} + let _: G.G.S + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{24-33=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{49-58=any ~Copyable}} + let _: NonCopyable_G<~Copyable>.NonCopyable_G<~Copyable>.S + // expected-error@+1 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{10-26=any S.HasAssoc_Alias}} + let _: S.HasAssoc_Alias + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-27=any ~S.Copyable_Alias}} + let _: ~S.Copyable_Alias + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{12-20=any HasAssoc}} + // expected-error@+1 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{10-36=any G.HasAssoc_Alias}} + let _: G.HasAssoc_Alias + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{13-21=any HasAssoc}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-37=any ~G.Copyable_Alias}} + let _: ~G.Copyable_Alias + // FIXME: No fix-it + generic argument not diagnosed. + // expected-error@+1 {{use of 'HasAssocGeneric' as a type must be written 'any HasAssocGeneric}}{{none}} + let _: S.HasAssocGeneric_Alias + // FIXME: No diagnostic. + let _: HasAssoc.Int_Alias + let _: HasAssoc.HasAssoc_Alias.Int_Alias // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=any HasAssoc.Type}} - let _: HasAssoc.Type = ConformingType.self + let _: HasAssoc.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-24=any ~Copyable.Type}} + let _: ~Copyable.Type + // expected-error@+1 {{type 'any Copyable.Type' cannot be suppressed}} + let _: ~(Copyable.Type) // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-25=any (HasAssoc).Type}} - let _: (HasAssoc).Type = ConformingType.self + let _: (HasAssoc).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=any (~Copyable).Type}} + let _: (~Copyable).Type // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-27=any ((HasAssoc)).Type}} - let _: ((HasAssoc)).Type = ConformingType.self + let _: ((HasAssoc)).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-28=any ((~Copyable)).Type}} + let _: ((~Copyable)).Type + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-28=any HasAssoc.Type.Type}} + let _: HasAssoc.Type.Type + // expected-error@+1 {{type 'any Copyable.Type.Type' cannot be suppressed}} + let _: ~Copyable.Type.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=any (~Copyable).Type.Type}} + let _: (~Copyable).Type.Type + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-30=any (HasAssoc.Type).Type}} + let _: (HasAssoc.Type).Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=any (~Copyable.Type).Type}} + let _: (~Copyable.Type).Type // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}} let _: HasAssoc.Protocol = HasAssoc.self + // expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{33-41=any HasAssoc}} + let _: (HasAssoc).Protocol = (HasAssoc).self + // expected-error@+1 {{type '(any Copyable).Type' cannot be suppressed}} + let _: ~Copyable.Protocol + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{34-43=any ~Copyable}} + let _: (~Copyable).Protocol = (~Copyable).self + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} + let _: HasAssoc.Protocol.Type.Type + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable).Protocol.Type.Type do { - struct Wrapper { - typealias HasAssocAlias = HasAssoc - } - let wrapperMeta: Wrapper.Type + let meta: S.Type // FIXME: What is the correct fix-it for the initializer? // - // expected-error@+2:20 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{12-33=(any Wrapper.HasAssocAlias)}} - // expected-error@+1:57 {{use of 'Wrapper.HasAssocAlias' (aka 'HasAssoc') as a type must be written 'any Wrapper.HasAssocAlias' (aka 'any HasAssoc')}}{{57-70=(any HasAssocAlias)}} - let _: Wrapper.HasAssocAlias.Protocol = wrapperMeta.HasAssocAlias.self + // expected-error@+2:14 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{12-28=(any S.HasAssoc_Alias)}} + // expected-error@+1:45 {{use of 'S.HasAssoc_Alias' (aka 'HasAssoc') as a type must be written 'any S.HasAssoc_Alias' (aka 'any HasAssoc')}}{{45-59=(any HasAssoc_Alias)}} + let _: S.HasAssoc_Alias.Protocol = meta.HasAssoc_Alias.self } + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=(any HasAssoc.Type)}} + let _: HasAssoc.Type.Protocol + // expected-error@+1 {{type '(any Copyable.Type).Type' cannot be suppressed}} + let _: ~Copyable.Type.Protocol + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=(any (~Copyable).Type)}} + let _: (~Copyable).Type.Protocol + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-28=(any HasAssoc.Type.Type)}} + let _: HasAssoc.Type.Type.Protocol + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-31=(any (~Copyable).Type.Type)}} + let _: (~Copyable).Type.Type.Protocol + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} + let _: HasAssoc? + // expected-error@+1 {{type '(any Copyable)?' cannot be suppressed}} + let _: ~Copyable? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-19=any HasAssoc}} - let _: (HasAssoc).Protocol = (any HasAssoc).self + let _: (HasAssoc)? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable)? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} - let _: HasAssoc? = ConformingType() + let _: HasAssoc! + // expected-error@+2 {{type '(any Copyable)?' cannot be suppressed}} + // expected-warning@+1 {{using '!' is not allowed here; treating this as '?' instead}} + let _: ~Copyable! + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable)! // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-23=(any HasAssoc.Type)}} - let _: HasAssoc.Type? = ConformingType.self + let _: HasAssoc.Type? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{10-26=(any (~Copyable).Type)}} + let _: (~Copyable).Type? // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}} - let _: HasAssoc.Protocol? = (any HasAssoc).self + let _: HasAssoc.Protocol? + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{11-20=any ~Copyable}} + let _: (~Copyable).Protocol? + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{21-29=any HasAssoc}} + let _: (borrowing HasAssoc) -> Void + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{21-30=any ~Copyable}} + let _: (borrowing ~Copyable) -> Void + // https://github.com/apple/swift/issues/72588 + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=any HasAssoc}} + let _: any HasAssocGeneric + // expected-error@+1 {{constraint that suppresses conformance requires 'any'}}{{30-39=any ~Copyable}} + let _: any HasAssocGeneric<~Copyable> + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{16-24=any HasAssoc}} + let _: any G.HasAssoc_Alias + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{17-25=any HasAssoc}} + let _: any ~G.Copyable_Alias + do { + // expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{22-30=any HasAssoc}} + func f(_: some G.HasAssoc_Alias) {} + } + // https://github.com/apple/swift/issues/65027 + // expected-error@+2:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}} + // expected-error@+1:21 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}} + let _: HasAssoc & HasAssoc + // expected-error@+2:10 {{constraint that suppresses conformance requires 'any'}}{{10-31=any ~Copyable & ~Copyable}} + // expected-error@+1:22 {{constraint that suppresses conformance requires 'any'}}{{10-31=any ~Copyable & ~Copyable}} + let _: ~Copyable & ~Copyable + // expected-error@+3:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + // expected-error@+2:22 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + // expected-error@+1:33 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-42=any HasAssoc & (HasAssoc & HasAssoc)}} + let _: HasAssoc & (HasAssoc & HasAssoc) + // expected-error@+3:10 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + // expected-error@+2:23 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + // expected-error@+1:35 {{constraint that suppresses conformance requires 'any'}}{{10-45=any ~Copyable & (~Copyable & ~Copyable)}} + let _: ~Copyable & (~Copyable & ~Copyable) + + // Misc. compound cases. + + // expected-error@+2 {{constraint that suppresses conformance requires 'any'}}{{21-52=any NonCopyableHasAssoc & ~Copyable}} + // expected-error@+1 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{21-52=any NonCopyableHasAssoc & ~Copyable}} + let _: (borrowing NonCopyableHasAssoc & ~Copyable) -> Void + // expected-error@+3:15 {{constraint that suppresses conformance requires 'any'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + // expected-error@+2:28 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + // expected-error@+1:51 {{use of protocol 'NonCopyableHasAssoc' as a type must be written 'any NonCopyableHasAssoc'}}{{10-88=(any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type)}} + let _: (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type? + let _: any (((((~Copyable) & NonCopyableHasAssoc) & NonCopyableHasAssoc).Type.Type)).Type // OK + + // Misplaced '?'. // expected-error@+1 {{optional 'any' type must be written '(any HasAssoc)?'}}{{10-23=(any HasAssoc)?}} - let _: any HasAssoc? = nil + let _: any HasAssoc? + // FIXME: Better recovery + // expected-error@+1 {{type '(any Copyable)?' cannot be suppressed}} + let _: any ~Copyable? // expected-error@+1 {{optional 'any' type must be written '(any HasAssoc.Type)?'}}{{10-28=(any HasAssoc.Type)?}} - let _: any HasAssoc.Type? = nil - - do { - struct Outer { - struct Inner {} - } - - // expected-error@+2:18 {{must be written 'any HasAssoc'}} - // expected-error@+1:34 {{must be written 'any HasAssoc'}} - let _: Outer.Inner - } + let _: any HasAssoc.Type? + // FIXME: Better recovery + // expected-error@+1 {{type '(any Copyable.Type)?' cannot be suppressed}} + let _: any ~Copyable.Type? } func testNestedMetatype() { diff --git a/tools/libSwiftScan/libSwiftScan.cpp b/tools/libSwiftScan/libSwiftScan.cpp index a334772ef6345..7575a2b6a14a1 100644 --- a/tools/libSwiftScan/libSwiftScan.cpp +++ b/tools/libSwiftScan/libSwiftScan.cpp @@ -93,11 +93,22 @@ void swiftscan_dependency_info_details_dispose( delete details_impl; } +void swiftscan_link_library_set_dispose(swiftscan_link_library_set_t *set) { + for (size_t i = 0; i < set->count; ++i) { + auto info = set->link_libraries[i]; + swiftscan_string_dispose(info->name); + delete info; + } + delete[] set->link_libraries; + delete set; +} + void swiftscan_dependency_info_dispose(swiftscan_dependency_info_t info) { swiftscan_string_dispose(info->module_name); swiftscan_string_dispose(info->module_path); swiftscan_string_set_dispose(info->source_files); swiftscan_string_set_dispose(info->direct_dependencies); + swiftscan_link_library_set_dispose(info->link_libraries); swiftscan_dependency_info_details_dispose(info->details); delete info; } @@ -260,11 +271,32 @@ swiftscan_string_set_t *swiftscan_module_info_get_direct_dependencies( return info->direct_dependencies; } + +swiftscan_link_library_set_t *swiftscan_module_info_get_link_libraries( + swiftscan_dependency_info_t info) { + return info->link_libraries; +} + swiftscan_module_details_t swiftscan_module_info_get_details(swiftscan_dependency_info_t info) { return info->details; } +//=== Link Library Info query APIs -----------------------------------===// + +swiftscan_string_ref_t +swiftscan_link_library_info_get_link_name(swiftscan_link_library_info_t info) { + return info->name; +} +bool +swiftscan_link_library_info_get_is_framework(swiftscan_link_library_info_t info) { + return info->isFramework; +} +bool +swiftscan_link_library_info_get_should_force_load(swiftscan_link_library_info_t info) { + return info->forceLoad; +} + //=== Swift Textual Module Details query APIs -----------------------------===// swiftscan_dependency_info_kind_t diff --git a/tools/libSwiftScan/libSwiftScan.exports b/tools/libSwiftScan/libSwiftScan.exports index 2232eb027a6c8..6d804a9a0632c 100644 --- a/tools/libSwiftScan/libSwiftScan.exports +++ b/tools/libSwiftScan/libSwiftScan.exports @@ -1,10 +1,14 @@ swiftscan_dependency_graph_get_main_module_name swiftscan_dependency_graph_get_dependencies swiftscan_dependency_graph_get_diagnostics +swiftscan_link_library_info_get_link_name +swiftscan_link_library_info_get_is_framework +swiftscan_link_library_info_get_should_force_load swiftscan_module_info_get_module_name swiftscan_module_info_get_module_path swiftscan_module_info_get_source_files swiftscan_module_info_get_direct_dependencies +swiftscan_module_info_get_link_libraries swiftscan_module_info_get_details swiftscan_module_detail_get_kind swiftscan_swift_textual_detail_get_module_interface_path diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 342601c6bdb4b..0c0cfd1ebf511 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -1770,6 +1770,28 @@ skip-test-tvos skip-test-osx +#===------------------------------------------------------------------------===# +# PR testing presets +#===------------------------------------------------------------------------===# + +[preset: pr_apple_llvm_project_linux] + +llvm-cmake-options=-DCLANG_DEFAULT_LINKER=gold + +foundation +libicu +libdispatch +test + +release + +lldb +lldb-test-swift-only + +skip-test-cmark +skip-test-swift +skip-test-foundation + #===------------------------------------------------------------------------===# # Mixins for LLBuild, SwiftPM and downstream package project PR tests. #===------------------------------------------------------------------------===# diff --git a/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildCrashesDuringShutdown.swift b/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildCrashesDuringShutdown.swift index b596a2015b9b3..0408bc81bf5ee 100644 --- a/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildCrashesDuringShutdown.swift +++ b/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildCrashesDuringShutdown.swift @@ -10,6 +10,8 @@ import StdlibUnittest import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildExitsDuringShutdown.swift b/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildExitsDuringShutdown.swift index 888274eb243d9..e024a0e070810 100644 --- a/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildExitsDuringShutdown.swift +++ b/validation-test/StdlibUnittest/ChildProcessShutdown/FailIfChildExitsDuringShutdown.swift @@ -8,6 +8,8 @@ import StdlibUnittest import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/StdlibUnittest/ChildProcessShutdown/PassIfChildCrashedDuringTestExecution.swift b/validation-test/StdlibUnittest/ChildProcessShutdown/PassIfChildCrashedDuringTestExecution.swift index 77af5601fd0be..8687bde2c1843 100644 --- a/validation-test/StdlibUnittest/ChildProcessShutdown/PassIfChildCrashedDuringTestExecution.swift +++ b/validation-test/StdlibUnittest/ChildProcessShutdown/PassIfChildCrashedDuringTestExecution.swift @@ -8,6 +8,8 @@ import StdlibUnittest import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/StdlibUnittest/ChildProcessShutdown/RequireOwnProcess.swift b/validation-test/StdlibUnittest/ChildProcessShutdown/RequireOwnProcess.swift index 2bfa62c5252bd..a74e4a25165d8 100644 --- a/validation-test/StdlibUnittest/ChildProcessShutdown/RequireOwnProcess.swift +++ b/validation-test/StdlibUnittest/ChildProcessShutdown/RequireOwnProcess.swift @@ -8,6 +8,8 @@ import StdlibUnittest import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/StdlibUnittest/Stdin.swift b/validation-test/StdlibUnittest/Stdin.swift index 056a92c9ca04e..a6c144e56eabd 100644 --- a/validation-test/StdlibUnittest/Stdin.swift +++ b/validation-test/StdlibUnittest/Stdin.swift @@ -10,6 +10,8 @@ import StdlibUnittest import Glibc #elseif os(Windows) import MSVCRT +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/stdlib/Glibc.swift b/validation-test/stdlib/Glibc.swift index 70276d29e0b81..1b004367078a8 100644 --- a/validation-test/stdlib/Glibc.swift +++ b/validation-test/stdlib/Glibc.swift @@ -6,7 +6,7 @@ // UNSUPPORTED: OS=tvos // UNSUPPORTED: OS=watchos -// REQUIRES: OS=linux-gnu || OS=linux-androideabi || OS=linux-android +// REQUIRES: OS=linux-gnu import Swift import StdlibUnittest diff --git a/validation-test/stdlib/POSIXErrorCode.swift b/validation-test/stdlib/POSIXErrorCode.swift index 2d3a442cd125e..5f126a314ffcb 100644 --- a/validation-test/stdlib/POSIXErrorCode.swift +++ b/validation-test/stdlib/POSIXErrorCode.swift @@ -10,6 +10,8 @@ import StdlibUnittest import Darwin #elseif canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #else #error("Unsupported platform") #endif diff --git a/validation-test/stdlib/String.swift b/validation-test/stdlib/String.swift index 32de3fa68542c..cc2219af7e73f 100644 --- a/validation-test/stdlib/String.swift +++ b/validation-test/stdlib/String.swift @@ -1235,6 +1235,8 @@ StringTests.test("Conversions") { #if canImport(Glibc) import Glibc +#elseif canImport(Android) + import Android #endif StringTests.test("lowercased()") {