diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 20773c55c28cf..5b96dbed8d3f9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,313 +1,2 @@ -# Lines starting with '#' are comments. -# Each line is a case-sensitive file pattern followed by one or more owners. -# Order is important. The last matching pattern has the most precedence. -# More information: https://docs.github.com/en/articles/about-code-owners -# -# Please mirror the repository's file hierarchy in case-sensitive lexicographic -# order. - -# TODO: /.clang-format - -/.clang-tidy @egorzhdan - -# TODO: /.dir-locals.el -# TODO: /.flake8 -# TODO: /.gitattributes - -# .github -/.github/ @shahmishal -/.github/CODEOWNERS @AnthonyLatsis @shahmishal -/.github/ISSUE_TEMPLATE/ @AnthonyLatsis @hborla @LucianoPAlmeida @shahmishal @xedin -/.github/PULL_REQUEST_TEMPLATE.md @AnthonyLatsis @hborla @LucianoPAlmeida @shahmishal @xedin - -# TODO: /.gitignore -# TODO: /.mailmap -# TODO: /Brewfile -# TODO: /CHANGELOG.md -# TODO: /CMakeLists.txt -# TODO: /CODE_OF_CONDUCT.md -# TODO: /CODE_OWNERS.TXT -# TODO: /CONTRIBUTING.md -# TODO: /LICENSE.txt -# TODO: /README.md - -# Runtimes -/Runtimes/**/*.cmake @etcwilde @compnerd @edymtt @justice-adams-apple -/Runtimes/**/CMakeLists.txt @etcwilde @compnerd @edymtt @justice-adams-apple -/Runtimes/Core/cmake/caches/Vendors/Apple/ @etcwilde @shahmishal @edymtt @justice-adams-apple -/Runtimes/Core/cmake/modules/ExperimentalFeatures.cmake @tshortli @etcwilde @compnerd @edymtt @justice-adams-apple - -# SwiftCompilerSources -/SwiftCompilerSources @eeckstein - -# apinotes -# TODO: /apinotes - -# benchmark -/benchmark @eeckstein - -# bindings -# TODO: /bindings - -# cmake -/cmake/**/*Windows* @compnerd - -# docs -/docs/ABI/ @rjmccall -/docs/ABI/*Mangling* @eeckstein -/docs/ABI/GenericSignature.md @slavapestov -/docs/ABI/KeyPaths.md @jckarter -/docs/ABI/RegisterUsage.md @al45tair -/docs/CrossCompilationModel.md @MaxDesiatov -/docs/Generics @slavapestov -/docs/HowToGuides/ @AnthonyLatsis @LucianoPAlmeida @xedin -/docs/Optimizer* @eeckstein -/docs/SIL* @jckarter -/docs/Windows* @compnerd - -# include -/include/swift-c/DependencyScan/ @artemcm @cachemeifyoucan -/include/swift/*Demangl*/ @rjmccall -/include/swift/AST/ @hborla @slavapestov @xedin -/include/swift/AST/*Availability* @tshortli -/include/swift/AST/*Conformance* @slavapestov -/include/swift/AST/*Demangl* @rjmccall -/include/swift/AST/*Distributed* @ktoso -/include/swift/AST/*Generic* @hborla @slavapestov -/include/swift/AST/*Protocol* @hborla @slavapestov -/include/swift/AST/*Requirement* @hborla @slavapestov -/include/swift/AST/*Substitution* @slavapestov -/include/swift/AST/DiagnosticGroup* @DougGregor -/include/swift/AST/DiagnosticsClangImporter.def @zoecarver @egorzhdan @beccadax @ian-twilightcoder @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/include/swift/AST/DiagnosticsDriver.def @artemcm -/include/swift/AST/DiagnosticsFrontend.def @artemcm @tshortli -/include/swift/AST/DiagnosticsIDE.def @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/AST/DiagnosticsIRGen.def @rjmccall -/include/swift/AST/DiagnosticsModuleDiffer.def @nkcsgexi -/include/swift/AST/DiagnosticsParse.def @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/include/swift/AST/DiagnosticsRefactoring.def @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/AST/DiagnosticsSIL.def @jckarter -/include/swift/AST/Evaluator* @CodaFi @slavapestov -/include/swift/Basic/ @DougGregor -/include/swift/Basic/Features.def @DougGregor @hborla -/include/swift/ClangImporter @zoecarver @egorzhdan @beccadax @ian-twilightcoder @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/include/swift/DependencyScan @artemcm @cachemeifyoucan -/include/swift/Driver*/ @artemcm -/include/swift/Frontend*/ @artemcm @tshortli -/include/swift/IDE/ @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/IRGen/ @rjmccall -/include/swift/Index/ @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/Markup/ @nkcsgexi -/include/swift/Migrator/ @nkcsgexi -/include/swift/Option/*Options* @tshortli -/include/swift/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/include/swift/PrintAsClang @zoecarver @egorzhdan @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/include/swift/Refactoring @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/Runtime/ @rjmccall @compnerd -/include/swift/SIL/ @jckarter -/include/swift/SIL/*Coverage* @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/SIL/*DebugInfo* @adrian-prantl -/include/swift/SIL/SILDebug* @adrian-prantl -/include/swift/SIL/SILProfiler.h @ahoppen @bnbarham @hamishknight @rintaro -/include/swift/SILOptimizer/ @eeckstein -/include/swift/SILOptimizer/Utils/Distributed* @ktoso -/include/swift/Sema/ @hborla @slavapestov @xedin -/include/swift/Sema/CS* @hborla @xedin -/include/swift/Sema/Constraint* @hborla @xedin -/include/swift/Serialization/ @xymus -/include/swift/Serialization/SerializedModuleLoader* @artemcm -/include/swift/SwiftRemoteMirror/ @slavapestov -/include/swift/SymbolGraphGen/ @QuietMisdreavus -/include/swift/Threading @al45tair - -# lib -/lib/*Demangl*/ @rjmccall -/lib/AST/ @hborla @slavapestov @xedin -/lib/AST/*Availability* @tshortli -/lib/AST/*Conformance* @slavapestov -/lib/AST/*Demangl* @rjmccall -/lib/AST/*Generic* @hborla @slavapestov -/lib/AST/*Requirement* @hborla @slavapestov -/lib/AST/*Substitution @slavapestov -/lib/AST/ASTPrinter.cpp @hborla @slavapestov @xedin @tshortli -/lib/AST/Evaluator* @CodaFi @slavapestov -/lib/AST/ModuleLoader.cpp @artemcm -/lib/AST/RequirementMachine/ @slavapestov -/lib/ASTGen/ @ahoppen @bnbarham @CodaFi @hamishknight @rintaro -/lib/Basic/ @DougGregor -/lib/Basic/Windows @compnerd -/lib/ClangImporter @zoecarver @egorzhdan @beccadax @ian-twilightcoder @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/lib/ClangImporter/DWARFImporter* @adrian-prantl -/lib/DependencyScan @artemcm @cachemeifyoucan -/lib/Driver*/ @artemcm -/lib/DriverTool/autolink_extract_main.cpp @MaxDesiatov @etcwilde -/lib/DriverTool/sil* @jckarter -/lib/DriverTool/sil_opt* @eeckstein -/lib/DriverTool/swift_symbolgraph_extract_main.cpp @QuietMisdreavus -/lib/Frontend*/ @artemcm @tshortli -/lib/IDE/ @ahoppen @bnbarham @hamishknight @rintaro -/lib/IDETool/ @ahoppen @bnbarham @hamishknight @rintaro -/lib/IRGen/ @rjmccall -/lib/IRGen/*Coverage* @ahoppen @bnbarham @hamishknight @rintaro -/lib/IRGen/*Debug* @adrian-prantl -/lib/IRGen/*Distributed* @ktoso -/lib/Index/ @ahoppen @bnbarham @hamishknight @rintaro -/lib/Macros/Sources/SwiftMacros/Swiftify* @hnrklssn @Xazax-hun -/lib/Markup/ @nkcsgexi -/lib/Migrator/ @nkcsgexi -/lib/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/lib/PrintAsClang @zoecarver @egorzhdan @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/lib/Refactoring/ @ahoppen @bnbarham @hamishknight @rintaro -/lib/SIL/ @jckarter -/lib/SIL/**/*DebugInfo* @adrian-prantl -/lib/SIL/IR/*Coverage* @ahoppen @bnbarham @hamishknight @rintaro -/lib/SIL/IR/SILDebug* @adrian-prantl -/lib/SIL/IR/SILLocation* @adrian-prantl -/lib/SIL/IR/SILProfiler.cpp @ahoppen @bnbarham @hamishknight @rintaro -/lib/SILGen/ @jckarter -/lib/SILGen/*Distributed* @ktoso -/lib/SILOptimizer/ @eeckstein -/lib/SILOptimizer/**/*DebugInfo* @adrian-prantl -/lib/SILOptimizer/Mandatory/ConsumeOperator* @kavon -/lib/SILOptimizer/Mandatory/FlowIsolation.cpp @kavon -/lib/SILOptimizer/Mandatory/MoveOnly* @kavon -/lib/SILOptimizer/Utils/Distributed* @ktoso -/lib/Sema/ @hborla @slavapestov @xedin -/lib/Sema/*Availability* @tshortli -/lib/Sema/CS* @hborla @xedin -/lib/Sema/CodeSynthesisDistributed* @hborla @ktoso -/lib/Sema/Constraint* @hborla @xedin -/lib/Sema/DerivedConformance* @slavapestov -/lib/Sema/DerivedConformanceDistributed* @ktoso @slavapestov -/lib/Sema/OpenedExistentials* @AnthonyLatsis @slavapestov -/lib/Sema/TypeCheckDistributed* @hborla @ktoso @xedin -/lib/Sema/TypeCheckProtocol* @AnthonyLatsis @hborla @slavapestov -/lib/Sema/TypeCheckType* @AnthonyLatsis @hborla @slavapestov @xedin -/lib/Serialization/ @xymus -/lib/Serialization/SerializedModuleLoader* @artemcm -/lib/SwiftRemoteMirror/ @slavapestov -/lib/SymbolGraphGen @QuietMisdreavus -/lib/Threading @al45tair - -# localization -# TODO: /localization - -# stdlib -/stdlib/ @swiftlang/standard-librarians -/stdlib/private/*Runtime*/ @rjmccall -/stdlib/private/SwiftReflectionTest/ @slavapestov -/stdlib/public/core/Swiftify* @hnrklssn @Xazax-hun -/stdlib/public/*Demangl*/ @rjmccall -/stdlib/public/Concurrency/ @ktoso -/stdlib/public/Cxx/ @zoecarver @egorzhdan @Xazax-hun @j-hui @fahadnayyar @susmonteiro -/stdlib/public/Distributed/ @ktoso -/stdlib/public/Observation/ @phausler -/stdlib/public/RuntimeModule/ @al45tair @mikeash -/stdlib/public/SwiftRemoteMirror/ @slavapestov -/stdlib/public/Threading/ @al45tair -/stdlib/public/Windows/ @compnerd -/stdlib/public/libexec/swift-backtrace/ @al45tair -/stdlib/public/runtime/ @mikeash @al45tair -/stdlib/tools/swift-reflection-test/ @slavapestov - -# test -/test/*Demangl*/ @rjmccall -/test/ASTGen/ @ahoppen @bnbarham @CodaFi @hamishknight @rintaro -/test/Concurrency/ @ktoso -/test/Constraints/ @hborla @xedin -/test/DebugInfo/ @adrian-prantl -/test/Distributed/ @ktoso -/test/Driver/ @artemcm -/test/Driver/static* @MaxDesiatov @etcwilde -/test/Frontend/ @artemcm @tshortli -/test/Generics/ @hborla @slavapestov -/test/Generics/inverse* @kavon -/test/IDE/ @ahoppen @bnbarham @hamishknight @rintaro -/test/IRGen/ @rjmccall -/test/Index/ @ahoppen @bnbarham @hamishknight @rintaro -/test/Interop/ @zoecarver @egorzhdan @Xazax-hun @j-hui @fahadnayyar @susmonteiro @hnrklssn -/test/Macros/SwiftifyImport @hnrklssn @Xazax-hun -/test/Migrator/ @nkcsgexi -/test/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/test/Profiler @ahoppen @bnbarham @hamishknight @rintaro -/test/Reflection/ @slavapestov -/test/Runtime/ @rjmccall -/test/SIL/ @jckarter -/test/SILGen/ @jckarter -/test/SILOptimizer/ @eeckstein -/test/SILOptimizer/moveonly* @kavon -/test/SILOptimizer/noimplicitcopy* @kavon -/test/ScanDependencies/ @artemcm -/test/Sema/ @hborla @slavapestov @xedin -/test/Sema/moveonly* @kavon -/test/Serialization/ @xymus -/test/SourceKit/ @ahoppen @bnbarham @hamishknight @rintaro -/test/SymbolGraph/ @QuietMisdreavus -/test/abi/ @swiftlang/standard-librarians -/test/decl/ @hborla @slavapestov -/test/decl/protocol/ @AnthonyLatsis @hborla @slavapestov -# FIXME: This file could have a dedicated directory. -/test/decl/protocol/special/DistributedActor.swift @ktoso -/test/expr/ @hborla @slavapestov @xedin -/test/refactoring/ @ahoppen @bnbarham @hamishknight @rintaro -/test/sil* @jckarter -/test/sil-opt* @eeckstein -/test/stdlib/ @swiftlang/standard-librarians -/test/stmt/ @hborla @xedin -/test/type/ @hborla @slavapestov @xedin - -# tools -# TODO: /tools -/tools/*reflection/ @slavapestov -/tools/SourceKit @ahoppen @bnbarham @hamishknight @rintaro -/tools/driver/ @artemcm -/tools/lldb-moduleimport-test/ @adrian-prantl -/tools/swift-demangle* @rjmccall -/tools/swift-ide-test @ahoppen @bnbarham @hamishknight @rintaro -/tools/swift-inspect @mikeash @al45tair @compnerd -/tools/swift-refactor @ahoppen @bnbarham @hamishknight @rintaro - -# unittests -/unittests/*Demangl*/ @rjmccall -/unittests/AST/ @hborla @slavapestov @xedin -/unittests/AST/*Evaluator* @CodaFi @slavapestov -/unittests/DependencyScan/ @artemcm @cachemeifyoucan -/unittests/Frontend*/ @artemcm @tshortli -/unittests/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/unittests/Reflection/ @slavapestov -/unittests/SIL/ @jckarter -/unittests/Sema/ @hborla @xedin -/unittests/SourceKit/ @ahoppen @bnbarham @rintaro @hamishknight -/unittests/runtime/ @rjmccall - -# userdocs -# TODO: /userdocs - -# utils -/utils/*windows* @compnerd -/utils/generate-xcode @hamishknight -/utils/gyb_sourcekit_support/ @ahoppen @bnbarham @hamishknight @rintaro -/utils/sourcekit_fuzzer/ @ahoppen @bnbarham @hamishknight @rintaro -/utils/swift-xcodegen/ @hamishknight -/utils/swift_build_support/products/earlyswiftsyntax.py @ahoppen @bnbarham @hamishknight @rintaro -/utils/swift_build_support/products/skstresstester.py @ahoppen @bnbarham @hamishknight @rintaro -/utils/swift_build_support/products/sourcekitlsp.py @ahoppen @bnbarham @hamishknight @rintaro -/utils/swift_build_support/products/swiftformat.py @ahoppen @allevato @bnbarham @hamishknight @rintaro -/utils/swift_build_support/products/swiftsyntax.py @ahoppen @bnbarham @hamishknight @rintaro -/utils/update-checkout* @shahmishal -/utils/update_checkout/ @shahmishal -/utils/vim/ @compnerd - -# validation-test -/validation-test/Driver/ @artemcm -/validation-test/IDE/ @ahoppen @bnbarham @rintaro @hamishknight -/validation-test/IRGen/ @rjmccall -/validation-test/Parse/ @ahoppen @bnbarham @CodaFi @DougGregor @hamishknight @rintaro -/validation-test/Reflection/ @slavapestov -/validation-test/Runtime/ @rjmccall -/validation-test/SIL/ @jckarter -/validation-test/SILGen/ @jckarter -/validation-test/SILOptimizer/ @eeckstein -/validation-test/Sema/ @hborla @slavapestov @xedin -/validation-test/Serialization/ @xymus -/validation-test/stdlib/ @swiftlang/standard-librarians +# For the release branch @swiftlang/swift-branch-managers needs to approve the changes +* @swiftlang/swift-branch-managers diff --git a/CHANGELOG.md b/CHANGELOG.md index d2bb92dd34743..05c0b5409021e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,61 @@ ## Swift 6.2 +* The Swift compiler no longer diagnoses references to declarations that are + potentially unavailable because the platform version might not be new enough + when those references occur inside of contexts that are also unavailable to + that platform. This addresses a long-standing nuisance for multi-platform + code. However, there is also a chance that existing source code may become + ambiguous as a result: + + ```swift + struct A {} + struct B {} + + func potentiallyAmbiguous(_: A) {} + + @available(macOS 99, *) + func potentiallyAmbiguous(_: B) {} + + @available(macOS, unavailable) + func unavailableOnMacOS() { + potentiallyAmbiguous(.init()) // error: ambiguous use of 'init()' + } + ``` + + Code that is now ambiguous as a result should likely be restructured since + disambiguation based on platform introduction alone has never been a reliable + strategy, given that the code would eventually become ambiguous anyways when + the deployment target is raised. + +* [SE-0470][]: + A protocol conformance can be isolated to a specific global actor, meaning that the conformance can only be used by code running on that actor. Isolated conformances are expressed by specifying the global actor on the conformance itself: + + ```swift + protocol P { + func f() + } + + @MainActor + class MyType: @MainActor P { + /*@MainActor*/ func f() { + // must be called on the main actor + } + } + ``` + + Swift will produce diagnostics if the conformance is directly accessed in code that isn't guaranteed to execute in the same global actor. For example: + + ```swift + func acceptP(_ value: T) { } + + /*nonisolated*/ func useIsolatedConformance(myType: MyType) { + acceptP(myType) // error: main actor-isolated conformance of 'MyType' to 'P' cannot be used in nonisolated context + } + ``` + + To address such issues, only use an isolated conformance from code that executes on the same global actor. + * [SE-0419][]: Introduced the new `Runtime` module, which contains a public API that can generate backtraces, presently supported on macOS and Linux. Capturing a @@ -10732,6 +10787,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig [SE-0442]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0442-allow-taskgroup-childtaskresult-type-to-be-inferred.md [SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md [SE-0458]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md +[SE-0470]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0470-isolated-conformances.md [#64927]: [#42697]: [#42728]: diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5cf4d0661a9..e4cbfb844e0a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,6 +336,8 @@ set(SWIFT_COMPILER_VERSION "" CACHE STRING "The internal version of the Swift compiler") set(CLANG_COMPILER_VERSION "" CACHE STRING "The internal version of the Clang compiler") +set(SWIFT_TOOLCHAIN_VERSION "" CACHE STRING + "The Swift compiler tag") option(SWIFT_DISABLE_DEAD_STRIPPING "Turn off Darwin-specific dead stripping for Swift host tools." FALSE) @@ -462,6 +464,10 @@ option(SWIFT_STDLIB_ASSERTIONS "Enable internal checks for the Swift standard library (useful for debugging the library itself, does not affect checks required for safety)" "${SWIFT_STDLIB_ASSERTIONS_default}") +option(SWIFT_STDLIB_ENABLE_STRICT_AVAILABILITY + "Enable strict availability; this will cause things to break at desk or in CI if the host OS is a lower version than some `@availability` annotations in the runtime code" + FALSE) + option(SWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER "Use the host compiler and not the internal clang to build the swift runtime" FALSE) @@ -1404,8 +1410,9 @@ endif() if(SWIFT_BUILD_STDLIB OR SWIFT_BUILD_SDK_OVERLAY) message(STATUS "Building Swift standard library and overlays for SDKs: ${SWIFT_SDKS}") - message(STATUS " Build type: ${SWIFT_STDLIB_BUILD_TYPE}") - message(STATUS " Assertions: ${SWIFT_STDLIB_ASSERTIONS}") + message(STATUS " Build type: ${SWIFT_STDLIB_BUILD_TYPE}") + message(STATUS " Assertions: ${SWIFT_STDLIB_ASSERTIONS}") + message(STATUS " Strict availability: ${SWIFT_STDLIB_ENABLE_STRICT_AVAILABILITY}") message(STATUS "") message(STATUS "Building Swift runtime with:") diff --git a/Runtimes/Core/CMakeLists.txt b/Runtimes/Core/CMakeLists.txt index 3f1e73c9fa84b..32dcef799247a 100644 --- a/Runtimes/Core/CMakeLists.txt +++ b/Runtimes/Core/CMakeLists.txt @@ -78,7 +78,6 @@ set(SwiftCore_VENDOR_MODULE_DIR "${SwiftCore_CMAKE_MODULES_DIR}/vendor" include(GNUInstallDirs) include(CheckSymbolExists) include(CheckIncludeFileCXX) -include(AvailabilityMacros) include(CompilerSettings) include(DefaultSettings) include(EmitSwiftInterface) @@ -86,6 +85,7 @@ include(PlatformInfo) include(gyb) include(ResourceEmbedding) include(CatalystSupport) +include(AvailabilityMacros) check_symbol_exists("asl_log" "asl.h" SwiftCore_HAS_ASL) check_symbol_exists("dladdr" "dlfcn.h" SwiftCore_HAS_DLADDR) @@ -125,6 +125,7 @@ defaulted_option(SwiftCore_ENABLE_BACKTRACING "Enable backtracing runtime suppor defaulted_set(SwiftCore_BACKTRACER_PATH STRING "Set a fixed path to the Swift backtracer") defaulted_option(SwiftCore_ENABLE_FATALERROR_BACKTRACE "Build stdlib fatalError with backtrace output") defaulted_option(SwiftCore_ENABLE_PRESPECIALIZATION "Enable generic metadata prespecialization") +defaulted_option(SwiftCore_ENABLE_STRICT_AVAILABILITY "Enable strict availability; this will cause things to break at desk or in CI if the host OS is a lower version than some `@availability` annotations in the runtime code") option(SwiftCore_ENABLE_CLOBBER_FREED_OBJECTS "" OFF) option(SwiftCore_ENABLE_RUNTIME_LEAK_CHECKER "" OFF) @@ -159,7 +160,7 @@ add_compile_definitions( $<$:-DSWIFT_STDLIB_HAS_DARWIN_LIBMALLOC> # Anything that includes include/swift/Runtime/Config.h $<$:-DSWIFT_THREADING_${SwiftCore_THREADING_PACKAGE}> $<$:-DSWIFT_RUNTIME_ENABLE_LEAK_CHECKER=$> - $<$:-DSWIFT_RUNTIME_CLOBBER_FREED_OBJECTS=$>) + $<$:-DSWIFT_RUNTIME_CLOBBER_FREED_OBJECTS>) add_compile_options( $<$:-fno-rtti> diff --git a/Runtimes/Core/Concurrency/CMakeLists.txt b/Runtimes/Core/Concurrency/CMakeLists.txt index 8dd89783d7ac2..f82b8db784f4c 100644 --- a/Runtimes/Core/Concurrency/CMakeLists.txt +++ b/Runtimes/Core/Concurrency/CMakeLists.txt @@ -1,7 +1,8 @@ add_subdirectory(InternalShims) +gyb_expand(Task+init.swift.gyb Task+init.swift) gyb_expand(TaskGroup+addTask.swift.gyb TaskGroup+addTask.swift) -gyb_expand(Task+startSynchronously.swift.gyb Task+startSynchronously.swift) +gyb_expand(Task+immediate.swift.gyb Task+immediate.swift) add_library(swift_Concurrency Actor.cpp @@ -12,9 +13,9 @@ add_library(swift_Concurrency EmbeddedSupport.cpp Error.cpp ExecutorBridge.cpp + ExecutorImpl.cpp ExecutorChecks.cpp GlobalExecutor.cpp - Setup.cpp Task.cpp TaskAlloc.cpp TaskGroup.cpp @@ -69,7 +70,6 @@ add_library(swift_Concurrency Deque/Deque+UnsafeHandle.swift Deque/UnsafeMutableBufferPointer+Utilities.swift DiscardingTaskGroup.swift - DummyExecutor.swift Errors.swift Executor.swift ExecutorAssertions.swift @@ -80,6 +80,8 @@ add_library(swift_Concurrency PartialAsyncTask.swift PlatformExecutorDarwin.swift PlatformExecutorLinux.swift + PlatformExecutorFreeBSD.swift + PlatformExecutorOpenBSD.swift PlatformExecutorWindows.swift PriorityQueue.swift SourceCompatibilityShims.swift @@ -89,15 +91,17 @@ add_library(swift_Concurrency Task+TaskExecutor.swift TaskCancellation.swift TaskGroup.swift - TaskGroup+Embedded.swift TaskLocal.swift TaskSleep.swift TaskSleepDuration.swift + UnimplementedExecutor.swift + "${CMAKE_CURRENT_BINARY_DIR}/Task+init.swift" "${CMAKE_CURRENT_BINARY_DIR}/TaskGroup+addTask.swift" - "${CMAKE_CURRENT_BINARY_DIR}/Task+startSynchronously.swift") + "${CMAKE_CURRENT_BINARY_DIR}/Task+immediate.swift") include(${SwiftCore_CONCURRENCY_GLOBAL_EXECUTOR}.cmake) target_compile_definitions(swift_Concurrency PRIVATE + $<$:-DSWIFT_RUNTIME> $<$:-DSWIFT_TARGET_LIBRARY_NAME=swift_Concurrency> # NOTE: VS2017 <15.8 would round clamp alignment to alignof(max_align_t) which # was non-conformant. Indicate that we wish to use extended alignment. @@ -108,6 +112,7 @@ target_compile_options(swift_Concurrency PRIVATE # NOTE: do not remove until `IsolatedAny` is on by default in all supported # compilers. "$<$:SHELL:-enable-experimental-feature IsolatedAny>" + "$<$:SHELL:-enable-experimental-feature Extern>" # NOTE: enable the async frame pointer on Darwin to faciliate debugging. $<$,$>:-fswift-async-fp=always> "$<$,$>:SHELL:-Xfrontend -swift-async-frame-pointer=always>" diff --git a/Runtimes/Core/cmake/caches/Vendors/Apple/apple-common.cmake b/Runtimes/Core/cmake/caches/Vendors/Apple/apple-common.cmake index 4a921adfa6b0c..abf1ecbb46827 100644 --- a/Runtimes/Core/cmake/caches/Vendors/Apple/apple-common.cmake +++ b/Runtimes/Core/cmake/caches/Vendors/Apple/apple-common.cmake @@ -12,6 +12,8 @@ set(SwiftCore_ENABLE_VECTOR_TYPES ON CACHE BOOL "") set(SwiftCore_ENABLE_RUNTIME_FUNCTION_COUNTERS ON CACHE BOOL "") set(SwiftCore_ENABLE_BACKDEPLOYMENT_SUPPORT ON CACHE BOOL "") set(SwiftCore_ENABLE_FILESYSTEM_SUPPORT ON CACHE BOOL "") +set(SwiftCore_ENABLE_STRICT_AVAILABILITY ON CACHE BOOL "") + set(SwiftCore_OPTIMIZATION_REMARKS "bitstream" CACHE STRING "") set(SwiftCore_INSTALL_NESTED_SUBDIR OFF CACHE BOOL "") diff --git a/Runtimes/Core/cmake/modules/AvailabilityMacros.cmake b/Runtimes/Core/cmake/modules/AvailabilityMacros.cmake index b1dd4920c6b80..5f3f21985ef9e 100644 --- a/Runtimes/Core/cmake/modules/AvailabilityMacros.cmake +++ b/Runtimes/Core/cmake/modules/AvailabilityMacros.cmake @@ -1,5 +1,42 @@ -file(STRINGS "${SwiftCore_SWIFTC_SOURCE_DIR}/utils/availability-macros.def" availability_defs) +configure_file("${SwiftCore_SWIFTC_SOURCE_DIR}/utils/availability-macros.def" + "${CMAKE_CURRENT_BINARY_DIR}/availability-macros.def" + COPYONLY) +file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/availability-macros.def" availability_defs) list(FILTER availability_defs EXCLUDE REGEX "^\\s*(#.*)?$") foreach(def ${availability_defs}) - add_compile_options("$<$:SHELL:-Xfrontend -define-availability -Xfrontend \"${def}\">") + list(APPEND availability_definitions "-Xfrontend -define-availability -Xfrontend \"${def}\"") + + if("${def}" MATCHES "SwiftStdlib .*") + # For each SwiftStdlib x.y, also define StdlibDeploymentTarget x.y, which, + # will expand to the current `-target` platform if the macro defines a + # newer platform as its availability. + # + # There is a setting, SwiftCore_ENABLE_STRICT_AVAILABILITY, which if set + # ON will cause us to use the "proper" availability instead. + string(REPLACE "SwiftStdlib" "StdlibDeploymentTarget" current "${def}") + if(NOT SwiftCore_ENABLE_STRICT_AVAILABILITY AND SwiftCore_SWIFT_AVAILABILITY_PLATFORM) + if("${SwiftCore_SWIFT_AVAILABILITY_PLATFORM}" STREQUAL "macOS" AND "${SwiftCore_VARIANT_AVAILABILITY_PLATFORM}" STREQUAL "iOS") + string(REGEX MATCH "iOS ([0-9]+(\.[0-9]+)+)" ios_platform_version "${def}") + string(REGEX MATCH "[0-9]+(\.[0-9]+)+" ios_version "${ios_platform_version}") + string(REGEX MATCH "macOS ([0-9]+(\.[0-9]+)+)" macos_platform_version "${def}") + string(REGEX MATCH "[0-9]+(\.[0-9]+)+" macos_version "${macos_platform_version}") + if((NOT macos_version STREQUAL "9999" OR NOT ios_version STREQUAL "9999") AND (macos_version VERSION_GREATER CMAKE_OSX_DEPLOYMENT_TARGET OR ios_version VERSION_GREATER SwiftCore_VARIANT_DEPLOYMENT_VERSION)) + string(REGEX REPLACE ":.*" ": macOS ${CMAKE_OSX_DEPLOYMENT_VERSION}, iOS ${SwiftCore_VARIANT_DEPLOYMENT_VERSION}" current "${current}") + endif() + else() + string(REGEX MATCH "${SwiftCore_SWIFT_AVAILABILITY_PLATFORM} ([0-9]+(\.[0-9]+)+)" platform_version "${def}") + string(REGEX MATCH "[0-9]+(\.[0-9]+)+" version "${platform_version}") + if(NOT version STREQUAL "9999" AND version VERSION_GREATER CMAKE_OSX_DEPLOYMENT_TARGET) + string(REGEX REPLACE ":.*" ":${SwiftCore_SWIFT_AVAILABILITY_PLATFORM} ${CMAKE_OSX_DEPLOYMENT_TARGET}" current "${current}") + endif() + endif() + endif() + list(APPEND availability_definitions "-Xfrontend -define-availability -Xfrontend \"${current}\"") + endif() endforeach() + +list(JOIN availability_definitions "\n" availability_definitions) +file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/availability-macros.rsp" + CONTENT "${availability_definitions}") +add_compile_options("$<$:SHELL:${CMAKE_Swift_RESPONSE_FILE_FLAG}${CMAKE_CURRENT_BINARY_DIR}/availability-macros.rsp>") diff --git a/Runtimes/Core/cmake/modules/CatalystSupport.cmake b/Runtimes/Core/cmake/modules/CatalystSupport.cmake index 7f761007414ea..1ac17eb9b554e 100644 --- a/Runtimes/Core/cmake/modules/CatalystSupport.cmake +++ b/Runtimes/Core/cmake/modules/CatalystSupport.cmake @@ -34,5 +34,12 @@ if(SwiftCore_COMPILER_VARIANT_TARGET) set(SwiftCore_VARIANT_MODULE_TRIPLE "${module_triple}" CACHE STRING "Triple used for installed swift{module,interface} files for the target variant") mark_as_advanced(SwiftCore_VARIANT_MODULE_TRIPLE) message(CONFIGURE_LOG "Swift target variant module triple: ${module_triple}") + + string(JSON triple GET "${target_info_json}" "target" "triple") + if(triple MATCHES "apple-([a-zA-Z]+)([0-9]+[.0-9]*)-macabi") + set(SwiftCore_VARIANT_DEPLOYMENT_VERSION "${CMAKE_MATCH_2}") + mark_as_advanced(SwiftCore_VARIANT_DEPLOYMENT_VERSION) + message(CONFIGURE_LOG "Swift target variant deployment version: ${SwiftCore_VARIANT_DEPLOYMENT_VERSION}") + endif() endif() endif() diff --git a/Runtimes/Core/cmake/modules/DefaultSettings.cmake b/Runtimes/Core/cmake/modules/DefaultSettings.cmake index e6fc1f5820ef0..3ff9b9da16e12 100644 --- a/Runtimes/Core/cmake/modules/DefaultSettings.cmake +++ b/Runtimes/Core/cmake/modules/DefaultSettings.cmake @@ -11,6 +11,8 @@ set(SwiftCore_ENABLE_COMMANDLINE_SUPPORT_default OFF) # TODO: enable this by def set(SwiftCore_ENABLE_STDIN_default ON) set(SwiftCore_ENABLE_TYPE_PRINTING_default ON) +set(SwiftCore_ENABLE_STRICT_AVAILABILITY_default OFF) + set(SwiftCore_BACKTRACER_PATH_default "") # Provide a boolean option that a user can optionally enable. @@ -20,7 +22,7 @@ macro(defaulted_option variable helptext) if(NOT DEFINED ${variable}_default) set(${variable}_default OFF) endif() - option(${variable} ${helptext} ${${variable}_default}) + option(${variable} "${helptext}" ${${variable}_default}) endmacro() # Create a defaulted cache entry diff --git a/Runtimes/Core/cmake/modules/ExperimentalFeatures.cmake b/Runtimes/Core/cmake/modules/ExperimentalFeatures.cmake index bc6b0bfd69ad1..d11fb6e8fcab3 100644 --- a/Runtimes/Core/cmake/modules/ExperimentalFeatures.cmake +++ b/Runtimes/Core/cmake/modules/ExperimentalFeatures.cmake @@ -4,10 +4,13 @@ add_compile_options( "$<$:SHELL:-enable-experimental-feature SE427NoInferenceOnExtension>" "$<$:SHELL:-enable-experimental-feature NonescapableTypes>" "$<$:SHELL:-enable-experimental-feature LifetimeDependence>" + "$<$:SHELL:-enable-experimental-feature InoutLifetimeDependence>" + "$<$:SHELL:-enable-experimental-feature LifetimeDependenceMutableAccessors>" "$<$:SHELL:-enable-experimental-feature MemberImportVisibility>" "$<$:SHELL:-enable-experimental-feature TypedThrows>" "$<$:SHELL:-enable-experimental-feature Macros>" "$<$:SHELL:-enable-experimental-feature FreestandingMacros>" "$<$:SHELL:-enable-experimental-feature BitwiseCopyable>" "$<$:SHELL:-enable-experimental-feature Extern>" + "$<$:SHELL:-enable-experimental-feature AllowUnsafeAttribute>" "$<$:SHELL:-enable-experimental-feature ValueGenerics>") diff --git a/Runtimes/Core/cmake/modules/PlatformInfo.cmake b/Runtimes/Core/cmake/modules/PlatformInfo.cmake index 999d6b0595f1b..90a0030eecea5 100644 --- a/Runtimes/Core/cmake/modules/PlatformInfo.cmake +++ b/Runtimes/Core/cmake/modules/PlatformInfo.cmake @@ -36,3 +36,47 @@ if(NOT SwiftCore_ARCH_SUBDIR) message(CONFIGURE_LOG "Swift Arch: ${arch}") endif() + +# Note: *moduleTriple* doesn't have an "x" on the end of "macos"; just to be +# safe, we support both cases here. +set(availability_platform_macos "macOS") +set(availaiblity_platform_macosx "macOS") +set(availability_platform_ios "iOS") +set(availability_platform_watchos "watchOS") +set(availability_platform_tvos "tvOS") +set(availability_platform_xros "visionOS") +set(availability_platform_bridgeos "bridgeOS") + +if(NOT SwiftCore_SWIFT_AVAILABILITY_PLATFORM) + if(SwiftCore_MODULE_TRIPLE MATCHES ".*-([^-]+)-simulator$") + set(platform "${CMAKE_MATCH_1}") + elseif(SwiftCore_MODULE_TRIPLE MATCHES ".*-([^-]+)-msvc$") + set(platform "${CMAKE_MATCH_1}") + elseif(SwiftCore_MODULE_TRIPLE MATCHES ".*-([^-]+)$") + set(platform "${CMAKE_MATCH_1}") + else() + message(WARNING "Unable to extract platform name from triple ${SwiftCore_MODULE_TRIPLE}") + endif() + + if(availability_platform_${platform}) + set(SwiftCore_SWIFT_AVAILABILITY_PLATFORM "${availability_platform_${platform}}") + else() + set(SwiftCore_SWIFT_AVAILABILITY_PLATFORM "unknown") + message(WARNING "Unknown platform ${platform} for availability") + endif() +endif() + +set(SwiftCore_VARIANT_AVAILABILITY_PLATFORM "none") +if(SwiftCore_VARIANT_MODULE_TRIPLE) + if(SwiftCore_VARIANT_MODULE_TRIPLE MATCHES ".*-([^-]+)$") + set(platform "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Unable to extract platform name from triple ${SwiftCore_VARIANT_MODULE_TRIPLE}") + endif() + + if(availability_platform_${platform}) + set(SwiftCore_VARIANT_AVAILABILITY_PLATFORM "${availability_platform_${platform}}") + else() + message(WARNING "Unknown platform ${platform} for variant availability") + endif() +endif() diff --git a/Runtimes/Core/core/CMakeLists.txt b/Runtimes/Core/core/CMakeLists.txt index 20df62386e987..bb65771d3db92 100644 --- a/Runtimes/Core/core/CMakeLists.txt +++ b/Runtimes/Core/core/CMakeLists.txt @@ -154,6 +154,8 @@ add_library(swiftCore Span/RawSpan.swift Span/MutableSpan.swift Span/MutableRawSpan.swift + Span/OutputSpan.swift + Span/OutputRawSpan.swift StaticString.swift StaticPrint.swift Stride.swift @@ -188,7 +190,6 @@ add_library(swiftCore StringWordBreaking.swift Substring.swift SwiftNativeNSArray.swift - SwiftSettings.swift TemporaryAllocation.swift ThreadLocalStorage.swift UIntBuffer.swift @@ -208,6 +209,13 @@ add_library(swiftCore UnsafeRawPointer.swift UTFEncoding.swift UTF8.swift + UTF8EncodingError.swift + UTF8Span.swift + UTF8SpanBits.swift + UTF8SpanComparisons.swift + UTF8SpanFundamentals.swift + UTF8SpanInternalHelpers.swift + UTF8SpanIterators.swift UTF16.swift UTF32.swift Unicode.swift # ORDER DEPENDENCY: must follow new unicode support @@ -294,7 +302,8 @@ target_compile_options(swiftCore PRIVATE $<$:-nostdimport> "$<$:SHELL:-Xfrontend -group-info-path -Xfrontend ${CMAKE_CURRENT_SOURCE_DIR}/GroupInfo.json>" "$<$:SHELL:-Xfrontend -disable-objc-attr-requires-foundation-module>" - "$<$:SHELL:-Xfrontend -require-explicit-availability=ignore>") + "$<$:SHELL:-Xfrontend -require-explicit-availability=ignore>" + "$<$,$>:SHELL:-Xfrontend -previous-module-installname-map-file -Xfrontend ${CMAKE_CURRENT_SOURCE_DIR}/PreviousModuleInstallName.json>") if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "MinSizeRel") # Using these in MinSizeRel would result in a 15% increase in the binary size target_compile_options(swiftCore PRIVATE diff --git a/Runtimes/Supplemental/StringProcessing/CMakeLists.txt b/Runtimes/Supplemental/StringProcessing/CMakeLists.txt index 43d1e7890c208..f9da35e84fbed 100644 --- a/Runtimes/Supplemental/StringProcessing/CMakeLists.txt +++ b/Runtimes/Supplemental/StringProcessing/CMakeLists.txt @@ -27,6 +27,7 @@ include(AvailabilityMacros) add_compile_options( $<$:-explicit-module-build> $<$:-nostdlibimport> + "$<$:SHELL:-Xfrontend -disable-implicit-concurrency-module-import>" "$<$:SHELL:-Xfrontend -disable-implicit-string-processing-module-import>") add_subdirectory(_RegexParser) diff --git a/Runtimes/Supplemental/StringProcessing/_RegexParser/CMakeLists.txt b/Runtimes/Supplemental/StringProcessing/_RegexParser/CMakeLists.txt index 0285297831a70..04a3d2b09ff7e 100644 --- a/Runtimes/Supplemental/StringProcessing/_RegexParser/CMakeLists.txt +++ b/Runtimes/Supplemental/StringProcessing/_RegexParser/CMakeLists.txt @@ -31,7 +31,8 @@ add_library(swift_RegexParser Utility/Errors.swift Utility/MissingUnicode.swift) -target_link_libraries(swift_RegexParser PRIVATE swiftCore) +target_link_libraries(swift_RegexParser PRIVATE + swiftCore) set_target_properties(swift_RegexParser PROPERTIES Swift_MODULE_NAME _RegexParser) diff --git a/SwiftCompilerSources/Sources/AST/Declarations.swift b/SwiftCompilerSources/Sources/AST/Declarations.swift index b20349e6cde15..dc793aa353fe8 100644 --- a/SwiftCompilerSources/Sources/AST/Declarations.swift +++ b/SwiftCompilerSources/Sources/AST/Declarations.swift @@ -117,6 +117,8 @@ final public class TopLevelCodeDecl: Decl {} final public class ImportDecl: Decl {} +final public class UsingDecl: Decl {} + final public class PrecedenceGroupDecl: Decl {} final public class MissingDecl: Decl {} diff --git a/SwiftCompilerSources/Sources/AST/Registration.swift b/SwiftCompilerSources/Sources/AST/Registration.swift index f1d09ebf4190d..6c4f62bf69cb7 100644 --- a/SwiftCompilerSources/Sources/AST/Registration.swift +++ b/SwiftCompilerSources/Sources/AST/Registration.swift @@ -36,6 +36,7 @@ public func registerAST() { registerDecl(ExtensionDecl.self) registerDecl(TopLevelCodeDecl.self) registerDecl(ImportDecl.self) + registerDecl(UsingDecl.self) registerDecl(PrecedenceGroupDecl.self) registerDecl(MissingDecl.self) registerDecl(MissingMemberDecl.self) diff --git a/SwiftCompilerSources/Sources/AST/Type.swift b/SwiftCompilerSources/Sources/AST/Type.swift index 77d8646f9529c..0da3540a7b01e 100644 --- a/SwiftCompilerSources/Sources/AST/Type.swift +++ b/SwiftCompilerSources/Sources/AST/Type.swift @@ -186,6 +186,7 @@ extension TypeProperties { public var hasLocalArchetype: Bool { rawType.bridged.hasLocalArchetype() } public var isEscapable: Bool { rawType.bridged.isEscapable() } public var isNoEscape: Bool { rawType.bridged.isNoEscape() } + public var isBuiltinType: Bool { rawType.bridged.isBuiltinType() } public var representationOfMetatype: AST.`Type`.MetatypeRepresentation { rawType.bridged.getRepresentationOfMetatype().representation diff --git a/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift b/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift index b238b39087af9..e0dc6e3dff552 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift @@ -253,12 +253,21 @@ struct AliasAnalysis { case let storeBorrow as StoreBorrowInst: return memLoc.mayAlias(with: storeBorrow.destination, self) ? .init(write: true) : .noEffects - case let mdi as MarkDependenceInstruction: + case let mdi as MarkDependenceInst: if mdi.base.type.isAddress && memLoc.mayAlias(with: mdi.base, self) { return .init(read: true) } return .noEffects + case let mdai as MarkDependenceAddrInst: + if memLoc.mayAlias(with: mdai.address, self) { + return .init(read: true, write: true) + } + if mdai.base.type.isAddress && memLoc.mayAlias(with: mdai.base, self) { + return .init(read: true) + } + return .noEffects + case let copy as SourceDestAddrInstruction: let mayRead = memLoc.mayAlias(with: copy.source, self) let mayWrite = memLoc.mayAlias(with: copy.destination, self) diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift b/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift index 13fdedd4d18a6..7c9a5c4456ca2 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift +++ b/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift @@ -181,3 +181,122 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { blockRange.deinitialize() } } + +extension InstructionRange { + enum PathOverlap { + // range: --- + // | pathBegin + // | | + // | pathEnd + // --- + case containsPath + + // range: --- + // | pathBegin + // --- | + // pathEnd + case containsBegin + + // pathBegin + // range: --- | + // | pathEnd + // --- + case containsEnd + + // pathBegin + // range: --- | + // | | + // --- | + // pathEnd + case overlappedByPath + + // either: pathBegin + // | + // pathEnd + // range: --- + // | + // --- + // or: pathBegin + // | + // pathEnd + case disjoint + } + + /// Return true if any exclusive path from `begin` to `end` includes an instruction in this exclusive range. + /// + /// Returns .containsBegin, if this range has the same begin and end as the path. + /// + /// Precondition: `begin` dominates `end`. + func overlaps(pathBegin: Instruction, pathEnd: Instruction, _ context: some Context) -> PathOverlap { + assert(pathBegin != pathEnd, "expect an exclusive path") + if contains(pathBegin) { + // Note: pathEnd != self.begin here since self.contains(pathBegin) + if contains(pathEnd) { return .containsPath } + return .containsBegin + } + if contains(pathEnd) { + if let rangeBegin = self.begin, rangeBegin == pathEnd { + return .disjoint + } + return .containsEnd + } + // Neither end-point is contained. If a backward path walk encouters this range, then it must overlap this + // range. Otherwise, it is disjoint. + var backwardBlocks = BasicBlockWorklist(context) + defer { backwardBlocks.deinitialize() } + backwardBlocks.pushIfNotVisited(pathEnd.parentBlock) + while let block = backwardBlocks.pop() { + if blockRange.inclusiveRangeContains(block) { + // This range overlaps with this block, but there are still three possibilities: + // (1) range, pathBegin, pathEnd = disjoint (range might not begin in this block) + // (2) pathBegin, pathEnd, range = disjoint (pathBegin might not be in this block) + // (3) pathBegin, range, pathEnd = overlappedByPath (range or pathBegin might not be in this block) + // + // Walk backward from pathEnd to find either pathBegin or an instruction in this range. + // Both this range and the path may or may not begin in this block. + let endInBlock = block == pathEnd.parentBlock ? pathEnd : block.terminator + for inst in ReverseInstructionList(first: endInBlock) { + // Check pathBegin first because the range is exclusive. + if inst == pathBegin { + break + } + // Check inclusiveRangeContains() in case the range end is the first instruction in this block. + if inclusiveRangeContains(inst) { + return .overlappedByPath + } + } + // No instructions in this range occur between pathBegin and pathEnd. + return .disjoint + } + // No range blocks have been reached. + if block == pathBegin.parentBlock { + return .disjoint + } + backwardBlocks.pushIfNotVisited(contentsOf: block.predecessors) + } + fatalError("begin: \(pathBegin)\n must dominate end: \(pathEnd)") + } +} + +let rangeOverlapsPathTest = FunctionTest("range_overlaps_path") { + function, arguments, context in + let rangeValue = arguments.takeValue() + print("Range of: \(rangeValue)") + var range = computeLinearLiveness(for: rangeValue, context) + defer { range.deinitialize() } + let pathInst = arguments.takeInstruction() + print("Path begin: \(pathInst)") + if let pathBegin = pathInst as? ScopedInstruction { + for end in pathBegin.endInstructions { + print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end, context)) + } + return + } + if let pathValue = pathInst as? SingleValueInstruction, pathValue.ownership == .owned { + for end in pathValue.uses.endingLifetime { + print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end.instruction, context)) + } + return + } + print("Test specification error: not a scoped or owned instruction: \(pathInst)") +} diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index ae4a34a852455..74b18fc5e8bfd 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -105,9 +105,9 @@ import SILBridging private let verbose = false -private func log(_ message: @autoclosure () -> String) { +private func log(prefix: Bool = true, _ message: @autoclosure () -> String) { if verbose { - print("### \(message())") + debugLog(prefix: prefix, message()) } } @@ -128,47 +128,48 @@ let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-special } var remainingSpecializationRounds = 5 - var callerModified = false repeat { + // TODO: Names here are pretty misleading. We are looking for a place where + // the pullback closure is created (so for `partial_apply` instruction). var callSites = gatherCallSites(in: function, context) + guard !callSites.isEmpty else { + return + } - if !callSites.isEmpty { - for callSite in callSites { - var (specializedFunction, alreadyExists) = getOrCreateSpecializedFunction(basedOn: callSite, context) - - if !alreadyExists { - context.notifyNewFunction(function: specializedFunction, derivedFrom: callSite.applyCallee) - } + for callSite in callSites { + var (specializedFunction, alreadyExists) = getOrCreateSpecializedFunction(basedOn: callSite, context) - rewriteApplyInstruction(using: specializedFunction, callSite: callSite, context) + if !alreadyExists { + context.notifyNewFunction(function: specializedFunction, derivedFrom: callSite.applyCallee) } - var deadClosures: InstructionWorklist = callSites.reduce(into: InstructionWorklist(context)) { deadClosures, callSite in - callSite.closureArgDescriptors - .map { $0.closure } - .forEach { deadClosures.pushIfNotVisited($0) } - } + rewriteApplyInstruction(using: specializedFunction, callSite: callSite, context) + } - defer { - deadClosures.deinitialize() - } + var deadClosures: InstructionWorklist = callSites.reduce(into: InstructionWorklist(context)) { deadClosures, callSite in + callSite.closureArgDescriptors + .map { $0.closure } + .forEach { deadClosures.pushIfNotVisited($0) } + } - while let deadClosure = deadClosures.pop() { - let isDeleted = context.tryDeleteDeadClosure(closure: deadClosure as! SingleValueInstruction) - if isDeleted { - context.notifyInvalidatedStackNesting() - } - } + defer { + deadClosures.deinitialize() + } - if context.needFixStackNesting { - function.fixStackNesting(context) + while let deadClosure = deadClosures.pop() { + let isDeleted = context.tryDeleteDeadClosure(closure: deadClosure as! SingleValueInstruction) + if isDeleted { + context.notifyInvalidatedStackNesting() } } - callerModified = callSites.count > 0 + if context.needFixStackNesting { + function.fixStackNesting(context) + } + remainingSpecializationRounds -= 1 - } while callerModified && remainingSpecializationRounds > 0 + } while remainingSpecializationRounds > 0 } // =========== Top-level functions ========== // @@ -503,12 +504,6 @@ private func handleApplies(for rootClosure: SingleValueInstruction, callSiteMap: continue } - // Workaround for a problem with OSSA: https://github.com/swiftlang/swift/issues/78847 - // TODO: remove this if-statement once the underlying problem is fixed. - if callee.hasOwnership { - continue - } - if callee.isDefinedExternally { continue } @@ -779,13 +774,13 @@ private extension SpecializationCloner { let clonedRootClosure = builder.cloneRootClosure(representedBy: closureArgDesc, capturedArguments: clonedClosureArgs) - let (finalClonedReabstractedClosure, releasableClonedReabstractedClosures) = + let finalClonedReabstractedClosure = builder.cloneRootClosureReabstractions(rootClosure: closureArgDesc.closure, clonedRootClosure: clonedRootClosure, reabstractedClosure: callSite.appliedArgForClosure(at: closureArgDesc.closureArgIndex)!, origToClonedValueMap: origToClonedValueMap, self.context) - let allClonedReleasableClosures = [clonedRootClosure] + releasableClonedReabstractedClosures + let allClonedReleasableClosures = [ finalClonedReabstractedClosure ]; return (finalClonedReabstractedClosure, allClonedReleasableClosures) } @@ -935,10 +930,9 @@ private extension Builder { func cloneRootClosureReabstractions(rootClosure: Value, clonedRootClosure: Value, reabstractedClosure: Value, origToClonedValueMap: [HashableValue: Value], _ context: FunctionPassContext) - -> (finalClonedReabstractedClosure: SingleValueInstruction, releasableClonedReabstractedClosures: [PartialApplyInst]) + -> SingleValueInstruction { func inner(_ rootClosure: Value, _ clonedRootClosure: Value, _ reabstractedClosure: Value, - _ releasableClonedReabstractedClosures: inout [PartialApplyInst], _ origToClonedValueMap: inout [HashableValue: Value]) -> Value { switch reabstractedClosure { case let reabstractedClosure where reabstractedClosure == rootClosure: @@ -947,7 +941,7 @@ private extension Builder { case let cvt as ConvertFunctionInst: let toBeReabstracted = inner(rootClosure, clonedRootClosure, cvt.fromFunction, - &releasableClonedReabstractedClosures, &origToClonedValueMap) + &origToClonedValueMap) let reabstracted = self.createConvertFunction(originalFunction: toBeReabstracted, resultType: cvt.type, withoutActuallyEscaping: cvt.withoutActuallyEscaping) origToClonedValueMap[cvt] = reabstracted @@ -955,7 +949,7 @@ private extension Builder { case let cvt as ConvertEscapeToNoEscapeInst: let toBeReabstracted = inner(rootClosure, clonedRootClosure, cvt.fromFunction, - &releasableClonedReabstractedClosures, &origToClonedValueMap) + &origToClonedValueMap) let reabstracted = self.createConvertEscapeToNoEscape(originalFunction: toBeReabstracted, resultType: cvt.type, isLifetimeGuaranteed: true) origToClonedValueMap[cvt] = reabstracted @@ -963,7 +957,7 @@ private extension Builder { case let pai as PartialApplyInst: let toBeReabstracted = inner(rootClosure, clonedRootClosure, pai.arguments[0], - &releasableClonedReabstractedClosures, &origToClonedValueMap) + &origToClonedValueMap) guard let function = pai.referencedFunction else { log("Parent function of callSite: \(rootClosure.parentFunction)") @@ -978,13 +972,11 @@ private extension Builder { calleeConvention: pai.calleeConvention, hasUnknownResultIsolation: pai.hasUnknownResultIsolation, isOnStack: pai.isOnStack) - releasableClonedReabstractedClosures.append(reabstracted) origToClonedValueMap[pai] = reabstracted return reabstracted case let mdi as MarkDependenceInst: - let toBeReabstracted = inner(rootClosure, clonedRootClosure, mdi.value, &releasableClonedReabstractedClosures, - &origToClonedValueMap) + let toBeReabstracted = inner(rootClosure, clonedRootClosure, mdi.value, &origToClonedValueMap) let base = origToClonedValueMap[mdi.base]! let reabstracted = self.createMarkDependence(value: toBeReabstracted, base: base, kind: .Escaping) origToClonedValueMap[mdi] = reabstracted @@ -998,11 +990,10 @@ private extension Builder { } } - var releasableClonedReabstractedClosures: [PartialApplyInst] = [] var origToClonedValueMap = origToClonedValueMap let finalClonedReabstractedClosure = inner(rootClosure, clonedRootClosure, reabstractedClosure, - &releasableClonedReabstractedClosures, &origToClonedValueMap) - return (finalClonedReabstractedClosure as! SingleValueInstruction, releasableClonedReabstractedClosures) + &origToClonedValueMap) + return (finalClonedReabstractedClosure as! SingleValueInstruction) } func destroyPartialApply(pai: PartialApplyInst, _ context: FunctionPassContext){ diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CopyToBorrowOptimization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CopyToBorrowOptimization.swift index b9caf36d8b892..d9abef94fe499 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CopyToBorrowOptimization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CopyToBorrowOptimization.swift @@ -360,6 +360,13 @@ private extension Value { } var lookThroughForwardingInstructions: Value { + if let bfi = definingInstruction as? BorrowedFromInst, + !bfi.borrowedPhi.isReborrow, + bfi.enclosingValues.count == 1 + { + // Return the single forwarded enclosingValue + return bfi.enclosingValues[0] + } if let fi = definingInstruction as? ForwardingInstruction, let forwardedOp = fi.singleForwardedOperand { diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DeadStoreElimination.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DeadStoreElimination.swift index 26d765f47907f..43c798f6879e5 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DeadStoreElimination.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/DeadStoreElimination.swift @@ -256,7 +256,7 @@ private extension Deallocation { private extension DeallocStackInst { func isStackDeallocation(of base: AccessBase) -> Bool { - if case .stack(let allocStack) = base, allocstack == allocStack { + if case .stack(let allocStack) = base, operand.value == allocStack { return true } return false diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift index 2f1e5d3cec5a5..a2c256282b528 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift @@ -122,6 +122,8 @@ private func insertEndInitInstructions( use.set(to: ssaUpdater.getValue(atEndOf: use.instruction.parentBlock), context) } } + // This peephole optimization is required to avoid ownership errors. + replacePhisWithIncomingValues(phis: ssaUpdater.insertedPhis, context) } private func constructLetInitRegion( diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift index 679a3ae276c59..9983ee125e933 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift @@ -53,7 +53,7 @@ let lifetimeDependenceDiagnosticsPass = FunctionPass( } } for instruction in function.instructions { - if let markDep = instruction as? MarkDependenceInst, markDep.isUnresolved { + if let markDep = instruction as? MarkDependenceInstruction, markDep.isUnresolved { if let lifetimeDep = LifetimeDependence(markDep, context) { if analyze(dependence: lifetimeDep, context) { // Note: This promotes the mark_dependence flag but does not invalidate analyses; preserving analyses is good, @@ -72,12 +72,16 @@ let lifetimeDependenceDiagnosticsPass = FunctionPass( markDep.settleToEscaping() continue } - if let apply = instruction as? FullApplySite { - // Handle ~Escapable results that do not have a lifetime dependence. This includes implicit initializers and - // @_unsafeNonescapableResult. + if let apply = instruction as? FullApplySite, !apply.hasResultDependence { + // Handle ~Escapable results that do not have a lifetime dependence. This includes implicit initializers, calls to + // closures, and @_unsafeNonescapableResult. apply.resultOrYields.forEach { - if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0, - context) { + if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0, apply: apply, context) { + _ = analyze(dependence: lifetimeDep, context) + } + } + apply.indirectResultOperands.forEach { + if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0.value, apply: apply, context) { _ = analyze(dependence: lifetimeDep, context) } } @@ -195,19 +199,43 @@ private struct DiagnoseDependence { if function.hasUnsafeNonEscapableResult { return .continueWalk } - // If the dependence scope is global, then it has immortal lifetime. - if case .global = dependence.scope { + // Check for immortal lifetime. + switch dependence.scope { + case .global: return .continueWalk + case let .unknown(value): + if value.type.isVoid { + return .continueWalk + } + default: + break } // Check that the parameter dependence for this result is the same // as the current dependence scope. if let arg = dependence.scope.parentValue as? FunctionArgument, - function.argumentConventions[resultDependsOn: arg.index] != nil { - // The returned value depends on a lifetime that is inherited or - // borrowed in the caller. The lifetime of the argument value - // itself is irrelevant here. - log(" has dependent function result") - return .continueWalk + let argDep = function.argumentConventions[resultDependsOn: arg.index] { + switch argDep { + case .inherit: + if dependence.markDepInst != nil { + // A mark_dependence represents a "borrow" scope. A local borrow scope cannot inherit the caller's dependence + // because the borrow scope depends on the argument value itself, while the caller allows the result to depend + // on a value that the argument was copied from. + break + } + fallthrough + case .scope: + // The returned value depends on a lifetime that is inherited or + // borrowed in the caller. The lifetime of the argument value + // itself is irrelevant here. + log(" has dependent function result") + return .continueWalk + } + // Briefly (April 2025), RawSpan._extracting, Span._extracting, and UTF8Span.span returned a borrowed value that + // depended on a copied argument. Continue to support those interfaces. The implementations were correct but + // needed an explicit _overrideLifetime. + if let sourceFileKind = dependence.function.sourceFileKind, sourceFileKind == .interface { + return .continueWalk + } } return .abortWalk } @@ -220,38 +248,56 @@ private struct DiagnoseDependence { onError() // Identify the escaping variable. - let escapingVar = LifetimeVariable(dependent: operand.value, context) - let varName = escapingVar.name - if let varName { - diagnose(escapingVar.sourceLoc, .lifetime_variable_outside_scope, - varName) + let escapingVar = LifetimeVariable(usedBy: operand, context) + if let varDecl = escapingVar.varDecl { + // Use the variable location, not the access location. + // Variable names like $return_value and $implicit_value don't have source locations. + let sourceLoc = varDecl.nameLoc ?? escapingVar.sourceLoc + diagnose(sourceLoc, .lifetime_variable_outside_scope, escapingVar.name ?? "") + } else if let sourceLoc = escapingVar.sourceLoc { + diagnose(sourceLoc, .lifetime_value_outside_scope) } else { - diagnose(escapingVar.sourceLoc, .lifetime_value_outside_scope) + // Always raise an error even if we can't find a source location. + let sourceLoc = function.location.sourceLoc + if let accessorKind = escapingVar.accessorKind { + diagnose(sourceLoc, .lifetime_value_outside_accessor, accessorKind) + } else { + // Thunks do not have a source location, but we try to use the function location anyway. + let thunkSelect = dependence.function.thunkKind == .noThunk ? 0 : 1 + diagnose(sourceLoc, .lifetime_value_outside_thunk, thunkSelect, function.name) + } } reportScope() // Identify the use point. - let userSourceLoc = operand.instruction.location.sourceLoc - diagnose(userSourceLoc, diagID) + if let userSourceLoc = operand.instruction.location.sourceLoc { + diagnose(userSourceLoc, diagID) + } } - // Identify the dependence scope. + // Identify the dependence scope. If no source location is found, bypass this diagnostic. func reportScope() { - if case let .access(beginAccess) = dependence.scope { - let parentVar = LifetimeVariable(dependent: beginAccess, context) - if let sourceLoc = beginAccess.location.sourceLoc ?? parentVar.sourceLoc { - diagnose(sourceLoc, .lifetime_outside_scope_access, - parentVar.name ?? "") - } + let parentVar = LifetimeVariable(definedBy: dependence.parentValue, context) + // First check if the dependency is limited to an access scope. If the access has no source location then + // fall-through to report possible dependence on an argument. + if parentVar.isAccessScope, let accessLoc = parentVar.sourceLoc { + diagnose(accessLoc, .lifetime_outside_scope_access, parentVar.name ?? "") return } - if let arg = dependence.parentValue as? Argument, - let varDecl = arg.varDecl, - let sourceLoc = arg.sourceLoc { - diagnose(sourceLoc, .lifetime_outside_scope_argument, - varDecl.userFacingName) + // If the argument does not have a source location (e.g. a synthesized accessor), report the function location. The + // function's source location is sufficient for argument diagnostics, but if the function has no location, don't + // report any scope. + if parentVar.isArgument, let argLoc = parentVar.sourceLoc ?? function.location.sourceLoc { + if parentVar.isClosureCapture { + diagnose(argLoc, .lifetime_outside_scope_capture) + } else if let parentName = parentVar.name { + diagnose(argLoc, .lifetime_outside_scope_argument, parentName) + } else { + diagnose(argLoc, .lifetime_outside_scope_synthesized_argument, parentVar.accessorKind ?? function.name) + } return } - let parentVar = LifetimeVariable(dependent: dependence.parentValue, context) + // Now diagnose dependencies on regular variable and value scopes. + // Thunks do not have a function location, so any scopes inside the thunk will be ignored. if let parentLoc = parentVar.sourceLoc { if let parentName = parentVar.name { diagnose(parentLoc, .lifetime_outside_scope_variable, parentName) @@ -265,46 +311,79 @@ private struct DiagnoseDependence { // Identify a best-effort variable declaration based on a defining SIL // value or any lifetime dependent use of that SIL value. private struct LifetimeVariable { - var varDecl: VarDecl? - var sourceLoc: SourceLoc? + var varDecl: VarDecl? = nil + var sourceLoc: SourceLoc? = nil + var isAccessScope: Bool = false + var isArgument: Bool = false + var isClosureCapture: Bool = false + var accessorKind: String? + var thunkKind: Function.ThunkKind = .noThunk var name: StringRef? { return varDecl?.userFacingName } - init(dependent value: Value, _ context: some Context) { - if value.type.isAddress { - self = Self(accessBase: value.accessBase, context) + init(usedBy operand: Operand, _ context: some Context) { + self = .init(dependent: operand.value, context) + // variable names like $return_value and $implicit_value don't have source locations. + // For @out arguments, the operand's location is the best answer. + // Otherwise, fall back to the function's location. + self.sourceLoc = self.sourceLoc ?? operand.instruction.location.sourceLoc + ?? operand.instruction.parentFunction.location.sourceLoc + } + + init(definedBy value: Value, _ context: some Context) { + self = .init(dependent: value, context) + // Fall back to the function's location. + self.sourceLoc = self.sourceLoc ?? value.parentFunction.location.sourceLoc + } + + private init(dependent value: Value, _ context: some Context) { + guard let introducer = getFirstVariableIntroducer(of: value, context) else { return } - if let firstIntroducer = getFirstVariableIntroducer(of: value, context) { - self = Self(introducer: firstIntroducer) + if introducer.type.isAddress { + if let beginAccess = introducer as? BeginAccessInst { + // Recurse through beginAccess to find the variable introducer rather than the variable access. + self = .init(dependent: beginAccess.address, context) + self.isAccessScope = true + // However, remember source location of the innermost access. + self.sourceLoc = beginAccess.location.sourceLoc ?? self.sourceLoc + return + } + self = .init(accessBase: introducer.accessBase, context) return } - self.varDecl = nil - self.sourceLoc = nil + self = Self(introducer: introducer, context) } private func getFirstVariableIntroducer(of value: Value, _ context: some Context) -> Value? { var introducer: Value? - var useDefVisitor = VariableIntroducerUseDefWalker(context, scopedValue: value) { + var useDefVisitor = VariableIntroducerUseDefWalker(context, scopedValue: value, ignoreTrivialCopies: false) { introducer = $0 return .abortWalk } defer { useDefVisitor.deinitialize() } - _ = useDefVisitor.walkUp(valueOrAddress: value) + _ = useDefVisitor.walkUp(newLifetime: value) return introducer } - private init(introducer: Value) { - if let arg = introducer as? Argument { + private init(introducer: Value, _ context: some Context) { + if let arg = introducer as? FunctionArgument { self.varDecl = arg.varDecl - } else { - self.sourceLoc = introducer.definingInstruction?.location.sourceLoc - self.varDecl = introducer.definingInstruction?.findVarDecl() + self.sourceLoc = arg.sourceLoc + self.isArgument = true + self.isClosureCapture = arg.isClosureCapture + return } - if let varDecl { - sourceLoc = varDecl.nameLoc + if let varDecl = introducer.definingInstruction?.findVarDecl() { + self.varDecl = varDecl + self.sourceLoc = varDecl.nameLoc + } else if let sourceLoc = introducer.definingInstruction?.location.sourceLoc { + self.sourceLoc = sourceLoc + } else { + self.accessorKind = introducer.parentFunction.accessorKindName + self.thunkKind = introducer.parentFunction.thunkKind } } @@ -318,32 +397,27 @@ private struct LifetimeVariable { // never be produced by one of these, except when it is redundant with the `alloc_box` VarDecl. It does not seem // possible for a box to be moved/borrowed directly into another variable's box. Reassignment always loads/stores // the value. - self = Self(introducer: projectBox.box.referenceRoot) + self = .init(introducer: projectBox.box.referenceRoot, context) case .stack(let allocStack): - self = Self(introducer: allocStack) + self = .init(introducer: allocStack, context) case .global(let globalVar): self.varDecl = globalVar.varDecl self.sourceLoc = varDecl?.nameLoc case .class(let refAddr): - self.varDecl = refAddr.varDecl - self.sourceLoc = refAddr.location.sourceLoc + self = .init(introducer: refAddr, context) case .tail(let refTail): - self = Self(introducer: refTail.instance) + self = .init(introducer: refTail.instance, context) case .argument(let arg): - self.varDecl = arg.varDecl - self.sourceLoc = arg.sourceLoc + self = .init(introducer: arg, context) case .yield(let result): // TODO: bridge VarDecl for FunctionConvention.Yields - self.varDecl = nil - self.sourceLoc = result.parentInstruction.location.sourceLoc + self = .init(introducer: result, context) case .storeBorrow(let sb): self = .init(dependent: sb.source, context) case .pointer(let ptrToAddr): - self.varDecl = nil - self.sourceLoc = ptrToAddr.location.sourceLoc + self = .init(introducer: ptrToAddr, context) case .index, .unidentified: - self.varDecl = nil - self.sourceLoc = nil + break } } } diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift index 61ffbee1a612c..0a4d353026ebb 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift @@ -95,6 +95,7 @@ extension LifetimeDependentApply { struct LifetimeSource { let targetKind: TargetKind let convention: LifetimeDependenceConvention + let isInout: Bool let value: Value } @@ -116,7 +117,8 @@ extension LifetimeDependentApply { guard let dep = applySite.resultDependence(on: operand) else { continue } - info.sources.push(LifetimeSource(targetKind: .result, convention: dep, value: operand.value)) + let isInout = applySite.convention(of: operand)?.isInout ?? false + info.sources.push(LifetimeSource(targetKind: .result, convention: dep, isInout: isInout, value: operand.value)) } return info } @@ -135,6 +137,7 @@ extension LifetimeDependentApply { ? TargetKind.yieldAddress : TargetKind.yield info.sources.push(LifetimeSource(targetKind: targetKind, convention: .scope(addressable: false, addressableForDeps: false), + isInout: false, value: beginApply.token)) } for operand in applySite.parameterOperands { @@ -145,9 +148,15 @@ extension LifetimeDependentApply { case .inherit: continue case .scope: + // FIXME: For yields with a scoped lifetime dependence, dependence on parameter operands is redundant, + // since we introduce dependence on the begin_apply's token as well. + // This can lead to duplicate lifetime dependence diagnostics in some cases. + // However this is neccessary for safety when begin_apply gets inlined which will delete the dependence on the token. for yieldedValue in beginApply.yieldedValues { let targetKind = yieldedValue.type.isAddress ? TargetKind.yieldAddress : TargetKind.yield - info.sources.push(LifetimeSource(targetKind: targetKind, convention: .inherit, value: operand.value)) + let isInout = applySite.convention(of: operand)?.isInout ?? false + info.sources.push(LifetimeSource(targetKind: targetKind, convention: dep, isInout: isInout, + value: operand.value)) } } } @@ -176,7 +185,8 @@ extension LifetimeDependentApply { guard let dep = dep else { continue } - info.sources.push(LifetimeSource(targetKind: targetKind, convention: dep, value: operand.value)) + let isInout = applySite.convention(of: operand)?.isInout ?? false + info.sources.push(LifetimeSource(targetKind: targetKind, convention: dep, isInout: isInout, value: operand.value)) } return info } @@ -219,8 +229,8 @@ private extension LifetimeDependentApply.LifetimeSourceInfo { return } // Create a new dependence on the apply's access to the argument. - for varIntoducer in gatherVariableIntroducers(for: source.value, context) { - let scope = LifetimeDependence.Scope(base: varIntoducer, context) + for varIntroducer in gatherVariableIntroducers(for: source.value, ignoreTrivialCopies: !source.isInout, context) { + let scope = LifetimeDependence.Scope(base: varIntroducer, context) log("Scoped lifetime from \(source.value)") log(" scope: \(scope)") bases.append(scope.parentValue) @@ -247,18 +257,21 @@ private func insertResultDependencies(for apply: LifetimeDependentApply, _ conte insertMarkDependencies(value: dependentValue, initializer: nil, bases: sources.bases, builder: builder, context) } for resultOper in apply.applySite.indirectResultOperands { - let accessBase = resultOper.value.accessBase - guard case let .store(initializingStore, initialAddress) = accessBase.findSingleInitializer(context) else { - continue + guard let initialAddress = resultOper.value.accessBase.address else { + diagnoseUnknownDependenceSource(sourceLoc: apply.applySite.location.sourceLoc, context) + return } - assert(initializingStore == resultOper.instruction, "an indirect result is a store") Builder.insert(after: apply.applySite, context) { builder in - insertMarkDependencies(value: initialAddress, initializer: initializingStore, bases: sources.bases, + insertMarkDependencies(value: initialAddress, initializer: resultOper.instruction, bases: sources.bases, builder: builder, context) } } } +private func diagnoseUnknownDependenceSource(sourceLoc: SourceLoc?, _ context: FunctionPassContext) { + context.diagnosticEngine.diagnose(sourceLoc, .lifetime_value_outside_scope, []) +} + private func insertParameterDependencies(apply: LifetimeDependentApply, target: Operand, _ context: FunctionPassContext ) { guard var sources = apply.getParameterDependenceSources(target: target) else { @@ -300,8 +313,8 @@ private func insertMarkDependencies(value: Value, initializer: Instruction?, } } -/// Walk up the value dependence chain to find the best-effort variable declaration. Typically called while diagnosing -/// an error. +/// Walk up the value dependence chain to find the best-effort variable declaration. Used to find the source of a borrow +/// dependence or to print the source variable in a diagnostic message. /// /// Returns an array with at least one introducer value. /// @@ -309,16 +322,17 @@ private func insertMarkDependencies(value: Value, initializer: Instruction?, /// - a variable declaration (begin_borrow [var_decl], move_value [var_decl]) /// - a begin_access for a mutable variable access /// - the value or address "root" of the dependence chain -func gatherVariableIntroducers(for value: Value, _ context: Context) +func gatherVariableIntroducers(for value: Value, ignoreTrivialCopies: Bool, _ context: Context) -> SingleInlineArray { var introducers = SingleInlineArray() - var useDefVisitor = VariableIntroducerUseDefWalker(context, scopedValue: value) { + var useDefVisitor = VariableIntroducerUseDefWalker(context, scopedValue: value, + ignoreTrivialCopies: ignoreTrivialCopies) { introducers.push($0) return .continueWalk } defer { useDefVisitor.deinitialize() } - _ = useDefVisitor.walkUp(valueOrAddress: value) + _ = useDefVisitor.walkUp(newLifetime: value) assert(!introducers.isEmpty, "missing variable introducer") return introducers } @@ -330,7 +344,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context) /// Walk up lifetime dependencies to the first value associated with a variable declaration. /// /// To start walking: -/// walkUp(valueOrAddress: Value) -> WalkResult +/// walkUp(newLifetime: Value) -> WalkResult /// /// This utility finds the value or address associated with the lvalue (variable declaration) that is passed as the /// source of a lifetime dependent argument. If no lvalue is found, then it finds the "root" of the chain of temporary @@ -382,10 +396,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context) /// All of the dependent uses including `end_borrow %5` and `destroy_value %4` must be before the end of the dependence /// scope: `destroy_value %parent`. In this case, the dependence parent is an owned value, so the scope is simply the /// value's OSSA lifetime. -struct VariableIntroducerUseDefWalker : ForwardingUseDefWalker { - // The ForwardingUseDefWalker's context is the most recent lifetime owner. - typealias PathContext = Value? - +struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefValueWalker, LifetimeDependenceUseDefAddressWalker { let context: Context // If the scoped value is trivial, then only the variable's lexical scope is relevant, and access scopes can be @@ -399,11 +410,15 @@ struct VariableIntroducerUseDefWalker : ForwardingUseDefWalker { // Call \p visit rather than calling this directly. private let visitorClosure: (Value) -> WalkResult - init(_ context: Context, scopedValue: Value, _ visitor: @escaping (Value) -> WalkResult) { + init(_ context: Context, scopedValue: Value, ignoreTrivialCopies: Bool, _ visitor: @escaping (Value) -> WalkResult) { self.context = context - self.isTrivialScope = scopedValue.type.isAddress - ? scopedValue.type.objectType.isTrivial(in: scopedValue.parentFunction) - : scopedValue.isTrivial(context) + if ignoreTrivialCopies { + self.isTrivialScope = scopedValue.type.isAddress + ? scopedValue.type.objectType.isTrivial(in: scopedValue.parentFunction) + : scopedValue.isTrivial(context) + } else { + self.isTrivialScope = false + } self.visitedValues = ValueSet(context) self.visitorClosure = visitor } @@ -412,128 +427,50 @@ struct VariableIntroducerUseDefWalker : ForwardingUseDefWalker { visitedValues.deinitialize() } - mutating func needWalk(for value: Value, _ owner: Value?) -> Bool { - visitedValues.insert(value) - } - mutating func introducer(_ value: Value, _ owner: Value?) -> WalkResult { return visitorClosure(value) } - mutating func walkUp(valueOrAddress: Value) -> WalkResult { - if valueOrAddress.type.isAddress { - return walkUp(address: valueOrAddress) - } - return walkUp(newLifetime: valueOrAddress) + mutating func addressIntroducer(_ address: Value, access: AccessBaseAndScopes) -> WalkResult { + return visitorClosure(address) + } + + mutating func needWalk(for value: Value, _ owner: Value?) -> Bool { + visitedValues.insert(value) + } + + mutating func needWalk(for address: Value) -> Bool { + visitedValues.insert(address) } -} -// Helpers -extension VariableIntroducerUseDefWalker { mutating func walkUp(newLifetime: Value) -> WalkResult { + if newLifetime.type.isAddress { + return walkUp(address: newLifetime) + } let newOwner = newLifetime.ownership == .owned ? newLifetime : nil return walkUp(value: newLifetime, newOwner) } + /// Override to check for variable introducers: move_value, begin_value, before following + /// OwnershipTransitionInstruction. mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult { - // Check for variable introducers: move_value, begin_value, before following OwnershipTransitionInstruction. if let inst = value.definingInstruction, VariableScopeInstruction(inst) != nil { return visitorClosure(value) } - switch value.definingInstruction { - case let transition as OwnershipTransitionInstruction: - return walkUp(newLifetime: transition.operand.value) - case let load as LoadInstruction: - return walkUp(address: load.address) - default: - break - } - // If the dependence chain has a phi, consider it a root. Dependence roots dominate all dependent values. - if Phi(value) != nil { - return introducer(value, owner) - } - // ForwardingUseDefWalker will callback to introducer() when it finds no forwarding instruction. - return walkUpDefault(forwarded: value, owner) - } - - // Handle temporary allocations and access scopes. - mutating func walkUp(address: Value) -> WalkResult { - let accessBaseAndScopes = address.accessBaseWithScopes - // Continue walking for some kinds of access base. - switch accessBaseAndScopes.base { - case .box, .global, .class, .tail, .pointer, .index, .unidentified: - break - case let .stack(allocStack): - if allocStack.varDecl == nil { - // Ignore temporary stack locations. Their access scopes do not affect lifetime dependence. - return walkUp(stackInitializer: allocStack, at: address) - } - case let .argument(arg): - // Ignore access scopes for @in or @in_guaranteed arguments when all scopes are reads. Do not ignore a [read] - // access of an inout argument or outer [modify]. Mutation later with the outer scope could invalidate the - // borrowed state in this narrow scope. Do not ignore any mark_depedence on the address. - if arg.convention.isIndirectIn && accessBaseAndScopes.isOnlyReadAccess { - return introducer(arg, nil) - } - // @inout arguments may be singly initialized (when no modification exists in this function), but this is not - // relevant here because they require nested access scopes which can never be ignored. - case let .yield(yieldedAddress): - // Ignore access scopes for @in or @in_guaranteed yields when all scopes are reads. - let apply = yieldedAddress.definingInstruction as! FullApplySite - if apply.convention(of: yieldedAddress).isIndirectIn && accessBaseAndScopes.isOnlyReadAccess { - return introducer(yieldedAddress, nil) - } - case .storeBorrow(let sb): - // Walk up through a store into a temporary. - if accessBaseAndScopes.scopes.isEmpty, - case .stack = sb.destinationOperand.value.accessBase { - return walkUp(newLifetime: sb.source) - } - } - // Skip the access scope for unsafe[Mutable]Address. Treat it like a projection of 'self' rather than a separate - // variable access. - if case let .access(innerAccess) = accessBaseAndScopes.scopes.first, - let addressorSelf = innerAccess.unsafeAddressorSelf { - return walkUp(valueOrAddress: addressorSelf) - } - // Ignore the acces scope for trivial values regardless of whether it is singly-initialized. Trivial values do not - // need to be kept alive in memory and can be safely be overwritten in the same scope. Lifetime dependence only - // cares that the loaded value is within the lexical scope of the trivial value's variable declaration. Rather than - // skipping all access scopes, call 'walkUp' on each nested access in case one of them needs to redirect the walk, - // as required for 'access.unsafeAddressorSelf'. - if isTrivialScope { - switch accessBaseAndScopes.scopes.first { - case .none, .base: - break - case let .access(beginAccess): - return walkUp(address: beginAccess.address) - case let .dependence(markDep): - return walkUp(address: markDep.value) - } - } - return introducer(accessBaseAndScopes.enclosingAccess.address ?? address, nil) + return walkUpDefault(value: value, owner) } - // Handle singly-initialized temporary stack locations. - mutating func walkUp(stackInitializer allocStack: AllocStackInst, at address: Value) -> WalkResult { - guard let initializer = allocStack.accessBase.findSingleInitializer(context) else { - return introducer(address, nil) - } - if case let .store(store, _) = initializer { - switch store { - case let store as StoringInstruction: - return walkUp(newLifetime: store.source) - case let srcDestInst as SourceDestAddrInstruction: - return walkUp(address: srcDestInst.destination) - case let apply as FullApplySite: - if let f = apply.referencedFunction, f.isConvertPointerToPointerArgument { - return walkUp(address: apply.parameterOperands[0].value) + /// Override to check for on-stack variables before following an initializer. + mutating func walkUp(address: Value, access: AccessBaseAndScopes) -> WalkResult { + // Check for stack locations that correspond to an lvalue if there isn't any nested access scope. + if access.innermostAccess == nil { + if case let .stack(allocStack) = access.base { + if allocStack.varDecl != nil { + return addressIntroducer(allocStack, access: access) } - default: - break } } - return introducer(address, nil) + return walkUpDefault(address: address, access: access) } } @@ -541,5 +478,5 @@ let variableIntroducerTest = FunctionTest("variable_introducer") { function, arguments, context in let value = arguments.takeValue() print("Variable introducers of: \(value)") - print(gatherVariableIntroducers(for: value, context)) + print(gatherVariableIntroducers(for: value, ignoreTrivialCopies: false, context)) } diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift index ecb69fde5b197..86f0b9be10c58 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift @@ -116,14 +116,98 @@ let lifetimeDependenceScopeFixupPass = FunctionPass( // Redirect the dependence base to ignore irrelevant borrow scopes. let newLifetimeDep = markDep.rewriteSkippingBorrow(scope: innerLifetimeDep.scope, context) - // Recursively sink enclosing end_access, end_borrow, or end_apply. - let args = extendScopes(dependence: newLifetimeDep, localReachabilityCache, context) + // Recursively sink enclosing end_access, end_borrow, end_apply, and destroy_value. If the scope can be extended + // into the caller, return the function arguments that are the dependency sources. + var scopeExtension = ScopeExtension(localReachabilityCache, context) + guard scopeExtension.extendScopes(dependence: newLifetimeDep) else { + continue + } + let args = scopeExtension.findArgumentDependencies() + + // If the scope cannot be extended to the caller, this must be the outermost dependency level. + // Insert end_cow_mutation_addr if needed. + if args.isEmpty { + createEndCOWMutationIfNeeded(lifetimeDep: newLifetimeDep, context) + } // Redirect the dependence base to the function arguments. This may create additional mark_dependence instructions. markDep.redirectFunctionReturn(to: args, context) } } +private extension Type { + func mayHaveMutableSpan(in function: Function, _ context: FunctionPassContext) -> Bool { + if hasArchetype { + return true + } + if isBuiltinType { + return false + } + // Only result types that are nominal can have a MutableSpan derived from an inout array access. + if nominal == nil { + return false + } + if nominal == context.swiftMutableSpan { + return true + } + if isStruct { + guard let fields = getNominalFields(in: function) else { + return false + } + return fields.contains { $0.mayHaveMutableSpan(in: function, context) } + } + if isTuple { + return tupleElements.contains { $0.mayHaveMutableSpan(in: function, context) } + } + if isEnum { + guard let cases = getEnumCases(in: function) else { + return true + } + return cases.contains { $0.payload?.mayHaveMutableSpan(in: function, context) ?? false } + } + // Classes cannot be ~Escapable, therefore cannot hold a MutableSpan. + if isClass { + return false + } + return false + } +} + +/// Insert end_cow_mutation_addr for lifetime dependent values that maybe of type MutableSpan and depend on a mutable address. +private func createEndCOWMutationIfNeeded(lifetimeDep: LifetimeDependence, _ context: FunctionPassContext) { + var scoped : ScopedInstruction + + // Handle cases which generate mutable addresses: begin_access [modify] and yield & + switch lifetimeDep.scope { + case let .access(beginAccess): + if beginAccess.accessKind != .modify { + return + } + scoped = beginAccess + case let .yield(value): + let beginApply = value.definingInstruction as! BeginApplyInst + if value == beginApply.token { + return + } + if beginApply.convention(of: value as! MultipleValueInstructionResult) != .indirectInout { + return + } + scoped = beginApply + // None of the below cases can generate a mutable address. + case .owned, .borrowed, .local, .initialized, .caller, .global, .unknown: + return + } + + guard lifetimeDep.dependentValue.type.mayHaveMutableSpan(in: lifetimeDep.dependentValue.parentFunction, context) else { + return + } + + for endInstruction in scoped.endInstructions { + let builder = Builder(before: endInstruction, context) + builder.createEndCOWMutationAddr(address: lifetimeDep.parentValue) + } +} + private extension MarkDependenceInstruction { /// Rewrite the mark_dependence base operand to ignore inner borrow scopes (begin_borrow, load_borrow). /// @@ -189,6 +273,31 @@ private extension MarkDependenceAddrInst { } } +/// A scope extension is a set of nested scopes and their owners. The owner is a value that represents ownership of +/// the outermost scopes, which cannot be extended; it limits how far the nested scopes can be extended. +private struct ScopeExtension { + let context: FunctionPassContext + let localReachabilityCache: LocalVariableReachabilityCache + + /// The ownership lifetime of the dependence base, which cannot be extended. + var owners = SingleInlineArray() + + // Initialized after walking dependent uses. True if the scope can be extended into the caller. + var dependsOnCaller: Bool? + + // Scopes listed in RPO over an upward walk. The outermost scope is first. + var scopes = SingleInlineArray() + + var innermostScope: ExtendableScope { get { scopes.last! } } + + var visitedValues: ValueSet? + + init(_ localReachabilityCache: LocalVariableReachabilityCache, _ context: FunctionPassContext) { + self.localReachabilityCache = localReachabilityCache + self.context = context + } +} + /// Transitively extend nested scopes that enclose the dependence base. /// /// If the parent function returns the dependent value, then this returns the function arguments that represent the @@ -218,215 +327,239 @@ private extension MarkDependenceAddrInst { // access. This scope fixup pass must extend '%a1' to cover the `@useDependent` but must not extend the base of the // `mark_dependence` to the outer access `%0`. This ensures that exclusivity diagnostics correctly reports the // violation, and that subsequent optimizations do not shrink the inner access `%a1`. -private func extendScopes(dependence: LifetimeDependence, - _ localReachabilityCache: LocalVariableReachabilityCache, - _ context: FunctionPassContext) -> SingleInlineArray { - log("Scope fixup for lifetime dependent instructions: \(dependence)") - - // Each scope extension is a set of nested scopes and an owner. The owner is a value that represents ownerhip of the - // outermost scope, which cannot be extended; it limits how far the nested scopes can be extended. - guard let scopeExtensions = dependence.scope.gatherExtensions(context) else { - return SingleInlineArray() - } - var dependsOnArgs = SingleInlineArray() - for scopeExtension in scopeExtensions { - var scopeExtension = scopeExtension - guard var useRange = computeDependentUseRange(of: dependence, within: &scopeExtension, localReachabilityCache, - context) else { - continue - } +extension ScopeExtension { + mutating func extendScopes(dependence: LifetimeDependence) -> Bool { + log("Scope fixup for lifetime dependent instructions:\n\(dependence)") - // deinitializes 'useRange' - guard scopeExtension.tryExtendScopes(over: &useRange, context) else { - continue + gatherExtensions(dependence: dependence) + + // computeDependentUseRange initializes scopeExtension.dependsOnCaller. + guard var useRange = computeDependentUseRange(of: dependence) else { + return false } - if scopeExtension.dependsOnCaller, let arg = scopeExtension.dependsOnArg { - dependsOnArgs.push(arg) + // tryExtendScopes deinitializes 'useRange' + var scopesToExtend = SingleInlineArray() + guard canExtendScopes(over: &useRange, scopesToExtend: &scopesToExtend) else { + useRange.deinitialize() + return false } + // extend(over:) must receive the original unmodified `useRange`, without intermediate scope ending instructions. + // This deinitializes `useRange` before erasing instructions. + extend(scopesToExtend: scopesToExtend, over: &useRange, context) + return true } - return dependsOnArgs } -/// All scopes nested within a single dependence base that require extension. -private struct ScopeExtension { - /// The ownership lifetime of the dependence base, which cannot be extended. - let owner: Value +// TODO: add parent and child indices to model a DAG of scopes. This will allow sibling scopes that do not follow a +// stack discipline among them but still share the same parent and child scopes. This can occur with dependencies on +// multiple call operands. Until then, scope extension may bail out unnecessarily while trying to extend over a sibling +// scope. +private struct ExtendableScope { + enum Introducer { + case scoped(ScopedInstruction) + case owned(Value) + } - /// The scopes nested under 'value' that may be extended, in inside-out order. There is always at - /// least one element, otherwise there is nothing to consider extending. - let nestedScopes: SingleInlineArray + let scope: LifetimeDependence.Scope + let introducer: Introducer - var innerScope: LifetimeDependence.Scope { get { nestedScopes.first! } } + var firstInstruction: Instruction { + switch introducer { + case let .scoped(scopedInst): + return scopedInst.instruction + case let .owned(value): + if let definingInst = value.definingInstructionOrTerminator { + return definingInst + } + return value.parentBlock.instructions.first! + } + } + var endInstructions: LazyMapSequence, Instruction> { + switch introducer { + case let .scoped(scopedInst): + return scopedInst.endOperands.users + case let .owned(value): + return value.uses.endingLifetime.users + } + } - /// `dependsOnArg` is set to the function argument that represents the caller's dependency source. - /// - /// Note: for non-address owners, this is equivalent to: owner as? FunctionArg? - var dependsOnArg: FunctionArgument? + // Allow scope extension as long as `beginInst` is scoped instruction and does not define a variable scope. + init?(_ scope: LifetimeDependence.Scope, beginInst: Instruction?) { + self.scope = scope + guard let beginInst = beginInst, VariableScopeInstruction(beginInst) == nil else { + return nil + } + guard let scopedInst = beginInst as? ScopedInstruction else { + return nil + } + self.introducer = .scoped(scopedInst) + } - /// `dependsOnCaller` is true if the dependent value is returned by the function. - /// Initialized during computeDependentUseRange(). - var dependsOnCaller = false + // Allow extension of owned temporaries that + // (a) are Escapable + // (b) do not define a variable scope + // (c) are only consumed by destroy_value + init?(_ scope: LifetimeDependence.Scope, owner: Value) { + self.scope = scope + // TODO: allow extension of lifetime dependent values by implementing a ScopeExtensionWalker that extends + // LifetimeDependenceUseDefWalker. + guard owner.type.isEscapable(in: owner.parentFunction), + VariableScopeInstruction(owner.definingInstruction) == nil, + owner.uses.endingLifetime.allSatisfy({ $0.instruction is DestroyValueInst }) else { + return nil + } + self.introducer = .owned(owner) + } } -private extension LifetimeDependence.Scope { - /// The instruction that introduces an extendable scope. This returns a non-nil scope introducer for - /// each scope in ScopeExtension.nestedScopes. - var extendableBegin: ScopedInstruction? { - switch self { - case let .access(beginAccess): - return beginAccess - case let .borrowed(beginBorrow): - return beginBorrow.value.definingInstruction as? ScopedInstruction - case let .yield(yieldedValue): - return yieldedValue.definingInstruction as? ScopedInstruction - case let .initialized(initializer): - switch initializer { - case let .store(initializingStore: store, initialAddress: _): - if let sb = store as? StoreBorrowInst { - return sb - } - return nil - case .argument, .yield: - // TODO: extend indirectly yielded scopes. - return nil - } - default: - return nil +// Gather extendable scopes. +extension ScopeExtension { + mutating func gatherExtensions(dependence: LifetimeDependence) { + visitedValues = ValueSet(context) + defer { + visitedValues!.deinitialize() + visitedValues = nil } + gatherExtensions(scope: dependence.scope) } - /// Precondition: the 'self' scope encloses a dependent value. 'innerScopes' are the extendable scopes enclosed by - /// 'self' that also enclose the dependent value. - /// - /// Gather the list of ScopeExtensions. Each extension is a list of scopes, including 'innerScopes', 'self' and, - /// recursively, any of its enclosing scopes that are extendable. We may have multiple extensions because a scope - /// introducer may itself depend on multiple operands. - /// - /// Return 'nil' if 'self' is not extendable. - func gatherExtensions(innerScopes: SingleInlineArray? = nil, _ context: FunctionPassContext) - -> SingleInlineArray? { + mutating func gatherExtensions(valueOrAddress: Value) { + if visitedValues!.insert(valueOrAddress) { + gatherExtensions(scope: LifetimeDependence.Scope(base: valueOrAddress, context)) + } + } - // Note: LifetimeDependence.Scope.extend() will assume that all inner scopes begin with a ScopedInstruction. - var innerScopes = innerScopes ?? SingleInlineArray() - switch self { + mutating func nonExtendable(_ scope: LifetimeDependence.Scope) { + owners.push(scope.parentValue) + } + + // If `scope` is extendable, find its owner or outer scopes first, then push for extension. + mutating func gatherExtensions(scope: LifetimeDependence.Scope) { + switch scope { case let .access(beginAccess): - return gatherAccessExtension(beginAccess: beginAccess, innerScopes: &innerScopes, context) + gatherAccessExtensions(beginAccess: beginAccess) + return case let .borrowed(beginBorrow): - // begin_borrow is extendable, so push this scope. - innerScopes.push(self) - return gatherBorrowExtension(borrowedValue: beginBorrow.baseOperand!.value, innerScopes: innerScopes, context) - - case let .yield(yieldedValue): - // A yield is extendable, so push this scope. - innerScopes.push(self) - // Create a separate ScopeExtension for each operand that the yielded value depends on. - var extensions = SingleInlineArray() - let applySite = yieldedValue.definingInstruction as! BeginApplyInst - for operand in applySite.parameterOperands { - guard let dep = applySite.resultDependence(on: operand), dep.isScoped else { - continue + if let beginInst = beginBorrow.value.definingInstruction { + if let extScope = ExtendableScope(scope, beginInst: beginInst) { + gatherExtensions(valueOrAddress: beginBorrow.baseOperand!.value) + scopes.push(extScope) + return } - // Pass a copy of innerScopes without modifying this one. - extensions.append(contentsOf: gatherOperandExtension(on: operand, innerScopes: innerScopes, context)) } - return extensions + + case let .yield(yieldedValue): + let beginApply = yieldedValue.definingInstruction as! BeginApplyInst + gatherYieldExtension(beginApply) + scopes.push(ExtendableScope(scope, beginInst: beginApply)!) + return + case let .initialized(initializer): switch initializer { case let .store(initializingStore: store, initialAddress: _): if let sb = store as? StoreBorrowInst { - innerScopes.push(self) - // Only follow the source of the store_borrow. The address is always an alloc_stack without any access scope. - return gatherBorrowExtension(borrowedValue: sb.source, innerScopes: innerScopes, context) + // Follow the source for nested scopes. + gatherExtensions(valueOrAddress: sb.source) + scopes.push(ExtendableScope(scope, beginInst: sb)!) + return } - return nil case .argument, .yield: // TODO: extend indirectly yielded scopes. - return nil + break + } + case let .owned(value): + if let extScope = ExtendableScope(scope, owner: value) { + scopes.push(extScope) + return + } + + case let .local(varInst): + switch varInst { + case let .beginBorrow(beginBorrow): + if let extScope = ExtendableScope(scope, beginInst: beginBorrow) { + gatherExtensions(valueOrAddress: beginBorrow.operand.value) + scopes.push(extScope) + return + } + + case let .moveValue(moveValue): + if let extScope = ExtendableScope(scope, owner: moveValue) { + scopes.push(extScope) + return + } } default: - return nil + break } + nonExtendable(scope) } - /// Unlike LifetimeDependenceInsertion this does not use gatherVariableIntroducers. The purpose here is to extend - /// any enclosing OSSA scopes as far as possible to achieve the longest possible owner lifetime, rather than to - /// find the "dependence root" for a call argument. - func gatherOperandExtension(on operand: Operand, innerScopes: SingleInlineArray, - _ context: FunctionPassContext) -> SingleInlineArray { - let enclosingScope = LifetimeDependence.Scope(base: operand.value, context) - if let extensions = enclosingScope.gatherExtensions(innerScopes: innerScopes, context) { - return extensions + /// Unlike LifetimeDependenceInsertion, this does not stop at an argument's "variable introducer" and does not stop at + /// an addressable parameter. The purpose here is to extend any enclosing OSSA scopes as far as possible to achieve + /// the longest possible owner lifetime, rather than to find the source-level lvalue for a call argument. + mutating func gatherYieldExtension(_ beginApply: BeginApplyInst) { + // Create a separate ScopeExtension for each operand that the yielded value depends on. + for operand in beginApply.parameterOperands { + gatherExtensions(valueOrAddress: operand.value) } - // This is the outermost scope to be extended because gatherExtensions did not find an enclosing scope. - return SingleInlineArray(element: getOuterExtension(owner: operand.value, nestedScopes: innerScopes, context)) - } - - func getOuterExtension(owner: Value, nestedScopes: SingleInlineArray, - _ context: FunctionPassContext) -> ScopeExtension { - let dependsOnArg = owner as? FunctionArgument - return ScopeExtension(owner: owner, nestedScopes: nestedScopes, dependsOnArg: dependsOnArg) } - // Find the nested access scopes that may be extended as if they are the same access. This includes any combination of - // read/modify accesses, regardless of whether they may cause an exclusivity violation. The outer accesses will only - // be extended as far as required such that the innermost access coveres all dependent uses. - // Set ScopeExtension.dependsOnArg if the nested accesses are all compatible with the argument's convention. Then, if - // all nested accesses were extended to the return statement, it is valid to logically combine them into a single - // access for the purpose of diagnostinc lifetime dependence. - func gatherAccessExtension(beginAccess: BeginAccessInst, - innerScopes: inout SingleInlineArray, - _ context: FunctionPassContext) -> SingleInlineArray { - // Finding the access base also finds all intermediate nested scopes; there is no need to recursively call - // gatherExtensions(). + mutating func gatherAccessExtensions(beginAccess: BeginAccessInst) { let accessBaseAndScopes = beginAccess.accessBaseWithScopes - var isCompatibleAccess = true - for nestedScope in accessBaseAndScopes.scopes { + if let baseAddress = accessBaseAndScopes.base.address { + gatherExtensions(valueOrAddress: baseAddress) + } + for nestedScope in accessBaseAndScopes.scopes.reversed() { switch nestedScope { case let .access(nestedBeginAccess): - innerScopes.push(.access(nestedBeginAccess)) - if nestedBeginAccess.accessKind != beginAccess.accessKind { - isCompatibleAccess = false - } + scopes.push(ExtendableScope(.access(nestedBeginAccess), beginInst: nestedBeginAccess)!) case .dependence, .base: // ignore recursive mark_dependence base for the purpose of extending scopes. This pass will extend the base // of that mark_dependence (if it is unresolved) later as a separate LifetimeDependence.Scope. break } } - guard case let .access(outerBeginAccess) = innerScopes.last else { - // beginAccess is included in accessBaseWithScopes; so at least one access was added to innerScopes. - fatalError("missing outer access") + } +} + +extension ScopeExtension { + /// Check if the dependent value depends only on function arguments and can therefore be returned to caller. If so, + /// return the list of arguments that it depends on. If this returns an empty list, then the dependent value cannot be + /// returned. + /// + /// The conditions for returning a dependent value are: + /// - The dependent value is returned from this function. + /// - All nested scopes are access scopes that are redundant with the caller's exclusive access scope. + /// - All scope owners are function arguments. + func findArgumentDependencies() -> SingleInlineArray { + let noCallerScope = SingleInlineArray() + // Check that the dependent value is returned by this function. + if !dependsOnCaller! { + return noCallerScope } - if case let .argument(arg) = accessBaseAndScopes.base { - if isCompatibleAccess && beginAccess.accessKind.isCompatible(with: arg.convention) { - let scopes = ScopeExtension(owner: outerBeginAccess.address, nestedScopes: innerScopes, dependsOnArg: arg) - return SingleInlineArray(element: scopes) + // Check that all nested scopes that it depends on can be covered by exclusive access in the caller. + for extScope in scopes { + switch extScope.scope { + case .access: + break + default: + return noCallerScope } } - /// Recurse in case of indirect yields. - let enclosingScope = LifetimeDependence.Scope(base: outerBeginAccess.address, context) - if let extensions = enclosingScope.gatherExtensions(innerScopes: innerScopes, context) { - return extensions - } - // When the owner is an address, the owner's scope is considered the availability of its access base starting at the - // position of innerScopes.last. - let scopes = ScopeExtension(owner: outerBeginAccess.address, nestedScopes: innerScopes, dependsOnArg: nil) - return SingleInlineArray(element: scopes) - } - - func gatherBorrowExtension(borrowedValue: Value, - innerScopes: SingleInlineArray, - _ context: FunctionPassContext) - -> SingleInlineArray { - - let enclosingScope = LifetimeDependence.Scope(base: borrowedValue, context) - if let extensions = enclosingScope.gatherExtensions(innerScopes: innerScopes, context) { - return extensions + // All owners must be arguments with exclusive access to depend on the caller's scope (inout_aliasable arguments do + // not have exclusivity). + var compatibleArgs = SingleInlineArray() + for owner in owners { + guard let arg = owner as? FunctionArgument else { + return noCallerScope + } + guard arg.convention.isIndirectIn || arg.convention.isInout else { + return noCallerScope + } + compatibleArgs.push(arg) } - // This is the outermost scope to be extended because gatherExtensions did not find an enclosing scope. - return SingleInlineArray(element: getOuterExtension(owner: enclosingScope.parentValue, nestedScopes: innerScopes, - context)) + return compatibleArgs } } @@ -460,121 +593,175 @@ extension ScopeExtension { return range.deinitialize() } } + + var description: String { + switch self { + case .fullRange: + return "full range" + case let .addressRange(range): + return range.description + case let .valueRange(range): + return range.description + } + } } /// Return nil if the scope's owner is valid across the function, such as a guaranteed function argument. - func computeRange(_ localReachabilityCache: LocalVariableReachabilityCache, _ context: FunctionPassContext) -> Range? - { + func computeSingleOwnerRange(owner: Value) -> Range? { if owner.type.isAddress { // Get the range of the accessBase lifetime at the point where the outermost extendable scope begins. - if let range = AddressOwnershipLiveRange.compute(for: owner, at: nestedScopes.last!.extendableBegin!.instruction, + if let range = AddressOwnershipLiveRange.compute(for: owner, at: scopes.first!.firstInstruction, localReachabilityCache, context) { return .addressRange(range) } return nil } - if owner.ownership == .owned { + switch owner.ownership { + case .owned: return .valueRange(computeLinearLiveness(for: owner, context)) + case .guaranteed: + if let bbv = BeginBorrowValue(owner) { + if case .functionArgument = bbv { + return .fullRange + } + return .valueRange(computeLinearLiveness(for: bbv.value, context)) + } + return nil + case .none: + return .fullRange + case .unowned: + return nil } - // Trivial or guaranted owner. - // - // TODO: limit extension to the begin_borrow [var_decl] scope - return .fullRange } -} -/// Return an InstructionRange covering all the dependent uses of 'dependence'. -private func computeDependentUseRange(of dependence: LifetimeDependence, within scopeExtension: inout ScopeExtension, - _ localReachabilityCache: LocalVariableReachabilityCache, - _ context: FunctionPassContext) - -> InstructionRange? { - let function = dependence.function - guard var ownershipRange = scopeExtension.computeRange(localReachabilityCache, context) else { - return nil - } - defer {ownershipRange.deinitialize()} - - // The innermost scope that must be extended must dominate all uses. - var useRange = InstructionRange(begin: scopeExtension.innerScope.extendableBegin!.instruction, context) - var walker = LifetimeDependentUseWalker(function, localReachabilityCache, context) { - // Do not extend the useRange past the ownershipRange. - let dependentInst = $0.instruction - if ownershipRange.coversUse(dependentInst) { - useRange.insert(dependentInst) + /// Return an InstructionRange covering all the dependent uses of 'dependence'. + /// + /// Initialize dependsOnCaller. + mutating func computeDependentUseRange(of dependence: LifetimeDependence) -> InstructionRange? { + if scopes.isEmpty { + return nil } - return .continueWalk - } - defer {walker.deinitialize()} - - _ = walker.walkDown(dependence: dependence) - - log("Scope fixup for dependent uses:\n\(useRange)") - - scopeExtension.dependsOnCaller = walker.dependsOnCaller + let function = dependence.function + var inRangeUses = [Instruction]() + do { + // The innermost scope that must be extended must dominate all uses. + var walker = LifetimeDependentUseWalker(function, localReachabilityCache, context) { + inRangeUses.append($0.instruction) + return .continueWalk + } + defer {walker.deinitialize()} + // walkDown may abort if any utility used by address use walker, such asLocalVarUtils, has unhandled cases. + if walker.walkDown(dependence: dependence) == .abortWalk { + return nil + } + dependsOnCaller = walker.dependsOnCaller + } + for owner in owners { + guard var ownershipRange = computeSingleOwnerRange(owner: owner) else { + return nil + } + defer { ownershipRange.deinitialize() } - // Lifetime dependenent uses may not be dominated by the access. The dependent value may be used by a phi or stored - // into a memory location. The access may be conditional relative to such uses. If any use was not dominated, then - // `useRange` will include the function entry. There is not way to directly check - // useRange.isValid. useRange.blockRange.isValid is not a strong enough check because it will always succeed when - // useRange.begin == entryBlock even if a use if above useRange.begin. - let firstInst = function.entryBlock.instructions.first! - if firstInst != useRange.begin, useRange.contains(firstInst) { - useRange.deinitialize() - return nil + inRangeUses = inRangeUses.filter { ownershipRange.coversUse($0) } + } + var useRange = InstructionRange(begin: innermostScope.firstInstruction, context) + useRange.insert(contentsOf: inRangeUses) + + log("Scope fixup for dependent uses:\n\(useRange)") + + // Lifetime dependenent uses may not be dominated by `innermostScope`. The dependent value may be used by a phi or + // stored into a memory location. The access may be conditional relative to such uses. If any use was not dominated, + // then `useRange` will include the function entry. There is no way to directly check if `useRange` is + // valid. `useRange.blockRange.isValid` is not a strong enough check because it will always succeed when + // `useRange.begin == entryBlock` even if a use is above `useRange.begin`. Instead check if `useRange` contains the + // first instruction, and the first instruction does not itself start `innermostScope`. + let firstInst = function.entryBlock.instructions.first! + if firstInst != useRange.begin, useRange.contains(firstInst) { + useRange.deinitialize() + return nil + } + return useRange } - return useRange } -// Extend nested scopes across a use-range within their owner's range. extension ScopeExtension { - // Prepare to extend each scope. - func tryExtendScopes(over useRange: inout InstructionRange, _ context: some MutatingContext) -> Bool { + /// Return true if all nested scopes were extended across `useRange`. `useRange` has already been pruned to be a + /// subset of the ranges of the owners. + /// + /// Note: the scopes may not be strictly nested. Two adjacent scopes in the nested scopes array may have begin at the + /// same nesting level. Their begin instructions may occur in any order relative to the nested scopes array, but we + /// order the end instructions according to the arbitrary order that the scopes were inserted in the array. This is + /// conservative and could extend some scopes longer than strictly necessary. To improve this, `scopes` must be + /// represnted as a DAG by recording parent and child indices. + func canExtendScopes(over useRange: inout InstructionRange, + scopesToExtend: inout SingleInlineArray) -> Bool { var extendedUseRange = InstructionRange(begin: useRange.begin!, ends: useRange.ends, context) - // Insert the first instruction of the exit blocks to mimic 'useRange'. This is innacurate, but it produces the same - // result for canExtend() check below, which only checks reachability of end_apply. + + // Insert the first instruction of the exit blocks to mimic `useRange`. There is no way to directly copy + // `useRange`. Inserting the exit block instructions is innacurate, but for the purpose of canExtend() below, it has + // the same effect as a copy of `useRange`. extendedUseRange.insert(contentsOf: useRange.exits) - for innerScope in nestedScopes { - guard let beginInst = innerScope.extendableBegin else { - fatalError("all nested scopes must have a scoped begin instruction") - } - // Extend 'extendedUseRange' to to cover this scope's end instructions. The extended scope must at least cover the - // original scope because the original scope may protect other operations. - extendedUseRange.insert(contentsOf: beginInst.endInstructions) - if !innerScope.canExtend(over: &extendedUseRange, context) { + defer { extendedUseRange.deinitialize() } + + // Append each scope that needs extention to scopesToExtend from the inner to the outer scope. + for extScope in scopes.reversed() { + // An outer scope might not originally cover one of its inner scopes. Therefore, extend 'extendedUseRange' to to + // cover this scope's end instructions. The extended scope must at least cover the original scopes because the + // original scopes may protect other operations. + var mustExtend = false + for scopeEndInst in extScope.endInstructions { + switch extendedUseRange.overlaps(pathBegin: extScope.firstInstruction, pathEnd: scopeEndInst, context) { + case .containsPath, .containsEnd, .disjoint: + // containsPath can occur when the extendable scope has the same begin as the use range. + // disjoint is unexpected, but if it occurs then `extScope` must be before the useRange. + mustExtend = true + break + case .containsBegin, .overlappedByPath: + // containsBegin can occur when the extendable scope has the same begin as the use range. + extendedUseRange.insert(scopeEndInst) + break + } + } + if !mustExtend { + continue + } + scopesToExtend.push(extScope) + if !extScope.canExtend(over: &extendedUseRange, context) { // Scope ending instructions cannot be inserted at the 'range' boundary. Ignore all nested scopes. // - // Note: We could still extend previously prepared inner scopes up to this 'innerScope'. To do that, we would - // need to repeat the steps above: treat 'innerScope' as the new owner, and recompute 'useRange'. But this + // Note: We could still extend previously prepared inner scopes up to this scope. To do that, we would + // need to repeat the steps above: treat 'extScope' as the new owner, and recompute `useRange`. But this // scenario could only happen with nested coroutine, where the range boundary is reachable from the outer // coroutine's EndApply and AbortApply--it is vanishingly unlikely if not impossible. return false } } - extendedUseRange.deinitialize() - // extend(over:) must receive the original unmodified 'useRange'. - extend(over: &useRange, context) return true } // Extend the scopes that actually required extension. // // Consumes 'useRange' - private func extend(over useRange: inout InstructionRange, _ context: some MutatingContext) { + private func extend(scopesToExtend: SingleInlineArray, + over useRange: inout InstructionRange, + _ context: some MutatingContext) { var deadInsts = [Instruction]() - for innerScope in nestedScopes { - guard let beginInst = innerScope.extendableBegin else { - fatalError("all nested scopes must have a scoped begin instruction") - } - let mustExtend = beginInst.endInstructions.contains(where: { useRange.contains($0) }) - + for extScope in scopesToExtend { // Extend 'useRange' to to cover this scope's end instructions. 'useRange' cannot be extended until the // inner scopes have been extended. - for endInst in beginInst.endInstructions { - useRange.insert(endInst) - } - if mustExtend { - deadInsts += innerScope.extend(over: &useRange, context) - } + useRange.insert(contentsOf: extScope.endInstructions) + + // Note, we could Skip extension here if we have a fully overlapping scope. But that requires computing the scope + // of [beginInst : beginInst.endInstructions) because an outer scope may be disjoint from the inner scope but + // still requires extension: + // %access = begin_access [read] %owner // <=== outer scoope + // %temp = load [copy] %access + // end_access %access + // (%dependent, %token) = begin_apply (%temp) // <=== inner scope + // end_apply %token + // + deadInsts += extScope.extend(over: &useRange, context) + // Continue checking enclosing scopes for extension even if 'mustExtend' is false. Multiple ScopeExtensions may // share the same inner scope, so this inner scope may already have been extended while handling a previous // ScopeExtension. Nonetheless, some enclosing scopes may still require extension. This only happens when a @@ -582,6 +769,7 @@ extension ScopeExtension { } // 'useRange' is invalid as soon as instructions are deleted. useRange.deinitialize() + // Delete original end instructions. for deadInst in deadInsts { context.erase(instruction: deadInst) @@ -590,28 +778,20 @@ extension ScopeExtension { } // Extend a dependence scope to cover the dependent uses. -private extension LifetimeDependence.Scope { +extension ExtendableScope { /// Return true if new scope-ending instruction can be inserted at the range boundary. func canExtend(over range: inout InstructionRange, _ context: some Context) -> Bool { - switch self { + switch self.scope { case let .yield(yieldedValue): - let beginApply = yieldedValue.definingInstruction as! BeginApplyInst - let canEndAtBoundary = { (boundaryInst: Instruction) in - switch beginApply.endReaches(block: boundaryInst.parentBlock, context) { - case .abortReaches, .endReaches: - return true - case .none: - return false - } - } - for end in range.ends { - if (!canEndAtBoundary(end)) { - return false - } - } - for exit in range.exits { - if (!canEndAtBoundary(exit)) { - return false + return canExtend(beginApply: yieldedValue.definingInstruction as! BeginApplyInst, over: &range, context) + case let .initialized(initializer): + switch initializer { + case .argument, .yield: + // A yield is already considered nested within the coroutine. + break + case let .store(initializingStore, _): + if let sb = initializingStore as? StoreBorrowInst { + return canExtend(storeBorrow: sb, over: &range) } } return true @@ -621,33 +801,70 @@ private extension LifetimeDependence.Scope { } } + func canExtend(beginApply: BeginApplyInst, over range: inout InstructionRange, _ context: some Context) -> Bool { + let canEndAtBoundary = { (boundaryInst: Instruction) in + switch beginApply.endReaches(block: boundaryInst.parentBlock, context) { + case .abortReaches, .endReaches, .deadEndReaches: + return true + case .none: + return false + } + } + for end in range.ends { + if (!canEndAtBoundary(end)) { + return false + } + } + for exit in range.exits { + if (!canEndAtBoundary(exit)) { + return false + } + } + return true + } + + /// A store borrow is considered to be nested within the scope of its stored values. It is, however, also + /// restricted to the range of its allocation. + /// + /// TODO: consider rewriting the dealloc_stack instructions if we ever find that SILGen emits them sooner that + /// we need for lifetime dependencies. + func canExtend(storeBorrow: StoreBorrowInst, over range: inout InstructionRange) -> Bool { + // store_borrow can be extended if all deallocations occur after the use range. + return storeBorrow.allocStack.deallocations.allSatisfy({ !range.contains($0) }) + } + /// Extend this scope over the 'range' boundary. Return the old scope ending instructions to be deleted. func extend(over range: inout InstructionRange, _ context: some MutatingContext) -> [Instruction] { - guard let beginInst = extendableBegin else { - fatalError("all nested scoped must have a scoped begin instruction") - } // Collect the original end instructions and extend the range to to cover them. The resulting access scope // must cover the original scope because it may protect other memory operations. - var endInsts = [Instruction]() - for end in beginInst.endInstructions { + let endsToErase = self.endInstructions + var unusedEnds = InstructionSet(context) + for end in endsToErase { assert(range.inclusiveRangeContains(end)) - endInsts.append(end) + unusedEnds.insert(end) } - insertBoundaryEnds(range: &range, context) - return endInsts - } - - /// Create new scope-ending instructions at the boundary of 'range'. - func insertBoundaryEnds(range: inout InstructionRange, _ context: some MutatingContext) { + defer { unusedEnds.deinitialize() } for end in range.ends { let location = end.location.autoGenerated - if end is ReturnInst { + switch end { + case is BranchInst: + assert(end.parentBlock.singleSuccessor!.terminator is ReturnInst, + "a phi only ends a use range if it is a returned value") + fallthrough + case is ReturnInst: // End this inner scope just before the return. The mark_dependence base operand will be redirected to a // function argument. let builder = Builder(before: end, location: location, context) // Insert newEnd so that this scope will be nested in any outer scopes. range.insert(createEndInstruction(builder, context)) continue + default: + break + } + if unusedEnds.contains(end) { + unusedEnds.erase(end) + assert(!unusedEnds.contains(end)) + continue } Builder.insert(after: end, location: location, context) { range.insert(createEndInstruction($0, context)) @@ -658,11 +875,12 @@ private extension LifetimeDependence.Scope { let builder = Builder(before: exitInst, location: location, context) range.insert(createEndInstruction(builder, context)) } + return endsToErase.filter { unusedEnds.contains($0) } } /// Create a scope-ending instruction at 'builder's insertion point. func createEndInstruction(_ builder: Builder, _ context: some Context) -> Instruction { - switch self { + switch self.scope { case let .access(beginAccess): return builder.createEndAccess(beginAccess: beginAccess) case let .borrowed(beginBorrow): @@ -675,6 +893,7 @@ private extension LifetimeDependence.Scope { switch initializer { case let .store(initializingStore: store, initialAddress: _): if let sb = store as? StoreBorrowInst { + // FIXME: we may need to rewrite the dealloc_stack. return builder.createEndBorrow(of: sb) } break @@ -682,6 +901,16 @@ private extension LifetimeDependence.Scope { // TODO: extend indirectly yielded scopes. break } + case let .owned(value): + return builder.createDestroyValue(operand: value) + case let .local(varInst): + switch varInst { + case let .beginBorrow(beginBorrow): + // FIXME: we may need to rewrite the dealloc_stack. + return builder.createEndBorrow(of: beginBorrow) + case let .moveValue(moveValue): + return builder.createDestroyValue(operand: moveValue) + } default: break } @@ -703,64 +932,62 @@ private extension BeginApplyInst { return builder.createEndApply(beginApply: self) case .abortReaches: return builder.createAbortApply(beginApply: self) + case .deadEndReaches: + return builder.createEndBorrow(of: self.token) } } enum EndReaches { case endReaches case abortReaches + case deadEndReaches } /// Return the single kind of coroutine termination that reaches 'reachableBlock' or nil. func endReaches(block reachableBlock: BasicBlock, _ context: some Context) -> EndReaches? { - var endBlocks = BasicBlockSet(context) - var abortBlocks = BasicBlockSet(context) + // TODO: use InlineArray<3> once bootstrapping is fixed. + var endingBlockMap: [(EndReaches, BasicBlockSet)] = [ + (.endReaches, BasicBlockSet(context)), + (.abortReaches, BasicBlockSet(context)), + (.deadEndReaches, BasicBlockSet(context)) + ] defer { - endBlocks.deinitialize() - abortBlocks.deinitialize() + for index in endingBlockMap.indices { + endingBlockMap[index].1.deinitialize() + } } for endInst in endInstructions { + let endKind: EndReaches switch endInst { case let endApply as EndApplyInst: // Cannot extend the scope of a coroutine when the resume produces a value. if !endApply.type.isEmpty(in: parentFunction) { return nil } - endBlocks.insert(endInst.parentBlock) + endKind = .endReaches case is AbortApplyInst: - abortBlocks.insert(endInst.parentBlock) + endKind = .abortReaches + case is EndBorrowInst: + endKind = .deadEndReaches default: fatalError("invalid begin_apply ending instruction") } + let endingBlocksIndex = endingBlockMap.firstIndex(where: { $0.0 == endKind })! + endingBlockMap[endingBlocksIndex].1.insert(endInst.parentBlock) } var endReaches: EndReaches? var backwardWalk = BasicBlockWorklist(context) defer { backwardWalk.deinitialize() } let backwardVisit = { (block: BasicBlock) -> WalkResult in - if endBlocks.contains(block) { - switch endReaches { - case .none: - endReaches = .endReaches - break - case .endReaches: - break - case .abortReaches: - return .abortWalk + for (endKind, endingBlocks) in endingBlockMap { + if endingBlocks.contains(block) { + if let endReaches = endReaches, endReaches != endKind { + return .abortWalk + } + endReaches = endKind + return .continueWalk } - return .continueWalk - } - if abortBlocks.contains(block) { - switch endReaches { - case .none: - endReaches = .abortReaches - break - case .abortReaches: - break - case .endReaches: - return .abortWalk - } - return .continueWalk } if block == self.parentBlock { // the insertion point is not dominated by the coroutine @@ -850,7 +1077,7 @@ private struct LifetimeDependentUseWalker : LifetimeDependenceDefUseWalker { } mutating func yieldedDependence(result: Operand) -> WalkResult { - return .continueWalk + return visitor(result) } mutating func storeToYieldDependence(address: Value, of operand: Operand) -> WalkResult { diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/RedundantLoadElimination.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/RedundantLoadElimination.swift index 902543bbe7830..8f4447ddd81df 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/RedundantLoadElimination.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/RedundantLoadElimination.swift @@ -12,7 +12,7 @@ import SIL -/// Replaces redundant load instructions with already available values. +/// Replaces redundant `load` or `copy_addr` instructions with already available values. /// /// A load is redundant if the loaded value is already available at that point. /// This can be via a preceding store to the same address: @@ -52,6 +52,9 @@ import SIL /// %f2 = load %fa2 /// %2 = struct (%f1, %f2) /// +/// This works in a similar fashion for `copy_addr`. If the source value of the `copy_addr` is +/// already available, the `copy_addr` is replaced by a `store` of the available value. +/// /// The algorithm is a data flow analysis which starts at the original load and searches /// for preceding stores or loads by following the control flow in backward direction. /// The preceding stores and loads provide the "available values" with which the original @@ -99,7 +102,7 @@ func eliminateRedundantLoads(in function: Function, while let i = inst { defer { inst = i.previous } - if let load = inst as? LoadInst { + if let load = inst as? LoadingInstruction { if !context.continueWithNextSubpassRun(for: load) { return changed } @@ -116,7 +119,59 @@ func eliminateRedundantLoads(in function: Function, return changed } -private func tryEliminate(load: LoadInst, complexityBudget: inout Int, _ context: FunctionPassContext) -> Bool { +/// Either a `load` or a `copy_addr` (which is equivalent to a load+store). +private protocol LoadingInstruction: Instruction { + var address: Value { get } + var type: Type { get } + var ownership: Ownership { get } + var loadOwnership: LoadInst.LoadOwnership { get } + var canLoadValue: Bool { get } + func trySplit(_ context: FunctionPassContext) -> Bool + func materializeLoadForReplacement(_ context: FunctionPassContext) -> LoadInst +} + +extension LoadInst : LoadingInstruction { + // We know that the type is loadable because - well - this is a load. + var canLoadValue: Bool { true } + + // Nothing to materialize, because this is already a `load`. + func materializeLoadForReplacement(_ context: FunctionPassContext) -> LoadInst { return self } +} + +extension CopyAddrInst : LoadingInstruction { + var address: Value { source } + var type: Type { address.type.objectType } + var typeIsLoadable: Bool { type.isLoadable(in: parentFunction) } + + var ownership: Ownership { + if !parentFunction.hasOwnership || type.isTrivial(in: parentFunction) { + return .none + } + // Regardless of if the copy is taking or copying, the loaded value is an owned value. + return .owned + } + + var canLoadValue: Bool { + if !source.type.isLoadable(in: parentFunction) { + // Although the original load's type is loadable (obviously), it can be projected-out + // from the copy_addr's type which might be not loadable. + return false + } + if !parentFunction.hasOwnership { + if !isTakeOfSrc || !isInitializationOfDest { + // For simplicity, bail if we would have to insert compensating retains and releases. + return false + } + } + return true + } + + func materializeLoadForReplacement(_ context: FunctionPassContext) -> LoadInst { + return replaceWithLoadAndStore(context).load + } +} + +private func tryEliminate(load: LoadingInstruction, complexityBudget: inout Int, _ context: FunctionPassContext) -> Bool { switch load.isRedundant(complexityBudget: &complexityBudget, context) { case .notRedundant: return false @@ -136,9 +191,12 @@ private func tryEliminate(load: LoadInst, complexityBudget: inout Int, _ context } } -private extension LoadInst { +private extension LoadingInstruction { func isEligibleForElimination(in variant: RedundantLoadEliminationVariant, _ context: FunctionPassContext) -> Bool { + if !canLoadValue { + return false + } switch variant { case .mandatory, .mandatoryInGlobalInit: if loadOwnership == .take { @@ -171,20 +229,6 @@ private extension LoadInst { return true } - enum DataflowResult { - case notRedundant - case redundant([AvailableValue]) - case maybePartiallyRedundant(AccessPath) - - init(notRedundantWith subPath: AccessPath?) { - if let subPath = subPath { - self = .maybePartiallyRedundant(subPath) - } else { - self = .notRedundant - } - } - } - func isRedundant(complexityBudget: inout Int, _ context: FunctionPassContext) -> DataflowResult { return isRedundant(at: address.constantAccessPath, complexityBudget: &complexityBudget, context) } @@ -285,7 +329,7 @@ private extension LoadInst { } } -private func replace(load: LoadInst, with availableValues: [AvailableValue], _ context: FunctionPassContext) { +private func replace(load: LoadingInstruction, with availableValues: [AvailableValue], _ context: FunctionPassContext) { var ssaUpdater = SSAUpdater(function: load.parentFunction, type: load.type, ownership: load.ownership, context) @@ -318,14 +362,16 @@ private func replace(load: LoadInst, with availableValues: [AvailableValue], _ c newValue = ssaUpdater.getValue(inMiddleOf: load.parentBlock) } + let originalLoad = load.materializeLoadForReplacement(context) + // Make sure to keep dependencies valid after replacing the load - insertMarkDependencies(for: load, context) + insertMarkDependencies(for: originalLoad, context) - load.replace(with: newValue, context) + originalLoad.replace(with: newValue, context) } private func provideValue( - for load: LoadInst, + for load: LoadingInstruction, from availableValue: AvailableValue, _ context: FunctionPassContext ) -> Value { @@ -341,9 +387,9 @@ private func provideValue( builder: availableValue.getBuilderForProjections(context)) case .take: if projectionPath.isEmpty { - return shrinkMemoryLifetime(from: load, to: availableValue, context) + return shrinkMemoryLifetime(to: availableValue, context) } else { - return shrinkMemoryLifetimeAndSplit(from: load, to: availableValue, projectionPath: projectionPath, context) + return shrinkMemoryLifetimeAndSplit(to: availableValue, projectionPath: projectionPath, context) } } } @@ -366,7 +412,7 @@ private func insertMarkDependencies(for load: LoadInst, _ context: FunctionPassC private struct MarkDependenceInserter : AddressUseDefWalker { let load: LoadInst let context: FunctionPassContext - + mutating func walkUp(address: Value, path: UnusedWalkingPath) -> WalkResult { if let mdi = address as? MarkDependenceInst { let builder = Builder(after: load, context) @@ -375,7 +421,7 @@ private struct MarkDependenceInserter : AddressUseDefWalker { } return walkUpDefault(address: address, path: path) } - + mutating func rootDef(address: Value, path: UnusedWalkingPath) -> WalkResult { return .continueWalk } @@ -392,7 +438,7 @@ private struct MarkDependenceInserter : AddressUseDefWalker { /// ... /// // replace %2 with %1 /// -private func shrinkMemoryLifetime(from load: LoadInst, to availableValue: AvailableValue, _ context: FunctionPassContext) -> Value { +private func shrinkMemoryLifetime(to availableValue: AvailableValue, _ context: FunctionPassContext) -> Value { switch availableValue { case .viaLoad(let availableLoad): assert(availableLoad.loadOwnership == .copy) @@ -442,7 +488,7 @@ private func shrinkMemoryLifetime(from load: LoadInst, to availableValue: Availa /// ... /// // replace %3 with %1 /// -private func shrinkMemoryLifetimeAndSplit(from load: LoadInst, to availableValue: AvailableValue, projectionPath: SmallProjectionPath, _ context: FunctionPassContext) -> Value { +private func shrinkMemoryLifetimeAndSplit(to availableValue: AvailableValue, projectionPath: SmallProjectionPath, _ context: FunctionPassContext) -> Value { switch availableValue { case .viaLoad(let availableLoad): assert(availableLoad.loadOwnership == .copy) @@ -462,6 +508,20 @@ private func shrinkMemoryLifetimeAndSplit(from load: LoadInst, to availableValue } } +private enum DataflowResult { + case notRedundant + case redundant([AvailableValue]) + case maybePartiallyRedundant(AccessPath) + + init(notRedundantWith subPath: AccessPath?) { + if let subPath = subPath { + self = .maybePartiallyRedundant(subPath) + } else { + self = .notRedundant + } + } +} + /// Either a `load` or `store` which is preceding the original load and provides the loaded value. private enum AvailableValue { case viaLoad(LoadInst) @@ -505,7 +565,7 @@ private extension Array where Element == AvailableValue { func replaceCopyAddrsWithLoadsAndStores(_ context: FunctionPassContext) -> [AvailableValue] { return map { if case .viaCopyAddr(let copyAddr) = $0 { - return .viaStore(copyAddr.replaceWithLoadAndStore(context)) + return .viaStore(copyAddr.replaceWithLoadAndStore(context).store) } else { return $0 } @@ -514,7 +574,7 @@ private extension Array where Element == AvailableValue { } private struct InstructionScanner { - private let load: LoadInst + private let load: LoadingInstruction private let accessPath: AccessPath private let storageDefBlock: BasicBlock? private let aliasAnalysis: AliasAnalysis @@ -522,7 +582,7 @@ private struct InstructionScanner { private(set) var potentiallyRedundantSubpath: AccessPath? = nil private(set) var availableValues = Array() - init(load: LoadInst, accessPath: AccessPath, _ aliasAnalysis: AliasAnalysis) { + init(load: LoadingInstruction, accessPath: AccessPath, _ aliasAnalysis: AliasAnalysis) { self.load = load self.accessPath = accessPath self.storageDefBlock = accessPath.base.reference?.referenceRoot.parentBlock @@ -616,7 +676,7 @@ private struct InstructionScanner { potentiallyRedundantSubpath = precedingStorePath } - case let preceedingCopy as CopyAddrInst where preceedingCopy.canProvideValue: + case let preceedingCopy as CopyAddrInst where preceedingCopy.canLoadValue: let copyPath = preceedingCopy.destination.constantAccessPath if copyPath.getMaterializableProjection(to: accessPath) != nil { availableValues.append(.viaCopyAddr(preceedingCopy)) @@ -712,20 +772,3 @@ private struct Liverange { return false } } - -private extension CopyAddrInst { - var canProvideValue: Bool { - if !source.type.isLoadable(in: parentFunction) { - // Although the original load's type is loadable (obviously), it can be projected-out - // from the copy_addr's type which might be not loadable. - return false - } - if !parentFunction.hasOwnership { - if !isTakeOfSrc || !isInitializationOfDest { - // For simplicity, bail if we would have to insert compensating retains and releases. - return false - } - } - return true - } -} diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt index 1cb0130076f90..043a62589f37c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt @@ -19,6 +19,7 @@ swift_compiler_sources(Optimizer SimplifyCondBranch.swift SimplifyCondFail.swift SimplifyConvertEscapeToNoEscape.swift + SimplifyCopyBlock.swift SimplifyCopyValue.swift SimplifyDebugStep.swift SimplifyDestroyValue.swift diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift index 85c6d297e6671..5fe28a090ea18 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyAllocStack.swift @@ -257,11 +257,15 @@ private extension AllocStackInst { case is CheckedCastAddrBranchInst, is UnconditionalCheckedCastAddrInst: // To construct a new cast instruction we need a formal type. requiresLegalFormalType = true - fallthrough - case is UncheckedAddrCastInst: if use != use.instruction.operands[0] { return nil } + case is UncheckedAddrCastInst: + if self.type.isExistential { + // Bail if the address of the original existential escapes. + // This is not a problem if the alloc_stack already contains the opened existential. + return nil + } default: return nil } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCheckedCast.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCheckedCast.swift index fe922951bdac0..b7f45bf361351 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCheckedCast.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCheckedCast.swift @@ -81,7 +81,9 @@ private extension UnconditionalCheckedCastInst { return } let conformance = sourceFormalType.instanceTypeOfMetatype.checkConformance(to: proto) - guard conformance.isValid else { + guard conformance.isValid, + conformance.matchesActorIsolation(in: parentFunction) + else { return } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCopyBlock.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCopyBlock.swift new file mode 100644 index 0000000000000..17082802309dd --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyCopyBlock.swift @@ -0,0 +1,112 @@ +//===--- SimplifyCopyBlock.swift ------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SIL + +extension CopyBlockInst : Simplifiable, SILCombineSimplifiable { + + /// Removes a `copy_block` if its only uses, beside ownership instructions, are callees of function calls + /// ``` + /// %2 = copy_block %0 + /// %3 = begin_borrow [lexical] %2 + /// %4 = apply %3() : $@convention(block) @noescape () -> () + /// end_borrow %3 + /// destroy_value %2 + /// ``` + /// -> + /// ``` + /// %4 = apply %0() : $@convention(block) @noescape () -> () + /// ``` + /// + func simplify(_ context: SimplifyContext) { + // Temporarily guarded with an experimental feature flag. + if !context.options.hasFeature(.CopyBlockOptimization) { + return + } + + if hasValidUses(block: self) { + replaceBlock(self, with: operand.value, context) + context.erase(instruction: self) + } + } +} + +private func hasValidUses(block: Value) -> Bool { + for use in block.uses { + switch use.instruction { + case let beginBorrow as BeginBorrowInst: + if !hasValidUses(block: beginBorrow) { + return false + } + case let apply as FullApplySite where apply.isCallee(operand: use): + break + case let partialApply as PartialApplyInst: + // If the block is passed to another function - either as closure argument or as closure capture - + // it's "converted" to a swift closure with the help of a thunk. The thunk just calls the block. + // If this is a non-escaping partial_apply and it's such a thunk, the block does not escape. + if partialApply.canClosureArgumentEscape(closure: use) { + return false + } + case is EndBorrowInst, is DestroyValueInst: + break + default: + return false + } + } + return true +} + +private func replaceBlock(_ block: Value, with original: Value, _ context: SimplifyContext) { + for use in block.uses { + switch use.instruction { + case let beginBorrow as BeginBorrowInst: + replaceBlock(beginBorrow, with: original, context) + context.erase(instruction: beginBorrow) + case is FullApplySite: + use.set(to: original, context) + case let partialApply as PartialApplyInst: + if original.ownership == .unowned { + let builder = Builder(before: partialApply, context) + let conv = builder.createUncheckedOwnershipConversion(operand: original, resultOwnership: .guaranteed) + use.set(to: conv, context) + } else { + use.set(to: original, context) + } + case is EndBorrowInst, is DestroyValueInst: + context.erase(instruction: use.instruction) + default: + fatalError("unhandled use") + } + } +} + +private extension PartialApplyInst { + func canClosureArgumentEscape(closure: Operand) -> Bool { + guard isOnStack, + let callee = referencedFunction, + callee.isDefinition, + let argIdx = calleeArgumentIndex(of: closure), + // If the callee only _calls_ the closure argument, it does not escape. + callee.arguments[argIdx].uses.allSatisfy(isCalleeOperandOfApply) + else { + return true + } + return false + } +} + +private func isCalleeOperandOfApply(_ operand: Operand) -> Bool { + if let apply = operand.instruction as? FullApplySite, apply.isCallee(operand: operand) { + return true + } + return false +} diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift index ca4d1012b97fe..0e5adb657488c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift @@ -44,6 +44,12 @@ let mandatoryPerformanceOptimizations = ModulePass(name: "mandatory-performance- // Print errors for generic functions in vtables, which is not allowed in embedded Swift. checkVTablesForGenericFunctions(moduleContext) } + + // It's not required to set the perf_constraint flag on all functions in embedded mode. + // Embedded mode already implies that flag. + if !moduleContext.options.enableEmbeddedSwift { + setPerformanceConstraintFlags(moduleContext) + } } private func optimizeFunctionsTopDown(using worklist: inout FunctionWorklist, @@ -53,13 +59,6 @@ private func optimizeFunctionsTopDown(using worklist: inout FunctionWorklist, if !context.loadFunction(function: f, loadCalleesRecursively: true) { return } - - // It's not required to set the perf_constraint flag on all functions in embedded mode. - // Embedded mode already implies that flag. - if !moduleContext.options.enableEmbeddedSwift { - f.set(isPerformanceConstraint: true, context) - } - optimize(function: f, context, moduleContext, &worklist) } @@ -68,7 +67,18 @@ private func optimizeFunctionsTopDown(using worklist: inout FunctionWorklist, // We need handle this case with a function signature optimization. removeMetatypeArgumentsInCallees(of: f, moduleContext) - worklist.addCallees(of: f) + worklist.addCallees(of: f, moduleContext) + } +} + +private func setPerformanceConstraintFlags(_ moduleContext: ModulePassContext) { + var worklist = FunctionWorklist() + for f in moduleContext.functions where f.performanceConstraints != .none && f.isDefinition { + worklist.pushIfNotVisited(f) + } + while let f = worklist.pop() { + moduleContext.transform(function: f) { f.set(isPerformanceConstraint: true, $0) } + worklist.addCallees(of: f, moduleContext) } } @@ -112,7 +122,8 @@ private func optimize(function: Function, _ context: FunctionPassContext, _ modu } } case let metatype as MetatypeInst: - if context.options.enableEmbeddedSwift { + if context.options.enableEmbeddedSwift, + metatype.type.representationOfMetatype == .thick { let instanceType = metatype.type.loweredInstanceTypeOfMetatype(in: function) if instanceType.isClass { specializeVTable(forClassType: instanceType, errorLocation: metatype.location, moduleContext) { @@ -137,11 +148,17 @@ private func optimize(function: Function, _ context: FunctionPassContext, _ modu // We need to de-virtualize deinits of non-copyable types to be able to specialize the deinitializers. case let destroyValue as DestroyValueInst: if !devirtualizeDeinits(of: destroyValue, simplifyCtxt) { - context.diagnosticEngine.diagnose(destroyValue.location.sourceLoc, .deinit_not_visible) + // If invoked from SourceKit avoid reporting false positives when WMO is turned off for indexing purposes. + if moduleContext.enableWMORequiredDiagnostics { + context.diagnosticEngine.diagnose(destroyValue.location.sourceLoc, .deinit_not_visible) + } } case let destroyAddr as DestroyAddrInst: if !devirtualizeDeinits(of: destroyAddr, simplifyCtxt) { - context.diagnosticEngine.diagnose(destroyAddr.location.sourceLoc, .deinit_not_visible) + // If invoked from SourceKit avoid reporting false positives when WMO is turned off for indexing purposes. + if moduleContext.enableWMORequiredDiagnostics { + context.diagnosticEngine.diagnose(destroyAddr.location.sourceLoc, .deinit_not_visible) + } } case let iem as InitExistentialMetatypeInst: @@ -515,9 +532,15 @@ fileprivate struct FunctionWorklist { return } - mutating func addCallees(of function: Function) { + mutating func addCallees(of function: Function, _ context: ModulePassContext) { for inst in function.instructions { switch inst { + case let fri as FunctionRefInst: + // In embedded swift all reachable functions must be handled - even if they are not called, + // e.g. referenced by a global. + if context.options.enableEmbeddedSwift { + pushIfNotVisited(fri.referencedFunction) + } case let apply as ApplySite: if let callee = apply.referencedFunction { pushIfNotVisited(callee) @@ -528,16 +551,39 @@ fileprivate struct FunctionWorklist { if let fri = bi.operands[1].value as? FunctionRefInst { pushIfNotVisited(fri.referencedFunction) } - break; default: break } + case let alloc as AllocRefInst: + if context.options.enableEmbeddedSwift { + addVTableMethods(forClassType: alloc.type, context) + } + case let metatype as MetatypeInst: + if context.options.enableEmbeddedSwift { + let instanceType = metatype.type.loweredInstanceTypeOfMetatype(in: function) + if instanceType.isClass { + addVTableMethods(forClassType: instanceType, context) + } + } + default: break } } } + mutating func addVTableMethods(forClassType classType: Type, _ context: ModulePassContext) { + guard let vtable = classType.isGenericAtAnyLevel ? + context.lookupSpecializedVTable(for: classType) : + context.lookupVTable(for: classType.nominal!) + else { + return + } + for entry in vtable.entries where !entry.implementation.isGeneric { + pushIfNotVisited(entry.implementation) + } + } + mutating func addWitnessMethods(of witnessTable: WitnessTable) { for entry in witnessTable.entries { if case .method(_, let witness) = entry, diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift index 6803362b43395..7f9d467adb4f8 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift @@ -324,6 +324,10 @@ struct FunctionPassContext : MutatingContext { _bridged.getSwiftArrayDecl().getAs(NominalTypeDecl.self) } + var swiftMutableSpan: NominalTypeDecl { + _bridged.getSwiftMutableSpanDecl().getAs(NominalTypeDecl.self) + } + func loadFunction(name: StaticString, loadCalleesRecursively: Bool) -> Function? { return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer) in let nameStr = BridgedStringRef(data: nameBuffer.baseAddress, count: nameBuffer.count) diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift index 48c7482a59a56..2f0967860bd38 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift @@ -114,6 +114,7 @@ private func registerSwiftPasses() { registerForSILCombine(LoadInst.self, { run(LoadInst.self, $0) }) registerForSILCombine(LoadBorrowInst.self, { run(LoadBorrowInst.self, $0) }) registerForSILCombine(CopyValueInst.self, { run(CopyValueInst.self, $0) }) + registerForSILCombine(CopyBlockInst.self, { run(CopyBlockInst.self, $0) }) registerForSILCombine(DestroyValueInst.self, { run(DestroyValueInst.self, $0) }) registerForSILCombine(DestructureStructInst.self, { run(DestructureStructInst.self, $0) }) registerForSILCombine(DestructureTupleInst.self, { run(DestructureTupleInst.self, $0) }) diff --git a/SwiftCompilerSources/Sources/Optimizer/TestPasses/MemBehaviorDumper.swift b/SwiftCompilerSources/Sources/Optimizer/TestPasses/MemBehaviorDumper.swift index d7b352454d9fa..7def70e95934d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/TestPasses/MemBehaviorDumper.swift +++ b/SwiftCompilerSources/Sources/Optimizer/TestPasses/MemBehaviorDumper.swift @@ -63,6 +63,7 @@ private extension Instruction { is BeginAccessInst, is EndAccessInst, is EndCOWMutationInst, + is EndCOWMutationAddrInst, is CopyValueInst, is DestroyValueInst, is StrongReleaseInst, diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift index 40bd631f5d0b2..60e8442b84dd7 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift @@ -131,7 +131,7 @@ extension AddressUseVisitor { is DestroyAddrInst, is DeallocStackInst, is DeinitExistentialAddrInst, is IsUniqueInst, is MarkFunctionEscapeInst, - is PackElementSetInst: + is PackElementSetInst, is EndCOWMutationAddrInst: return leafAddressUse(of: operand) case is LoadInst, is LoadUnownedInst, is LoadWeakInst, is ValueMetatypeInst, is ExistentialMetatypeInst, @@ -501,6 +501,11 @@ enum AddressOwnershipLiveRange : CustomStringConvertible { } } + /// Return the live range of the addressable value that reaches 'begin', not including 'begin', which may itself be an + /// access of the address. + /// + /// The range ends at the destroy or reassignment of the addressable value. + /// /// Return nil if the live range is unknown. static func compute(for address: Value, at begin: Instruction, _ localReachabilityCache: LocalVariableReachabilityCache, @@ -624,7 +629,7 @@ extension AddressOwnershipLiveRange { var reachableUses = Stack(context) defer { reachableUses.deinitialize() } - localReachability.gatherKnownReachableUses(from: assignment, in: &reachableUses) + localReachability.gatherKnownLifetimeUses(from: assignment, in: &reachableUses) let assignmentInst = assignment.instruction ?? allocation.parentFunction.entryBlock.instructions.first! var range = InstructionRange(begin: assignmentInst, context) @@ -643,12 +648,10 @@ extension AddressOwnershipLiveRange { let addressOwnershipLiveRangeTest = FunctionTest("address_ownership_live_range") { function, arguments, context in let address = arguments.takeValue() + let begin = arguments.takeInstruction() print("Address: \(address)") print("Base: \(address.accessBase)") - let begin = address.definingInstructionOrTerminator ?? { - assert(address is FunctionArgument) - return function.instructions.first! - }() + print("Begin: \(begin)") let localReachabilityCache = LocalVariableReachabilityCache() guard var ownershipRange = AddressOwnershipLiveRange.compute(for: address, at: begin, localReachabilityCache, context) else { diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift index 2aa2343f36aff..95d619c2e9585 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift @@ -211,6 +211,9 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { return scopedValue } + /// Returns non-nil if this borrowing instruction produces an guaranteed dependent value and does not have immediate + /// scope-ending uses. Finding the borrow scope in such cases requires recursively following uses of the guaranteed + /// value. var dependentValue: Value? { switch self { case .borrowedFrom(let bfi): @@ -425,7 +428,7 @@ enum BeginBorrowValue { var baseOperand: Operand? { switch self { case let .beginBorrow(beginBorrow): - return beginBorrow.operand + return beginBorrow.operand case let .loadBorrow(loadBorrow): return loadBorrow.operand case .beginApply, .functionArgument, .reborrow, .uncheckOwnershipConversion: diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift index 125d26fca4ab9..8651edc876dac 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/EscapeUtils.swift @@ -640,12 +640,14 @@ fileprivate struct EscapeWalker : ValueDefUseWalker, } // Indirect arguments cannot escape the function, but loaded values from such can. - if !followLoads(at: path) { - guard let beginApply = apply as? BeginApplyInst else { - return .continueWalk - } - // Except for begin_apply: it can yield an address value. - if !indirectResultEscapes(of: beginApply, path: path) { + if argOp.value.type.isAddress && !followLoads(at: path) { + if let beginApply = apply as? BeginApplyInst { + // begin_apply can yield an address value. + if !indirectResultEscapes(of: beginApply, path: path) { + return .continueWalk + } + } else if !apply.isAddressable(operand: argOp) { + // The result does not depend on the argument's address. return .continueWalk } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift index 56122160a64c8..3a0fbb7942a9d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift @@ -118,7 +118,7 @@ extension ForwardingUseDefWalker { } mutating func walkUpDefault(forwarded value: Value, _ path: PathContext) -> WalkResult { - if let inst = value.forwardingInstruction { + if let inst = value.forwardingInstruction, !inst.forwardedOperands.isEmpty { return walkUp(instruction: inst, path) } if let phi = Phi(value) { diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift index d992481da692b..41d905d8bb16b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift @@ -161,20 +161,16 @@ extension LifetimeDependence { // Construct a LifetimeDependence from a return value. This only // constructs a dependence for ~Escapable results that do not have a - // lifetime dependence (@_unsafeNonescapableResult). + // lifetime dependence (@lifetime(immortal), @_unsafeNonescapableResult). // // This is necessary because inserting a mark_dependence placeholder for such an unsafe dependence would illegally // have the same base and value operand. - // - // TODO: handle indirect results - init?(unsafeApplyResult value: Value, _ context: some Context) { + init?(unsafeApplyResult value: Value, apply: FullApplySite, _ context: some Context) { if value.isEscapable { return nil } - if (value.definingInstructionOrTerminator as! FullApplySite).hasResultDependence { - return nil - } - assert(value.ownership == .owned, "unsafe apply result must be owned") + assert(!apply.hasResultDependence, "mark_dependence should be used instead") + assert(value.ownership == .owned || value.type.isAddress, "unsafe apply result must be owned") self.scope = Scope(base: value, context) self.dependentValue = value self.markDepInst = nil @@ -279,8 +275,18 @@ extension LifetimeDependence.Scope { case let .box(projectBox): // Note: the box may be in a borrow scope. self.init(base: projectBox.operand.value, context) - case .stack, .class, .tail, .pointer, .index, .unidentified: + case .class, .tail, .pointer, .index: self = .unknown(accessBase.address!) + case .unidentified: + self = .unknown(address) + case let .stack(allocStack): + if let initializer = accessBase.findSingleInitializer(context) { + if case let .store(store, _) = initializer { + self = .initialized(.store(initializingStore: store, initialAddress: allocStack)) + return + } + } + self = .unknown(allocStack) case .global: // TODO: When AccessBase directly stores GlobalAccessBase, we don't need a check here and don't need to pass // 'address' in to this function. @@ -400,6 +406,17 @@ extension LifetimeDependence.Scope { /// /// Returns nil if the dependence scope covers the entire function. Returns an empty range for an unknown scope. /// + /// Ignore the lifetime of temporary trivial values (with .initialized and .unknown scopes). Temporaries have an + /// unknown Scope, which means that LifetimeDependence.Scope did not recognize a VariableScopeInstruction. This is + /// important to promote mark_dependence instructions emitted by SILGen to [nonescaping] (e.g. unsafeAddressor). It + /// also allows trivial value to be "extended" without actually tracking their scope, which is expected behavior. For + /// example: + /// + /// let span = Span(buffer.baseAddress) + /// + /// If 'baseAddress' is an opaque getter, then the temporary pointer is effectively valid + /// until the end of the function. + /// /// Note: The caller must deinitialize the returned range. func computeRange(_ context: Context) -> InstructionRange? { switch self { @@ -437,18 +454,13 @@ extension LifetimeDependence.Scope { if case let .argument(arg) = initializer, arg.convention.isInout { return nil } + let address = initializer.initialAddress + if address.type.objectType.isTrivial(in: address.parentFunction) { + return nil + } return LifetimeDependence.Scope.computeInitializedRange(initializer: initializer, context) case let .unknown(value): - // Ignore the lifetime of temporary trivial values. Temporaries have an unknown Scope, which means that - // LifetimeDependence.Scope did not recognize a VariableScopeInstruction. This is important to promote - // mark_dependence instructions emitted by SILGen to [nonescaping] (e.g. unsafeAddressor). It also allows trivial - // value to be "extended" without actually tracking their scope, which is expected behavior. For example: - // - // let span = Span(buffer.baseAddress) - // - // If 'baseAddress' is an opaque getter, then the temporary pointer is effectively valid - // until the end of the function. - if value.type.isTrivial(in: value.parentFunction) { + if value.type.objectType.isTrivial(in: value.parentFunction) { return nil } // Return an empty range. @@ -562,8 +574,8 @@ extension LifetimeDependenceDefUseWalker { } let root = dependence.dependentValue if root.type.isAddress { - // The root address may be an escapable mark_dependence that guards its address uses (unsafeAddress), or an - // allocation or incoming argument. In all these cases, it is sufficient to walk down the address uses. + // The root address may be an escapable mark_dependence that guards its address uses (unsafeAddress), an + // allocation, an incoming argument, or an outgoing argument. In all these cases, walk down the address uses. return walkDownAddressUses(of: root) } return walkDownUses(of: root, using: nil) @@ -585,7 +597,7 @@ extension LifetimeDependenceDefUseWalker { // Override ForwardingDefUseWalker. mutating func walkDown(operand: Operand) -> WalkResult { // Initially delegate all uses to OwnershipUseVisitor. - // walkDownDefault will be called for uses that forward ownership. + // forwardingUse() will be called for uses that forward ownership, which then delegates to walkDownDefault(). return classify(operand: operand) } @@ -638,7 +650,7 @@ extension LifetimeDependenceDefUseWalker { is DestroyNotEscapedClosureInst, is ClassMethodInst, is SuperMethodInst, is ClassifyBridgeObjectInst, is DebugValueInst, is ObjCMethodInst, is ObjCSuperMethodInst, is UnmanagedRetainValueInst, - is UnmanagedReleaseValueInst, is SelectEnumInst: + is UnmanagedReleaseValueInst, is SelectEnumInst, is IgnoredUseInst: // Catch .instantaneousUse operations that are dependence leaf uses. return leafUse(of: operand) @@ -663,6 +675,11 @@ extension LifetimeDependenceDefUseWalker { mutating func forwardingUse(of operand: Operand, isInnerLifetime: Bool) -> WalkResult { + // Lifetime dependence is only interested in dominated uses. Treat a returned phi like a dominated use by stopping + // at the phi operand rather than following the forwarded value to the ReturnInst. + if let phi = Phi(using: operand), phi.isReturnValue { + return returnedDependence(result: operand) + } // Delegate ownership forwarding operations to the ForwardingDefUseWalker. return walkDownDefault(forwarding: operand) } @@ -796,7 +813,10 @@ extension LifetimeDependenceDefUseWalker { } private mutating func walkDownAddressUses(of address: Value) -> WalkResult { - address.uses.ignoreTypeDependence.walk { + if !needWalk(for: address) { + return .continueWalk + } + return address.uses.ignoreTypeDependence.walk { return classifyAddress(operand: $0) } } @@ -814,9 +834,15 @@ extension LifetimeDependenceDefUseWalker { return walkDownUses(of: bfi, using: operand) case let .storeBorrow(sbi): return walkDownAddressUses(of: sbi) - case .beginApply: - // Skip the borrow scope; the type system enforces non-escapable - // arguments. + case let .beginApply(bai): + // First, visit the uses of any non-Escapable yields. The yielded value may be copied and used outside the + // coroutine scope. Now, visit the uses of the begin_apply token. This adds the coroutine scope itself to the + for yield in bai.yieldedValues { + if walkDownUses(of: yield, using: operand) == .abortWalk { + return .abortWalk + } + } + // lifetime to account for the scope of any arguments. return visitInnerBorrowUses(of: borrowInst, operand: operand) case .partialApply, .markDependence: fatalError("OwnershipUseVisitor should bypass partial_apply [on_stack] " @@ -910,6 +936,10 @@ extension LifetimeDependenceDefUseWalker { return loadedAddressUse(of: localAccess.operand!, intoValue: load) case let copyAddr as SourceDestAddrInstruction: return loadedAddressUse(of: localAccess.operand!, intoAddress: copyAddr.destinationOperand) + case is SwitchEnumAddrInst: + // switch_enum_addr does not produce any values. Subsequent uses of the address (unchecked_enum_data_addr) + // directly use the original address. + return .continueWalk default: return .abortWalk } @@ -929,9 +959,9 @@ extension LifetimeDependenceDefUseWalker { // Simply a marker that indicates the start of an in-memory dependent value. If this was a mark_dependence, uses // of its forwarded address has were visited by LocalVariableAccessWalker and recorded as separate local accesses. return .continueWalk - case .store: - let si = localAccess.operand!.instruction as! StoringInstruction - assert(si.sourceOperand == initialValue, "the only reachable store should be the current assignment") + case .store, .storeBorrow: + // A store does not use the previous in-memory value. + return .continueWalk case .apply: return visitAppliedUse(of: localAccess.operand!, by: localAccess.instruction as! FullApplySite) case .escape: @@ -945,13 +975,15 @@ extension LifetimeDependenceDefUseWalker { return yieldedDependence(result: localAccess.operand!) case .incomingArgument: fatalError("Incoming arguments are never reachable") + case .deadEnd: + return .continueWalk } - return .continueWalk } private mutating func visitAppliedUse(of operand: Operand, by apply: FullApplySite) -> WalkResult { if let conv = apply.convention(of: operand), conv.isIndirectOut { - return leafUse(of: operand) + // This apply initializes an allocation. + return dependentUse(of: operand, dependentAddress: operand.value) } if apply.isCallee(operand: operand) { return leafUse(of: operand) @@ -1065,6 +1097,277 @@ private struct LifetimeDependenceUsePrinter : LifetimeDependenceDefUseWalker { } } +// ============================================================================= +// LifetimeDependenceUseDefWalker - upward walk +// ============================================================================= + +/// Walk up lifetime dependencies to the first value associated with a variable declaration. +/// +/// To start walking: +/// walkUp(newLifetime: Value) -> WalkResult +/// +/// This utility finds a value or address that is the best-effort "root" of the chain of temporary lifetime-dependent +/// values. +/// +/// This "looks through" projections: a property that is either visible as a stored property or access via +/// unsafe[Mutable]Address. +/// +/// dependsOn(lvalue.field) // finds 'lvalue' when 'field' is a stored property +/// +/// dependsOn(lvalue.computed) // finds the temporary value directly returned by a getter. +/// +/// SILGen emits temporary copies that violate lifetime dependence semantcs. This utility looks through such temporary +/// copies, stopping at a value that introduces an immutable variable: move_value [var_decl] or begin_borrow [var_decl], +/// or at an access of a mutable variable: begin_access [read] or begin_access [modify]. +/// +/// In this example, the dependence "root" is copied, borrowed, and forwarded before being used as the base operand of +/// `mark_dependence`. The dependence "root" is the parent of the outer-most dependence scope. +/// +/// %root = apply // lifetime dependence root +/// %copy = copy_value %root +/// %parent = begin_borrow %copy // lifetime dependence parent value +/// %base = struct_extract %parent // lifetime dependence base value +/// %dependent = mark_dependence [nonescaping] %value on %base +/// +/// LifetimeDependenceUseDefWalker extends the ForwardingUseDefWalker to follow copies, moves, and +/// borrows. ForwardingUseDefWalker treats these as forward-extended lifetime introducers. But they inherit a lifetime +/// dependency from their operand because non-escapable values can be copied, moved, and borrowed. Nonetheless, all of +/// their uses must remain within original dependence scope. +/// +/// # owned lifetime dependence +/// %parent = apply // begin dependence scope -+ +/// ... | +/// %1 = mark_dependence [nonescaping] %value on %parent | +/// ... | +/// %2 = copy_value %1 -+ | +/// # forwarding instruction | | +/// %3 = struct $S (%2) | forward-extended lifetime | +/// | | OSSA Lifetime +/// %4 = move_value %3 -+ | +/// ... | forward-extended lifetime | +/// %5 = begin_borrow %4 | -+ | +/// # dependent use of %1 | | forward-extended lifetime| +/// end_borrow %5 | -+ | +/// destroy_value %4 -+ | +/// ... | +/// destroy_value %parent // end dependence scope -+ +/// +/// All of the dependent uses including `end_borrow %5` and `destroy_value %4` must be before the end of the dependence +/// scope: `destroy_value %parent`. In this case, the dependence parent is an owned value, so the scope is simply the +/// value's OSSA lifetime. +/// +/// The ForwardingUseDefWalker's PathContext is the most recent lifetime owner (Value?). If we ever want to track the +/// access path as well, then we can aggregate both the owner and access path in a single PathContext. +protocol LifetimeDependenceUseDefValueWalker : ForwardingUseDefWalker where PathContext == Value? { + var context: Context { get } + + // 'path' is the lifetime "owner": the "def" into which the current 'value' is eventually forwarded. + mutating func introducer(_ value: Value, _ path: PathContext) -> WalkResult + + // Minimally, check a ValueSet. This walker may traverse chains of + // aggregation and destructuring along with phis. + // + // 'path' is the "owner" of the forwarded value. + mutating func needWalk(for value: Value, _ path: PathContext) -> Bool + + // The 'newLifetime' value is not forwarded to its uses. + mutating func walkUp(newLifetime: Value) -> WalkResult + + // 'owner' is the "def" into which the current 'value' is eventually forwarded. + mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult +} + +// Defaults +extension LifetimeDependenceUseDefValueWalker { + mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult { + walkUpDefault(value: value, owner) + } +} + +// Helpers +extension LifetimeDependenceUseDefValueWalker { + mutating func walkUpDefault(value: Value, _ owner: Value?) -> WalkResult { + switch value.definingInstruction { + case let transition as OwnershipTransitionInstruction: + return walkUp(newLifetime: transition.operand.value) + case let load as LoadInstruction: + return walkUp(newLifetime: load.address) + default: + break + } + // If the dependence chain has a phi, consider it a root. Dependence roots dominate all dependent values. + if Phi(value) != nil { + return introducer(value, owner) + } + // ForwardingUseDefWalker will callback to introducer() when it finds no forwarding instruction. + return walkUpDefault(forwarded: value, owner) + } +} + +protocol LifetimeDependenceUseDefAddressWalker { + var context: Context { get } + + // If the scoped value is trivial, then only the variable's lexical scope is relevant, and access scopes can be + // ignored. + var isTrivialScope: Bool { get } + + mutating func needWalk(for address: Value) -> Bool + + mutating func addressIntroducer(_ address: Value, access: AccessBaseAndScopes) -> WalkResult + + // The 'newLifetime' value is not forwarded to its uses. It may be a non-address or an address. + mutating func walkUp(newLifetime: Value) -> WalkResult + + mutating func walkUp(address: Value, access: AccessBaseAndScopes) -> WalkResult +} + +// Defaults +extension LifetimeDependenceUseDefAddressWalker { + mutating func walkUp(address: Value, access: AccessBaseAndScopes) -> WalkResult { + walkUpDefault(address: address, access: access) + } +} + +// Helpers +extension LifetimeDependenceUseDefAddressWalker { + mutating func walkUp(address: Value) -> WalkResult { + walkUp(address: address, access: address.accessBaseWithScopes) + } + + mutating func walkUpDefault(address: Value, access: AccessBaseAndScopes) -> WalkResult { + if !needWalk(for: address) { + return .continueWalk + } + if let beginAccess = access.innermostAccess { + // Skip the access scope for unsafe[Mutable]Address. Treat it like a projection of 'self' rather than a separate + // variable access. + if let addressorSelf = beginAccess.unsafeAddressorSelf { + return walkUp(newLifetime: addressorSelf) + } + // Ignore the acces scope for trivial values regardless of whether it is singly-initialized. Trivial values do not + // need to be kept alive in memory and can be safely be overwritten in the same scope. Lifetime dependence only + // cares that the loaded value is within the lexical scope of the trivial value's variable declaration. Rather + // than skipping all access scopes, call 'walkUp' on each nested access in case one of them needs to redirect the + // walk, as required for 'access.unsafeAddressorSelf' or in case the implementation overrides certain accesses. + if isTrivialScope { + return walkUp(newLifetime: beginAccess.address) + } + // Generally assume an access scope introduces a variable borrow scope. And generally ignore address forwarding + // mark_dependence. + return addressIntroducer(beginAccess, access: access) + } + // Continue walking for some kinds of access base. + switch access.base { + case .box, .global, .class, .tail, .pointer, .index, .unidentified: + break + case let .stack(allocStack): + // Ignore stack locations. Their access scopes do not affect lifetime dependence. + return walkUp(stackInitializer: allocStack, at: address, access: access) + case let .argument(arg): + if arg.convention.isExclusiveIndirect { + return addressIntroducer(arg, access: access) + } + case let .yield(yieldedAddress): + // Ignore access scopes for @in or @in_guaranteed yields when all scopes are reads. + let apply = yieldedAddress.definingInstruction as! FullApplySite + if apply.convention(of: yieldedAddress).isIndirectIn && access.isOnlyReadAccess { + return addressIntroducer(yieldedAddress, access: access) + } + case .storeBorrow(let sb): + // Walk up through a store into a temporary. + if access.scopes.isEmpty, + case .stack = sb.destinationOperand.value.accessBase { + return walkUp(newLifetime: sb.source) + } + } + return addressIntroducer(access.enclosingAccess.address ?? address, access: access) + } + + // Handle singly-initialized temporary stack locations. + mutating func walkUp(stackInitializer allocStack: AllocStackInst, at address: Value, + access: AccessBaseAndScopes) -> WalkResult { + guard let initializer = allocStack.accessBase.findSingleInitializer(context) else { + return addressIntroducer(address, access: access) + } + if case let .store(store, _) = initializer { + switch store { + case let store as StoringInstruction: + return walkUp(newLifetime: store.source) + case let srcDestInst as SourceDestAddrInstruction: + return walkUp(newLifetime: srcDestInst.source) + case let apply as FullApplySite: + if let f = apply.referencedFunction, f.isConvertPointerToPointerArgument { + return walkUp(newLifetime: apply.parameterOperands[0].value) + } + default: + break + } + } + return addressIntroducer(address, access: access) + } +} + +/// Walk up through all new lifetimes to find the roots of a lifetime dependence chain. +struct LifetimeDependenceRootWalker : LifetimeDependenceUseDefValueWalker, LifetimeDependenceUseDefAddressWalker { + // The ForwardingUseDefWalker's context is the most recent lifetime owner. + typealias PathContext = Value? + + let context: Context + + // If the scoped value is trivial, then only the variable's lexical scope is relevant, and access scopes can be + // ignored. + let isTrivialScope: Bool + + // This visited set is only really needed for instructions with + // multiple results, including phis. + private var visitedValues: ValueSet + + var roots: SingleInlineArray = SingleInlineArray() + + init(_ context: Context, scopedValue: Value) { + self.context = context + self.isTrivialScope = scopedValue.type.isAddress + ? scopedValue.type.objectType.isTrivial(in: scopedValue.parentFunction) + : scopedValue.isTrivial(context) + self.visitedValues = ValueSet(context) + } + + mutating func deinitialize() { + visitedValues.deinitialize() + } + + mutating func introducer(_ value: Value, _ owner: Value?) -> WalkResult { + roots.push(value) + return .continueWalk + } + + mutating func addressIntroducer(_ address: Value, access: AccessBaseAndScopes) -> WalkResult { + roots.push(address) + return .continueWalk + } + + mutating func needWalk(for value: Value, _ owner: Value?) -> Bool { + visitedValues.insert(value) + } + + mutating func needWalk(for address: Value) -> Bool { + visitedValues.insert(address) + } + + mutating func walkUp(newLifetime: Value) -> WalkResult { + if newLifetime.type.isAddress { + return walkUp(address: newLifetime) + } + let newOwner = newLifetime.ownership == .owned ? newLifetime : nil + return walkUp(value: newLifetime, newOwner) + } +} + +// ============================================================================= +// Unit tests +// ============================================================================= + + let lifetimeDependenceUseTest = FunctionTest("lifetime_dependence_use") { function, arguments, context in let value = arguments.takeValue() @@ -1087,6 +1390,18 @@ let lifetimeDependenceUseTest = FunctionTest("lifetime_dependence_use") { _ = printer.walkDown(dependence: dependence) } +let lifetimeDependenceRootTest = FunctionTest("lifetime_dependence_root") { + function, arguments, context in + let value = arguments.takeValue() + print("Lifetime dependence roots of: \(value)") + var walker = LifetimeDependenceRootWalker(context, scopedValue: value) + let result = walker.walkUp(newLifetime: value) + assert(result == .continueWalk) + for root in walker.roots { + print("root: \(root)") + } + walker.deinitialize() +} // SIL Unit tests diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift index 2736f60ca0531..222086411046e 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift @@ -27,9 +27,9 @@ import SIL private let verbose = false -private func log(_ message: @autoclosure () -> String) { +private func log(prefix: Bool = true, _ message: @autoclosure () -> String) { if verbose { - print("### \(message())") + debugLog(prefix: prefix, message()) } } @@ -69,8 +69,10 @@ struct LocalVariableAccess: CustomStringConvertible { case dependenceSource // A value/address depends on this local here (like a load) case dependenceDest // This local depends on another value/address here (like a store) case store // 'var' initialization and destruction + case storeBorrow // scoped initialization of temporaries case apply // indirect arguments case escape // alloc_box captures + case deadEnd // unreachable } let kind: Kind // All access have an operand except .incomingArgument and .outgoingArgument. @@ -101,9 +103,9 @@ struct LocalVariableAccess: CustomStringConvertible { case .`init`, .modify: return true } - case .load, .dependenceSource, .dependenceDest: + case .load, .dependenceSource, .dependenceDest, .deadEnd: return false - case .incomingArgument, .outgoingArgument, .store, .inoutYield: + case .incomingArgument, .outgoingArgument, .store, .storeBorrow, .inoutYield: return true case .apply: let apply = instruction as! FullApplySite @@ -146,10 +148,14 @@ struct LocalVariableAccess: CustomStringConvertible { str += "dependenceDest" case .store: str += "store" + case .storeBorrow: + str += "storeBorrow" case .apply: str += "apply" case .escape: str += "escape" + case .deadEnd: + str += "deadEnd" } if let inst = instruction { str += "\(inst)" @@ -178,9 +184,9 @@ class LocalVariableAccessInfo: CustomStringConvertible { case .`init`, .modify: break // lazily compute full assignment } - case .load, .dependenceSource, .dependenceDest: + case .load, .dependenceSource, .dependenceDest: self._isFullyAssigned = false - case .store: + case .store, .storeBorrow: if let store = localAccess.instruction as? StoringInstruction { self._isFullyAssigned = LocalVariableAccessInfo.isBase(address: store.destination) } else { @@ -198,7 +204,7 @@ class LocalVariableAccessInfo: CustomStringConvertible { self.hasEscaped = true case .inoutYield: self._isFullyAssigned = false - case .incomingArgument, .outgoingArgument: + case .incomingArgument, .outgoingArgument, .deadEnd: fatalError("Function arguments are never mapped to LocalVariableAccessInfo") } } @@ -226,7 +232,7 @@ class LocalVariableAccessInfo: CustomStringConvertible { } var description: String { - return "full-assign: \(_isFullyAssigned == nil ? "unknown" : String(describing: _isFullyAssigned!)), " + return "assign: \(_isFullyAssigned == nil ? "unknown" : String(describing: _isFullyAssigned!)), " + "\(access)" } @@ -329,7 +335,7 @@ struct LocalVariableAccessMap: Collection, CustomStringConvertible { subscript(instruction: Instruction) -> LocalVariableAccessInfo? { accessMap[instruction] } var description: String { - "Access map:\n" + map({String(describing: $0)}).joined(separator: "\n") + "Access map for: \(allocation)\n" + map({String(describing: $0)}).joined(separator: "\n") } } @@ -421,12 +427,17 @@ extension LocalVariableAccessWalker: AddressUseVisitor { // temporaries do not have access scopes, so we need to walk down any projection that may be used to initialize the // temporary. mutating func projectedAddressUse(of operand: Operand, into value: Value) -> WalkResult { - // Intercept mark_dependence destination to record an access point which can be used like a store when finding all - // uses that affect the base after the point that the dependence was marked. if let md = value as? MarkDependenceInst { - assert(operand == md.valueOperand) - visit(LocalVariableAccess(.dependenceDest, operand)) - // walk down the forwarded address as usual... + if operand == md.valueOperand { + // Intercept mark_dependence destination to record an access point which can be used like a store when finding + // all uses that affect the base after the point that the dependence was marked. + visit(LocalVariableAccess(.dependenceDest, operand)) + // walk down the forwarded address as usual... + } else { + // A dependence is similar to loading from its source. Downstream uses are not accesses of the original local. + visit(LocalVariableAccess(.dependenceSource, operand)) + return .continueWalk + } } return walkDownAddressUses(address: value) } @@ -442,6 +453,9 @@ extension LocalVariableAccessWalker: AddressUseVisitor { case is LoadBorrowInst: visit(LocalVariableAccess(.load, operand)) return .continueWalk + case is StoreBorrowInst: + visit(LocalVariableAccess(.storeBorrow, operand)) + return .continueWalk default: // A StoreBorrow should be guarded by an access scope. // @@ -457,13 +471,18 @@ extension LocalVariableAccessWalker: AddressUseVisitor { mutating func leafAddressUse(of operand: Operand) -> WalkResult { switch operand.instruction { case is StoringInstruction, is SourceDestAddrInstruction, is DestroyAddrInst, is DeinitExistentialAddrInst, - is InjectEnumAddrInst, is SwitchEnumAddrInst, is TupleAddrConstructorInst, is InitBlockStorageHeaderInst, - is PackElementSetInst: - // Handle instructions that initialize both temporaries and local variables. + is InjectEnumAddrInst, is TupleAddrConstructorInst, is InitBlockStorageHeaderInst, is PackElementSetInst: + // Handle instructions that initialize both temporaries and local variables. If operand's address is the same as + // the local variable's address, then this fully kills operand liveness. The original value in operand's address + // cannot be used in any way. visit(LocalVariableAccess(.store, operand)) case let md as MarkDependenceAddrInst: assert(operand == md.addressOperand) visit(LocalVariableAccess(.dependenceDest, operand)) + case is SwitchEnumAddrInst: + // switch_enum_addr is truly a leaf address use. It does not produce a new value. But in every other respect it is + // like a load. + visit(LocalVariableAccess(.load, operand)) case is DeallocStackInst: break default: @@ -630,13 +649,17 @@ struct LocalVariableReachableAccess { // Find reaching assignments... extension LocalVariableReachableAccess { - // Gather all fully assigned accesses that reach `instruction`. + // Gather all fully assigned accesses that reach 'instruction'. If 'instruction' is itself a modify access, it is + // ignored and the nearest assignments above 'instruction' are still gathered. func gatherReachingAssignments(for instruction: Instruction, in accessStack: inout Stack) -> Bool { var blockList = BasicBlockWorklist(context) defer { blockList.deinitialize() } - let initialEffect = backwardScanAccesses(before: instruction, accessStack: &accessStack) + var initialEffect: BlockEffect? = nil + if let prev = instruction.previous { + initialEffect = backwardScanAccesses(before: prev, accessStack: &accessStack) + } if !backwardPropagateEffect(in: instruction.parentBlock, effect: initialEffect, blockList: &blockList, accessStack: &accessStack) { return false @@ -647,7 +670,7 @@ extension LocalVariableReachableAccess { // lattice: none -> read -> modify -> escape -> assign // // `blockInfo.effect` is the same as `currentEffect` returned by backwardScanAccesses, except when an early escape - // happens after an assign. + // happens below an assign, in which case we report the escape here. switch currentEffect { case .none, .read, .modify, .escape: break @@ -695,10 +718,10 @@ extension LocalVariableReachableAccess { continue case .assign: accessStack.push(accessInfo.access) - break case .escape: break } + break } return currentEffect } @@ -708,27 +731,33 @@ extension LocalVariableReachableAccess { extension LocalVariableReachableAccess { /// This performs a forward CFG walk to find known reachable uses from `assignment`. This ignores aliasing and /// escapes. - func gatherKnownReachableUses(from assignment: LocalVariableAccess, + /// + /// The known live range is the range in which the assigned value is valid and may be used by dependent values. It + /// includes the destroy or reassignment of the local. + func gatherKnownLifetimeUses(from assignment: LocalVariableAccess, in accessStack: inout Stack) { if let modifyInst = assignment.instruction { - _ = gatherReachableUses(after: modifyInst, in: &accessStack, allowEscape: true) + _ = gatherReachableUses(after: modifyInst, in: &accessStack, lifetime: true) + return } - gatherKnownReachableUsesFromEntry(in: &accessStack) + gatherKnownLifetimeUsesFromEntry(in: &accessStack) } /// This performs a forward CFG walk to find known reachable uses from the function entry. This ignores aliasing and /// escapes. - private func gatherKnownReachableUsesFromEntry(in accessStack: inout Stack) { + private func gatherKnownLifetimeUsesFromEntry(in accessStack: inout Stack) { assert(accessMap.liveInAccess!.kind == .incomingArgument, "only an argument access is live in to the function") let firstInst = accessMap.function.entryBlock.instructions.first! - _ = gatherReachableUses(onOrAfter: firstInst, in: &accessStack, allowEscape: true) + _ = gatherReachableUses(onOrAfter: firstInst, in: &accessStack, lifetime: true) } /// This performs a forward CFG walk to find all reachable uses of `modifyInst`. `modifyInst` may be a `begin_access /// [modify]` or instruction that initializes the local variable. /// - /// Returns true if all possible reachable uses were visited. Returns false if any escapes may reach `modifyInst` are - /// reachable from `modifyInst`. + /// This does not include the destroy or reassignment of the value set by `modifyInst`. + /// + /// Returns true if all possible reachable uses were visited. Returns false if any escapes may reach `modifyInst` or + /// are reachable from `modifyInst`. /// /// This does not gather the escaping accesses themselves. When escapes are reachable, it also does not guarantee that /// previously reachable accesses are gathered. @@ -748,37 +777,40 @@ extension LocalVariableReachableAccess { if accessInfo.hasEscaped! { return false } - return gatherReachableUses(after: modifyInst, in: &accessStack, allowEscape: false) + return gatherReachableUses(after: modifyInst, in: &accessStack, lifetime: false) } /// This performs a forward CFG walk to find all uses of this local variable reachable after `begin`. /// - /// If `allowEscape` is true, then this returns false if the walk ended early because of a reachable escape. + /// If `lifetime` is true, then this gathers the full known lifetime, includeing destroys and reassignments ignoring + /// escapes. + /// + /// If `lifetime` is false, then this returns `false` if the walk ended early because of a reachable escape. private func gatherReachableUses(after begin: Instruction, in accessStack: inout Stack, - allowEscape: Bool) -> Bool { + lifetime: Bool) -> Bool { if let term = begin as? TermInst { for succ in term.successors { - if !gatherReachableUses(onOrAfter: succ.instructions.first!, in: &accessStack, allowEscape: allowEscape) { + if !gatherReachableUses(onOrAfter: succ.instructions.first!, in: &accessStack, lifetime: lifetime) { return false } } return true } else { - return gatherReachableUses(onOrAfter: begin.next!, in: &accessStack, allowEscape: allowEscape) + return gatherReachableUses(onOrAfter: begin.next!, in: &accessStack, lifetime: lifetime) } } /// This performs a forward CFG walk to find all uses of this local variable reachable after and including `begin`. /// - /// If `allowEscape` is true, then this returns false if the walk ended early because of a reachable escape. + /// If `lifetime` is true, then this returns false if the walk ended early because of a reachable escape. private func gatherReachableUses(onOrAfter begin: Instruction, in accessStack: inout Stack, - allowEscape: Bool) -> Bool { + lifetime: Bool) -> Bool { var blockList = BasicBlockWorklist(context) defer { blockList.deinitialize() } let initialBlock = begin.parentBlock - let initialEffect = forwardScanAccesses(after: begin, accessStack: &accessStack, allowEscape: allowEscape) - if !allowEscape, initialEffect == .escape { + let initialEffect = forwardScanAccesses(after: begin, accessStack: &accessStack, lifetime: lifetime) + if !lifetime, initialEffect == .escape { return false } forwardPropagateEffect(in: initialBlock, blockInfo: blockMap[initialBlock], effect: initialEffect, @@ -794,22 +826,22 @@ extension LocalVariableReachableAccess { case .none: break case .escape: - if !allowEscape { + if !lifetime { break } fallthrough case .read, .modify, .assign: let firstInst = block.instructions.first! - currentEffect = forwardScanAccesses(after: firstInst, accessStack: &accessStack, allowEscape: allowEscape) + currentEffect = forwardScanAccesses(after: firstInst, accessStack: &accessStack, lifetime: lifetime) } - if !allowEscape, currentEffect == .escape { + if !lifetime, currentEffect == .escape { return false } forwardPropagateEffect(in: block, blockInfo: blockInfo, effect: currentEffect, blockList: &blockList, accessStack: &accessStack) } - log("\(accessMap)") - log("Reachable access:\n\(accessStack.map({ String(describing: $0)}).joined(separator: "\n"))") + log("\n\(accessMap)") + log(prefix: false, "Reachable access:\n\(accessStack.map({ String(describing: $0)}).joined(separator: "\n"))") return true } @@ -826,6 +858,8 @@ extension LocalVariableReachableAccess { } if block.terminator.isFunctionExiting { accessStack.push(LocalVariableAccess(.outgoingArgument, block.terminator)) + } else if block.successors.isEmpty { + accessStack.push(LocalVariableAccess(.deadEnd, block.terminator)) } else { for successor in block.successors { blockList.pushIfNotVisited(successor) } } @@ -835,9 +869,9 @@ extension LocalVariableReachableAccess { } // Check all instructions in this block after and including `begin`. Return a BlockEffect indicating the combined - // effects seen before stopping the scan. An .assign stops the scan. A .escape stops the scan if allowEscape is false. + // effects seen before stopping the scan. An .assign stops the scan. A .escape stops the scan if lifetime is false. private func forwardScanAccesses(after first: Instruction, accessStack: inout Stack, - allowEscape: Bool) + lifetime: Bool) -> BlockEffect? { var currentEffect: BlockEffect? for inst in InstructionList(first: first) { @@ -847,9 +881,12 @@ extension LocalVariableReachableAccess { currentEffect = BlockEffect(for: accessInfo, accessMap.context).meet(currentEffect) switch currentEffect! { case .assign: + if lifetime { + accessStack.push(accessInfo.access) + } return currentEffect case .escape: - if !allowEscape { + if !lifetime { log("Local variable: \(accessMap.allocation)\n escapes at \(inst)") return currentEffect } @@ -873,7 +910,7 @@ extension LocalVariableReachableAccess { private func findAllEscapesPriorToAccess() { var visitedBlocks = BasicBlockSet(context) var escapedBlocks = BasicBlockSet(context) - var blockList = BasicBlockWorklist(context) + var blockList = Stack(context) defer { visitedBlocks.deinitialize() escapedBlocks.deinitialize() @@ -886,19 +923,19 @@ extension LocalVariableReachableAccess { for successor in from.successors { if hasEscaped { if escapedBlocks.insert(successor) { - blockList.pushIfNotVisited(successor) + blockList.push(successor) } } else if visitedBlocks.insert(successor) { - blockList.pushIfNotVisited(successor) + blockList.push(successor) } } } var hasEscaped = propagateEscapeInBlock(after: accessMap.allocation.nextInstruction, hasEscaped: false) forwardPropagate(accessMap.allocation.parentBlock, hasEscaped) while let block = blockList.pop() { - hasEscaped = escapedBlocks.insert(block) + hasEscaped = escapedBlocks.contains(block) hasEscaped = propagateEscapeInBlock(after: block.instructions.first!, hasEscaped: hasEscaped) - forwardPropagate(accessMap.allocation.parentBlock, hasEscaped) + forwardPropagate(block, hasEscaped) } } @@ -917,3 +954,49 @@ extension LocalVariableReachableAccess { return hasEscaped } } + +let localVariableReachingAssignmentsTest = FunctionTest("local_variable_reaching_assignments") { + function, arguments, context in + let allocation = arguments.takeValue() + let instruction = arguments.takeInstruction() + print("### Allocation: \(allocation)") + let localReachabilityCache = LocalVariableReachabilityCache() + guard let localReachability = localReachabilityCache.reachability(for: allocation, context) else { + print("No reachability") + return + } + print("### Access map:") + print(localReachability.accessMap) + print("### Instruction: \(instruction)") + var reachingAssignments = Stack(context) + defer { reachingAssignments.deinitialize() } + guard localReachability.gatherReachingAssignments(for: instruction, in: &reachingAssignments) else { + print("!!! Reaching escape") + return + } + print("### Reachable assignments:") + print(reachingAssignments.map({ String(describing: $0)}).joined(separator: "\n")) +} + +let localVariableReachableUsesTest = FunctionTest("local_variable_reachable_uses") { + function, arguments, context in + let allocation = arguments.takeValue() + let modify = arguments.takeInstruction() + print("### Allocation: \(allocation)") + let localReachabilityCache = LocalVariableReachabilityCache() + guard let localReachability = localReachabilityCache.reachability(for: allocation, context) else { + print("No reachability") + return + } + print("### Access map:") + print(localReachability.accessMap) + print("### Modify: \(modify)") + var reachableUses = Stack(context) + defer { reachableUses.deinitialize() } + guard localReachability.gatherAllReachableUses(of: modify, in: &reachableUses) else { + print("!!! Reachable escape") + return + } + print("### Reachable access:") + print(reachableUses.map({ String(describing: $0)}).joined(separator: "\n")) +} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 6173adaf24e75..9d1ea5ead1d48 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -456,7 +456,7 @@ extension Instruction { } } - /// Returns true if `otherInst` is in the same block and dominated by this instruction. + /// Returns true if `otherInst` is in the same block and is strictly dominated by this instruction. /// To be used as simple dominance check if both instructions are most likely located in the same block /// and no DominatorTree is available (like in instruction simplification). func dominatesInSameBlock(_ otherInst: Instruction) -> Bool { @@ -941,27 +941,74 @@ extension CheckedCastAddrBranchInst { extension CopyAddrInst { @discardableResult - func replaceWithLoadAndStore(_ context: some MutatingContext) -> StoreInst { - let loadOwnership: LoadInst.LoadOwnership - let storeOwnership: StoreInst.StoreOwnership - if parentFunction.hasOwnership { - if source.type.isTrivial(in: parentFunction) { - loadOwnership = .trivial - storeOwnership = .trivial - } else { - loadOwnership = isTakeOfSrc ? .take : .copy - storeOwnership = isInitializationOfDest ? .initialize : .assign + func trySplit(_ context: FunctionPassContext) -> Bool { + let builder = Builder(before: self, context) + if source.type.isStruct { + if (source.type.nominal as! StructDecl).hasUnreferenceableStorage { + return false } - } else { - loadOwnership = .unqualified - storeOwnership = .unqualified + guard let fields = source.type.getNominalFields(in: parentFunction) else { + return false + } + for idx in 0.. Bool { + return isTakeOfSrc && !fieldValue.type.objectType.isTrivial(in: parentFunction) + } + + @discardableResult + func replaceWithLoadAndStore(_ context: some MutatingContext) -> (load: LoadInst, store: StoreInst) { let builder = Builder(before: self, context) - let value = builder.createLoad(fromAddress: source, ownership: loadOwnership) - let store = builder.createStore(source: value, destination: destination, ownership: storeOwnership) + let load = builder.createLoad(fromAddress: source, ownership: loadOwnership) + let store = builder.createStore(source: load, destination: destination, ownership: storeOwnership) context.erase(instruction: self) - return store + return (load, store) + } + + var loadOwnership: LoadInst.LoadOwnership { + if !parentFunction.hasOwnership { + return .unqualified + } + if type.isTrivial(in: parentFunction) { + return .trivial + } + if isTakeOfSrc { + return .take + } + return .copy + } + + var storeOwnership: StoreInst.StoreOwnership { + if !parentFunction.hasOwnership { + return .unqualified + } + if type.isTrivial(in: parentFunction) { + return .trivial + } + if isInitializationOfDest { + return .initialize + } + return .assign } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift index 7b1d0f88c4d28..60e2803d34ac0 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift @@ -50,4 +50,14 @@ struct SSAUpdater { context.notifyInstructionsChanged() return context._bridged.SSAUpdater_getValueInMiddleOfBlock(block.bridged).value } + + var insertedPhis: [Phi] { + var phis = [Phi]() + let numPhis = context._bridged.SSAUpdater_getNumInsertedPhis() + phis.reserveCapacity(numPhis) + for idx in 0.. Bool { + return function.bridged.conformanceMatchesActorIsolation(bridged) + } +} diff --git a/SwiftCompilerSources/Sources/SIL/ApplySite.swift b/SwiftCompilerSources/Sources/SIL/ApplySite.swift index a8bf3a07fb3bf..4e7c0168dfb14 100644 --- a/SwiftCompilerSources/Sources/SIL/ApplySite.swift +++ b/SwiftCompilerSources/Sources/SIL/ApplySite.swift @@ -229,6 +229,13 @@ extension ApplySite { functionConvention.resultDependencies != nil } + public func isAddressable(operand: Operand) -> Bool { + if let dep = resultDependence(on: operand) { + return dep.isAddressable(for: operand.value) + } + return false + } + public var hasLifetimeDependence: Bool { functionConvention.hasLifetimeDependencies() } diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index 26c6bed560e4d..9892f011e172b 100644 --- a/SwiftCompilerSources/Sources/SIL/Argument.swift +++ b/SwiftCompilerSources/Sources/SIL/Argument.swift @@ -34,7 +34,12 @@ public class Argument : Value, Hashable { public var isLexical: Bool { false } - public var varDecl: VarDecl? { bridged.getVarDecl().getAs(VarDecl.self) } + public var varDecl: VarDecl? { + if let varDecl = bridged.getVarDecl().getAs(VarDecl.self) { + return varDecl + } + return debugUserDecl + } public var sourceLoc: SourceLoc? { varDecl?.nameLoc } @@ -56,6 +61,10 @@ final public class FunctionArgument : Argument { bridged.FunctionArgument_isLexical() } + public var isClosureCapture: Bool { + bridged.FunctionArgument_isClosureCapture() + } + public var isSelf: Bool { parentFunction.argumentConventions.selfIndex == index } @@ -192,6 +201,22 @@ public struct Phi { } } +extension Phi { + /// Return true of this phi is directly returned with no side effects between the phi and the return. + public var isReturnValue: Bool { + if let singleUse = value.uses.singleUse, let ret = singleUse.instruction as? ReturnInst, + ret.parentBlock == successor { + for inst in successor.instructions { + if inst.mayHaveSideEffects { + return false + } + } + return true + } + return false + } +} + extension Operand { public var forwardingBorrowedFromUser: BorrowedFromInst? { if let bfi = instruction as? BorrowedFromInst, index == 0 { @@ -260,7 +285,7 @@ public struct ArgumentConventions : Collection, CustomStringConvertible { if let paramIdx = parameterIndex(for: argumentIndex) { return convention.parameters[paramIdx].convention } - let resultInfo = convention.indirectSILResults[argumentIndex] + let resultInfo = convention.indirectSILResult(at: argumentIndex) return ArgumentConvention(result: resultInfo.convention) } @@ -268,7 +293,7 @@ public struct ArgumentConventions : Collection, CustomStringConvertible { if parameterIndex(for: argumentIndex) != nil { return nil } - return convention.indirectSILResults[argumentIndex] + return convention.indirectSILResult(at: argumentIndex) } public subscript(parameter argumentIndex: Int) -> ParameterInfo? { @@ -591,19 +616,6 @@ public enum ArgumentConvention : CustomStringConvertible { } } -extension BeginAccessInst.AccessKind { - public func isCompatible(with convention: ArgumentConvention) -> Bool { - switch self { - case .`init`, .deinit: - return false - case .read: - return convention.isIndirectIn - case .modify: - return convention.isInout - } - } -} - // Bridging utilities extension BridgedArgument { diff --git a/SwiftCompilerSources/Sources/SIL/Builder.swift b/SwiftCompilerSources/Sources/SIL/Builder.swift index fa4b3e1725e0d..235a5dcc411eb 100644 --- a/SwiftCompilerSources/Sources/SIL/Builder.swift +++ b/SwiftCompilerSources/Sources/SIL/Builder.swift @@ -215,6 +215,13 @@ public struct Builder { return notifyNew(cast.getAs(UnconditionalCheckedCastAddrInst.self)) } + public func createUncheckedOwnershipConversion( + operand: Value, resultOwnership: Ownership + ) -> UncheckedOwnershipConversionInst { + let uoc = bridged.createUncheckedOwnershipConversion(operand.bridged, resultOwnership._bridged) + return notifyNew(uoc.getAs(UncheckedOwnershipConversionInst.self)) + } + public func createLoad(fromAddress: Value, ownership: LoadInst.LoadOwnership) -> LoadInst { let load = bridged.createLoad(fromAddress.bridged, ownership.rawValue) return notifyNew(load.getAs(LoadInst.self)) @@ -575,6 +582,12 @@ public struct Builder { return notifyNew(endMutation.getAs(EndCOWMutationInst.self)) } + @discardableResult + public func createEndCOWMutationAddr(address: Value) -> EndCOWMutationAddrInst { + let endMutation = bridged.createEndCOWMutationAddr(address.bridged) + return notifyNew(endMutation.getAs(EndCOWMutationAddrInst.self)) + } + public func createMarkDependence(value: Value, base: Value, kind: MarkDependenceKind) -> MarkDependenceInst { let markDependence = bridged.createMarkDependence(value.bridged, base.bridged, BridgedInstruction.MarkDependenceKind(rawValue: kind.rawValue)!) diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift index 11db1fedf5f5b..00ecf480145d6 100644 --- a/SwiftCompilerSources/Sources/SIL/Function.swift +++ b/SwiftCompilerSources/Sources/SIL/Function.swift @@ -219,6 +219,13 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash } } + public var accessorKindName: String? { + guard bridged.isAccessor() else { + return nil + } + return StringRef(bridged: bridged.getAccessorName()).string + } + /// True, if the function runs with a swift 5.1 runtime. /// Note that this is function specific, because inlinable functions are de-serialized /// in a client module, which might be compiled with a different deployment target. diff --git a/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift b/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift index a95ea62ee2f1e..036d8436fc2c6 100644 --- a/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift +++ b/SwiftCompilerSources/Sources/SIL/FunctionConvention.swift @@ -53,11 +53,15 @@ public struct FunctionConvention : CustomStringConvertible { : SILFunctionType_getNumPackResults(functionType.bridged) } - /// Indirect results including the error. - public var indirectSILResults: LazyFilterSequence { - hasLoweredAddresses - ? results.lazy.filter { $0.isSILIndirect } - : results.lazy.filter { $0.convention == .pack } + /// Returns the indirect result - including the error - at `index`. + public func indirectSILResult(at index: Int) -> ResultInfo { + let indirectResults = results.lazy.filter { + hasLoweredAddresses ? $0.isSILIndirect : $0.convention == .pack + } + // Note that subscripting a LazyFilterCollection (with the base index, e.g. `Int`) does not work + // as expected, because it returns the nth element of the base collection! + // Therefore we need to implement the subscript "manually". + return indirectResults.enumerated().first{ $0.offset == index }!.element } public var parameters: Parameters { diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 64dbfe771f393..e0f8749af38db 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -149,7 +149,8 @@ public class Instruction : CustomStringConvertible, Hashable { /// their operand. public final var isIncidentalUse: Bool { switch self { - case is DebugValueInst, is FixLifetimeInst, is EndLifetimeInst: + case is DebugValueInst, is FixLifetimeInst, is EndLifetimeInst, + is IgnoredUseInst: return true default: return isEndOfScopeMarker @@ -451,7 +452,7 @@ public enum VariableScopeInstruction { // TODO: with SIL verification, we might be able to make varDecl non-Optional. public var varDecl: VarDecl? { - if let debugVarDecl = instruction.debugVarDecl { + if let debugVarDecl = instruction.debugResultDecl { return debugVarDecl } // SILGen may produce double var_decl instructions for the same variable: @@ -473,15 +474,31 @@ extension Instruction { if let varScopeInst = VariableScopeInstruction(self) { return varScopeInst.varDecl } - return debugVarDecl + return debugResultDecl } - var debugVarDecl: VarDecl? { + var debugResultDecl: VarDecl? { for result in results { - for use in result.uses { - if let debugVal = use.instruction as? DebugValueInst { - return debugVal.varDecl - } + if let varDecl = result.debugUserDecl { + return varDecl + } + } + return nil + } +} + +extension Value { + var debugValDecl: VarDecl? { + if let arg = self as? Argument { + return arg.varDecl + } + return debugUserDecl + } + + var debugUserDecl: VarDecl? { + for use in uses { + if let debugVal = use.instruction as? DebugValueInst { + return debugVal.varDecl } } return nil @@ -630,11 +647,7 @@ extension Deallocation { } -final public class DeallocStackInst : Instruction, UnaryInstruction, Deallocation { - public var allocstack: AllocStackInst { - return operand.value as! AllocStackInst - } -} +final public class DeallocStackInst : Instruction, UnaryInstruction, Deallocation {} final public class DeallocStackRefInst : Instruction, UnaryInstruction, Deallocation { public var allocRef: AllocRefInstBase { operand.value as! AllocRefInstBase } @@ -1071,7 +1084,7 @@ class ThinToThickFunctionInst : SingleValueInstruction, UnaryInstruction { final public class ThickToObjCMetatypeInst : SingleValueInstruction {} final public class ObjCToThickMetatypeInst : SingleValueInstruction {} -final public class CopyBlockInst : SingleValueInstruction {} +final public class CopyBlockInst : SingleValueInstruction, UnaryInstruction {} final public class CopyBlockWithoutEscapingInst : SingleValueInstruction {} final public @@ -1223,6 +1236,10 @@ final public class EndCOWMutationInst : SingleValueInstruction, UnaryInstruction public var doKeepUnique: Bool { bridged.EndCOWMutationInst_doKeepUnique() } } +final public class EndCOWMutationAddrInst : Instruction, UnaryInstruction { + public var address: Value { operand.value } +} + final public class ClassifyBridgeObjectInst : SingleValueInstruction, UnaryInstruction {} @@ -1346,6 +1363,7 @@ final public class AllocStackInst : SingleValueInstruction, Allocation, DebugVar public var hasDynamicLifetime: Bool { bridged.AllocStackInst_hasDynamicLifetime() } public var isFromVarDecl: Bool { bridged.AllocStackInst_isFromVarDecl() } public var usesMoveableValueDebugInfo: Bool { bridged.AllocStackInst_usesMoveableValueDebugInfo() } + public override var isLexical: Bool { bridged.AllocStackInst_isLexical() } public var varDecl: VarDecl? { bridged.AllocStack_getDecl().getAs(VarDecl.self) @@ -1472,7 +1490,7 @@ final public class LoadBorrowInst : SingleValueInstruction, LoadInstruction, Bor } final public class StoreBorrowInst : SingleValueInstruction, StoringInstruction, BorrowIntroducingInstruction { - var allocStack: AllocStackInst { + public var allocStack: AllocStackInst { var dest = destination if let mark = dest as? MarkUnresolvedNonCopyableValueInst { dest = mark.operand.value @@ -1531,14 +1549,15 @@ final public class EndUnpairedAccessInst : Instruction {} final public class BeginApplyInst : MultipleValueInstruction, FullApplySite { public var numArguments: Int { bridged.BeginApplyInst_numArguments() } + public var isCalleeAllocated: Bool { bridged.BeginApplyInst_isCalleeAllocated() } public var singleDirectResult: Value? { nil } public var singleDirectErrorResult: Value? { nil } - public var token: Value { getResult(index: resultCount - 1) } + public var token: Value { getResult(index: resultCount - (isCalleeAllocated ? 2 : 1)) } public var yieldedValues: Results { - Results(inst: self, numResults: resultCount - 1) + Results(inst: self, numResults: resultCount - (isCalleeAllocated ? 2 : 1)) } } diff --git a/SwiftCompilerSources/Sources/SIL/Registration.swift b/SwiftCompilerSources/Sources/SIL/Registration.swift index 3a6b1c7c73960..15b83dc9002dd 100644 --- a/SwiftCompilerSources/Sources/SIL/Registration.swift +++ b/SwiftCompilerSources/Sources/SIL/Registration.swift @@ -215,6 +215,7 @@ public func registerSILClasses() { register(MoveValueInst.self) register(DropDeinitInst.self) register(EndCOWMutationInst.self) + register(EndCOWMutationAddrInst.self) register(ClassifyBridgeObjectInst.self) register(PartialApplyInst.self) register(ApplyInst.self) diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift index d7680d9e832f5..42aa10cea05d1 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift @@ -89,6 +89,8 @@ public enum AccessBase : CustomStringConvertible, Hashable { /// The access base is some SIL pattern which does not fit into any other case. /// This should be a very rare situation. + /// + /// TODO: unidentified should preserve its base address value, but AccessBase must be Hashable. case unidentified public init(baseAddress: Value) { @@ -556,10 +558,6 @@ public struct AccessBaseAndScopes { self.scopes = scopes } - public var outerAddress: Value? { - base.address ?? scopes.last?.address - } - public var enclosingAccess: EnclosingAccessScope { return scopes.first ?? .base(base) } diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift index a5ecef2512688..6ab15c5de5a1f 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/WalkUtils.swift @@ -39,10 +39,11 @@ public enum WalkResult { } extension Sequence { + // Walk each element until the walk aborts. public func walk( - _ predicate: (Element) throws -> WalkResult + _ walker: (Element) throws -> WalkResult ) rethrows -> WalkResult { - return try contains { try predicate($0) == .abortWalk } ? .abortWalk : .continueWalk + return try contains { try walker($0) == .abortWalk } ? .abortWalk : .continueWalk } } diff --git a/benchmark/single-source/ObjectiveCBridging.swift b/benchmark/single-source/ObjectiveCBridging.swift index c0e9d1a083292..2fddb3dfc3726 100644 --- a/benchmark/single-source/ObjectiveCBridging.swift +++ b/benchmark/single-source/ObjectiveCBridging.swift @@ -97,6 +97,27 @@ public let benchmarks = [ BenchmarkInfo(name: "NSArray.bridged.repeatedBufferAccess", runFunction: run_BridgedNSArrayRepeatedBufferAccess, tags: t, setUpFunction: setup_bridgedArrays), + BenchmarkInfo(name: "NSDictionary.bridged.enumerate", + runFunction: run_BridgedNSDictionaryEnumerate, tags: t, + setUpFunction: setup_bridgedDictionaries), + BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.ascii", + runFunction: run_BridgedNSStringLengthASCII_ASCII, tags: ts, + setUpFunction: setup_bridgedStrings), + BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.utf8", + runFunction: run_BridgedNSStringLengthASCII_UTF8, tags: ts, + setUpFunction: setup_bridgedStrings), + BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.utf16", + runFunction: run_BridgedNSStringLengthASCII_UTF16, tags: ts, + setUpFunction: setup_bridgedStrings), + BenchmarkInfo(name: "NSString.bridged.byteCount.ascii.macroman", + runFunction: run_BridgedNSStringLengthASCII_MacRoman, tags: ts, + setUpFunction: setup_bridgedStrings), + BenchmarkInfo(name: "NSString.bridged.byteCount.utf8.utf8", + runFunction: run_BridgedNSStringLengthUTF8_UTF8, tags: ts, + setUpFunction: setup_bridgedStrings), + BenchmarkInfo(name: "NSString.bridged.byteCount.utf8.utf16", + runFunction: run_BridgedNSStringLengthUTF8_UTF16, tags: ts, + setUpFunction: setup_bridgedStrings), ] #if _runtime(_ObjC) @@ -794,9 +815,12 @@ public func run_UnicodeStringFromCodable(_ n: Int) { #if _runtime(_ObjC) var bridgedArray:NSArray! = nil +var bridgedDictionaryOfNumbersToNumbers:NSDictionary! = nil var bridgedArrayMutableCopy:NSMutableArray! = nil var nsArray:NSArray! = nil var nsArrayMutableCopy:NSMutableArray! = nil +var bridgedASCIIString:NSString! = nil +var bridgedUTF8String:NSString! = nil #endif public func setup_bridgedArrays() { @@ -804,11 +828,29 @@ public func setup_bridgedArrays() { var arr = Array(repeating: NSObject(), count: 100) as [AnyObject] bridgedArray = arr as NSArray bridgedArrayMutableCopy = (bridgedArray.mutableCopy() as! NSMutableArray) + nsArray = NSArray(objects: &arr, count: 100) nsArrayMutableCopy = (nsArray.mutableCopy() as! NSMutableArray) #endif } +public func setup_bridgedDictionaries() { + var numDict = Dictionary() + for i in 0 ..< 100 { + numDict[i] = i + } + bridgedDictionaryOfNumbersToNumbers = numDict as NSDictionary +} + +public func setup_bridgedStrings() { + #if _runtime(_ObjC) + let str = Array(repeating: "The quick brown fox jumps over the lazy dog.", count: 100).joined() + bridgedASCIIString = str as NSString + let str2 = Array(repeating: "The quick brown fox jumps over the lazy dög.", count: 100).joined() + bridgedUTF8String = str2 as NSString + #endif +} + @inline(never) public func run_BridgedNSArrayObjectAtIndex(_ n: Int) { #if _runtime(_ObjC) @@ -820,6 +862,23 @@ public func run_BridgedNSArrayObjectAtIndex(_ n: Int) { #endif } +private func dictionaryApplier( + _ keyPtr: UnsafeRawPointer?, + _ valuePtr :UnsafeRawPointer?, + _ contextPtr: UnsafeMutableRawPointer? +) -> Void {} + +@inline(never) +public func run_BridgedNSDictionaryEnumerate(_ n: Int) { + #if _runtime(_ObjC) + let cf = bridgedDictionaryOfNumbersToNumbers as CFDictionary + for _ in 0 ..< n * 50 { + // Use CF to prevent Swift from providing an override, forcing going through ObjC bridging + CFDictionaryApplyFunction(cf, dictionaryApplier, nil) + } + #endif +} + @inline(never) public func run_BridgedNSArrayBufferAccess(_ n: Int) { #if _runtime(_ObjC) @@ -883,3 +942,40 @@ public func run_RealNSArrayMutableCopyObjectAtIndex(_ n: Int) { #endif } +@inline(__always) +fileprivate func run_BridgedNSStringLength(_ asciiBase: Bool, _ enc: UInt, _ n: Int) { + let str = asciiBase ? bridgedASCIIString : bridgedUTF8String + for _ in 0 ..< n * 100 { + blackHole(str!.lengthOfBytes(using: enc)) + } +} + +@inline(never) +public func run_BridgedNSStringLengthASCII_ASCII(_ n: Int) { + run_BridgedNSStringLength(true, 1 /* NSASCIIStringEncoding */, n) +} + +@inline(never) +public func run_BridgedNSStringLengthASCII_UTF8(_ n: Int) { + run_BridgedNSStringLength(true, 4 /* NSUTF8StringEncoding */, n) +} + +@inline(never) +public func run_BridgedNSStringLengthASCII_UTF16(_ n: Int) { + run_BridgedNSStringLength(true, 10 /* NSUnicodeStringEncoding */, n) +} + +@inline(never) +public func run_BridgedNSStringLengthASCII_MacRoman(_ n: Int) { + run_BridgedNSStringLength(true, 30 /* NSMacOSRomanStringEncoding */, n) +} + +@inline(never) +public func run_BridgedNSStringLengthUTF8_UTF8(_ n: Int) { + run_BridgedNSStringLength(false, 4 /* NSUTF8StringEncoding */, n) +} + +@inline(never) +public func run_BridgedNSStringLengthUTF8_UTF16(_ n: Int) { + run_BridgedNSStringLength(false, 10 /* NSUnicodeStringEncoding */, n) +} diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 9dc517f62b6d7..3e51d48dd17e3 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -324,6 +324,9 @@ function(_add_host_variant_c_compile_flags target) target_compile_definitions(${target} PRIVATE $<$:_LARGEFILE_SOURCE _FILE_OFFSET_BITS=64>) endif() + + target_compile_definitions(${target} PRIVATE + $<$,$>:SWIFT_ENABLE_SWIFT_IN_SWIFT>) endfunction() function(_add_host_variant_link_flags target) @@ -965,6 +968,11 @@ function(add_swift_host_tool executable) endif() endif() + # Opt-out of OpenBSD BTCFI if instructed where it is enforced by default. + if(SWIFT_HOST_VARIANT_SDK STREQUAL "OPENBSD" AND SWIFT_HOST_VARIANT_ARCH STREQUAL "aarch64" AND NOT SWIFT_OPENBSD_BTCFI) + target_link_options(${executable} PRIVATE "LINKER:-z,nobtcfi") + endif() + if(SWIFT_BUILD_SWIFT_SYNTAX) set(extra_relative_rpath "") if(NOT "${ASHT_BOOTSTRAPPING}" STREQUAL "") diff --git a/cmake/modules/DarwinSDKs.cmake b/cmake/modules/DarwinSDKs.cmake index 20d555b74751c..113e0eca9bf95 100644 --- a/cmake/modules/DarwinSDKs.cmake +++ b/cmake/modules/DarwinSDKs.cmake @@ -12,7 +12,7 @@ is_sdk_requested(OSX swift_build_osx) if(swift_build_osx) configure_sdk_darwin( OSX "OS X" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_OSX}" - macosx macosx macos "${SUPPORTED_OSX_ARCHS}") + macosx macosx macos macOS "${SUPPORTED_OSX_ARCHS}") configure_target_variant(OSX-DA "OS X Debug+Asserts" OSX DA "Debug+Asserts") configure_target_variant(OSX-RA "OS X Release+Asserts" OSX RA "Release+Asserts") configure_target_variant(OSX-R "OS X Release" OSX R "Release") @@ -22,16 +22,21 @@ is_sdk_requested(FREESTANDING swift_build_freestanding) if(swift_build_freestanding AND (SWIFT_FREESTANDING_FLAVOR STREQUAL "apple")) set(SWIFT_FREESTANDING_SDK "" CACHE STRING "Which SDK to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_DEPLOYMENT_VERSION "" CACHE STRING + "The deployment version to use when building the FREESTANDING stdlib") set(SWIFT_FREESTANDING_TRIPLE_NAME "" CACHE STRING "Which triple name (e.g. 'none-macho') to use when building the FREESTANDING stdlib") set(SWIFT_FREESTANDING_MODULE_NAME "" CACHE STRING "Which .swiftmodule name (e.g. 'freestanding') to use when building the FREESTANDING stdlib") + set(SWIFT_FREESTANDING_AVAILABILITY_NAME "" CACHE STRING + "Which @availability name (e.g. 'macOS') to use when building the FREESTANDING stdlib") set(SWIFT_FREESTANDING_ARCHS "" CACHE STRING "Which architectures to build when building the FREESTANDING stdlib") configure_sdk_darwin( - FREESTANDING "FREESTANDING" "" + FREESTANDING "FREESTANDING" "${SWIFT_FREESTANDING_DEPLOYMENT_VERSION}" "${SWIFT_FREESTANDING_SDK}" - "${SWIFT_FREESTANDING_TRIPLE_NAME}" "${SWIFT_FREESTANDING_MODULE_NAME}" "${SWIFT_FREESTANDING_ARCHS}") + "${SWIFT_FREESTANDING_TRIPLE_NAME}" "${SWIFT_FREESTANDING_MODULE_NAME}" + "${SWIFT_FREESTANDING_AVAILABILITY_NAME}" "${SWIFT_FREESTANDING_ARCHS}") set(SWIFT_SDK_FREESTANDING_LIB_SUBDIR "freestanding") configure_target_variant(FREESTANDING-DA "FREESTANDING Debug+Asserts" FREESTANDING DA "Debug+Asserts") configure_target_variant(FREESTANDING-RA "FREESTANDING Release+Asserts" FREESTANDING RA "Release+Asserts") @@ -53,7 +58,7 @@ is_sdk_requested(IOS swift_build_ios) if(swift_build_ios) configure_sdk_darwin( IOS "iOS" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_IOS}" - iphoneos ios ios "${SUPPORTED_IOS_ARCHS}") + iphoneos ios ios iOS "${SUPPORTED_IOS_ARCHS}") configure_target_variant(IOS-DA "iOS Debug+Asserts" IOS DA "Debug+Asserts") configure_target_variant(IOS-RA "iOS Release+Asserts" IOS RA "Release+Asserts") configure_target_variant(IOS-R "iOS Release" IOS R "Release") @@ -63,7 +68,7 @@ is_sdk_requested(IOS_SIMULATOR swift_build_ios_simulator) if(swift_build_ios_simulator) configure_sdk_darwin( IOS_SIMULATOR "iOS Simulator" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_IOS}" - iphonesimulator ios ios-simulator + iphonesimulator ios ios-simulator iOS "${SUPPORTED_IOS_SIMULATOR_ARCHS}") configure_target_variant( IOS_SIMULATOR-DA "iOS Debug+Asserts" IOS_SIMULATOR DA "Debug+Asserts") @@ -77,7 +82,7 @@ is_sdk_requested(TVOS swift_build_tvos) if(swift_build_tvos) configure_sdk_darwin( TVOS "tvOS" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS}" - appletvos tvos tvos "${SUPPORTED_TVOS_ARCHS}") + appletvos tvos tvos tvOS "${SUPPORTED_TVOS_ARCHS}") configure_target_variant(TVOS-DA "tvOS Debug+Asserts" TVOS DA "Debug+Asserts") configure_target_variant(TVOS-RA "tvOS Release+Asserts" TVOS RA "Release+Asserts") configure_target_variant(TVOS-R "tvOS Release" TVOS R "Release") @@ -87,7 +92,7 @@ is_sdk_requested(TVOS_SIMULATOR swift_build_tvos_simulator) if(swift_build_tvos_simulator) configure_sdk_darwin( TVOS_SIMULATOR "tvOS Simulator" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS}" - appletvsimulator tvos tvos-simulator + appletvsimulator tvos tvos-simulator tvOS "${SUPPORTED_TVOS_SIMULATOR_ARCHS}") configure_target_variant( TVOS_SIMULATOR-DA "tvOS Debug+Asserts" TVOS_SIMULATOR DA "Debug+Asserts") @@ -101,7 +106,7 @@ is_sdk_requested(WATCHOS swift_build_watchos) if(swift_build_watchos) configure_sdk_darwin( WATCHOS "watchOS" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS}" - watchos watchos watchos "${SUPPORTED_WATCHOS_ARCHS}") + watchos watchos watchos watchOS "${SUPPORTED_WATCHOS_ARCHS}") configure_target_variant(WATCHOS-DA "watchOS Debug+Asserts" WATCHOS DA "Debug+Asserts") configure_target_variant(WATCHOS-RA "watchOS Release+Asserts" WATCHOS RA "Release+Asserts") configure_target_variant(WATCHOS-R "watchOS Release" WATCHOS R "Release") @@ -111,7 +116,7 @@ is_sdk_requested(WATCHOS_SIMULATOR swift_build_watchos_simulator) if(swift_build_watchos_simulator) configure_sdk_darwin( WATCHOS_SIMULATOR "watchOS Simulator" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS}" - watchsimulator watchos watchos-simulator + watchsimulator watchos watchos-simulator watchOS "${SUPPORTED_WATCHOS_SIMULATOR_ARCHS}") configure_target_variant(WATCHOS_SIMULATOR-DA "watchOS Debug+Asserts" WATCHOS_SIMULATOR DA "Debug+Asserts") configure_target_variant(WATCHOS_SIMULATOR-RA "watchOS Release+Asserts" WATCHOS_SIMULATOR RA "Release+Asserts") @@ -122,7 +127,7 @@ is_sdk_requested(XROS swift_build_xros) if(swift_build_xros) configure_sdk_darwin( XROS "xrOS" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_XROS}" - xros xros xros "${SUPPORTED_XROS_ARCHS}") + xros xros xros visionOS "${SUPPORTED_XROS_ARCHS}") configure_target_variant(XROS-DA "xrOS Debug+Asserts" XROS DA "Debug+Asserts") configure_target_variant(XROS-RA "xrOS Release+Asserts" XROS RA "Release+Asserts") configure_target_variant(XROS-R "xrOS Release" XROS R "Release") @@ -132,7 +137,7 @@ is_sdk_requested(XROS_SIMULATOR swift_build_xros_simulator) if(swift_build_xros_simulator) configure_sdk_darwin( XROS_SIMULATOR "xrOS Simulator" "${SWIFT_DARWIN_DEPLOYMENT_VERSION_XROS}" - xrsimulator xros xros-simulator + xrsimulator xros xros-simulator visionOS "${SUPPORTED_XROS_SIMULATOR_ARCHS}") configure_target_variant( diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake index 53036dafcf192..b5d3cff9ebbd3 100644 --- a/cmake/modules/SwiftConfigureSDK.cmake +++ b/cmake/modules/SwiftConfigureSDK.cmake @@ -53,7 +53,7 @@ function(_report_sdk prefix) endforeach() elseif("${prefix}" STREQUAL "ANDROID") if(NOT "${SWIFT_ANDROID_NDK_PATH}" STREQUAL "") - message(STATUS " NDK: $ENV{SWIFT_ANDROID_NDK_PATH}") + message(STATUS " NDK: ${SWIFT_ANDROID_NDK_PATH}") endif() if(NOT "${SWIFT_ANDROID_NATIVE_SYSROOT}" STREQUAL "") message(STATUS " Sysroot: ${SWIFT_ANDROID_NATIVE_SYSROOT}") @@ -136,6 +136,7 @@ endfunction() # deployment_version # Deployment version # xcrun_name # SDK name to use with xcrun # triple_name # The name used in Swift's -triple +# availability_name # The name used in Swift's @availability # architectures # A list of architectures this SDK supports # ) # @@ -165,9 +166,11 @@ endfunction() # SWIFT_SDK_${prefix}_ARCH_${ARCH}_TRIPLE Triple name # SWIFT_SDK_${prefix}_ARCH_${ARCH}_MODULE Module triple name for this SDK # SWIFT_SDK_${prefix}_USE_BUILD_ID Whether to pass --build-id to the linker +# SWIFT_SDK_${prefix}_AVAILABILITY_NAME Name to use in @availability +# macro(configure_sdk_darwin prefix name deployment_version xcrun_name - triple_name module_name architectures) + triple_name module_name availability_name architectures) # Note: this has to be implemented as a macro because it sets global # variables. @@ -201,6 +204,7 @@ macro(configure_sdk_darwin set(SWIFT_SDK_${prefix}_DEPLOYMENT_VERSION "${deployment_version}") set(SWIFT_SDK_${prefix}_LIB_SUBDIR "${xcrun_name}") set(SWIFT_SDK_${prefix}_TRIPLE_NAME "${triple_name}") + set(SWIFT_SDK_${prefix}_AVAILABILITY_NAME "${availability_name}") set(SWIFT_SDK_${prefix}_OBJECT_FORMAT "MACHO") set(SWIFT_SDK_${prefix}_USE_ISYSROOT TRUE) set(SWIFT_SDK_${prefix}_SHARED_LIBRARY_PREFIX "lib") @@ -439,6 +443,8 @@ macro(configure_sdk_unix name architectures) set(SWIFT_SDK_OPENBSD_ARCH_${arch}_TRIPLE "${arch}-unknown-openbsd${openbsd_system_version}") + add_link_options("LINKER:-z,origin") + if(CMAKE_SYSROOT) set(SWIFT_SDK_OPENBSD_ARCH_${arch}_PATH "${CMAKE_SYSROOT}${SWIFT_SDK_OPENBSD_ARCH_${arch}_PATH}" CACHE INTERNAL "sysroot path" FORCE) endif() diff --git a/cmake/modules/SwiftSetIfArchBitness.cmake b/cmake/modules/SwiftSetIfArchBitness.cmake index cbf16c7e754d3..8268b33f4192d 100644 --- a/cmake/modules/SwiftSetIfArchBitness.cmake +++ b/cmake/modules/SwiftSetIfArchBitness.cmake @@ -27,15 +27,15 @@ function(set_if_arch_bitness var_name) "${SIA_ARCH}" STREQUAL "powerpc") set("${var_name}" "${SIA_CASE_32_BIT}" PARENT_SCOPE) elseif("${SIA_ARCH}" STREQUAL "x86_64" OR - "${SIA_ARCH}" STREQUAL "amd64" OR - "${SIA_ARCH}" STREQUAL "arm64" OR - "${SIA_ARCH}" STREQUAL "arm64e" OR - "${SIA_ARCH}" STREQUAL "aarch64" OR - "${SIA_ARCH}" STREQUAL "powerpc64" OR - "${SIA_ARCH}" STREQUAL "powerpc64le" OR - "${SIA_ARCH}" STREQUAL "s390x" OR - "${SIA_ARCH}" STREQUAL "riscv64" OR - "${SIA_ARCH}" STREQUAL "wasm64") + "${SIA_ARCH}" STREQUAL "amd64" OR + "${SIA_ARCH}" STREQUAL "arm64" OR + "${SIA_ARCH}" STREQUAL "arm64e" OR + "${SIA_ARCH}" STREQUAL "aarch64" OR + "${SIA_ARCH}" STREQUAL "powerpc64" OR + "${SIA_ARCH}" STREQUAL "powerpc64le" OR + "${SIA_ARCH}" STREQUAL "s390x" OR + "${SIA_ARCH}" STREQUAL "riscv64" OR + "${SIA_ARCH}" STREQUAL "wasm64") set("${var_name}" "${SIA_CASE_64_BIT}" PARENT_SCOPE) else() message(FATAL_ERROR "Unknown architecture: ${SIA_ARCH}") diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 1dba89461ded3..ba66d9d97bad2 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -331,6 +331,7 @@ with a differentiable function used for differentiable programming. global ::= generic-signature? type 'WOe' // Outlined consume global ::= generic-signature? type 'WOr' // Outlined retain global ::= generic-signature? type 'WOs' // Outlined release + global ::= generic-signature? type 'WOB' // Outlined initializeWithTake, not using value witness global ::= generic-signature? type 'WOb' // Outlined initializeWithTake global ::= generic-signature? type 'WOc' // Outlined initializeWithCopy global ::= generic-signature? type 'WOC' // Outlined initializeWithCopy, not using value witness @@ -761,7 +762,7 @@ Types sending-result ::= 'YT' // -> sending T #endif #if SWIFT_RUNTIME_VERSION >= 6.2 - function-isolation :== 'YC' // @execution(caller) on function type + function-isolation :== 'YC' // nonisolated(nonsending) on function type #endif differentiable ::= 'Yjf' // @differentiable(_forward) on function type differentiable ::= 'Yjr' // @differentiable(reverse) on function type @@ -900,6 +901,15 @@ mangled in to disambiguate. PARAM-CONVENTION ::= 'p' // pack guaranteed PARAM-CONVENTION ::= 'm' // pack inout + #if SWIFT_RUNTIME_VERSION >= 6.0 + SENDING-PARAM ::= 'T' // sending parameter + #endif + + #if SWIFT_RUNTIME_VERSION >= 6.2 + ISOLATED-PARAM ::= 'I' // @isolated parameter + IMPLICIT-LEADING-PARAM ::= 'L' // @implicit_leading parameter + #endif + PARAM-DIFFERENTIABILITY ::= 'w' // @noDerivative RESULT-CONVENTION ::= 'r' // indirect diff --git a/docs/Diagnostics.md b/docs/Diagnostics.md index 6acf30d89160e..3f9743d497e7c 100644 --- a/docs/Diagnostics.md +++ b/docs/Diagnostics.md @@ -38,8 +38,23 @@ Clang also has a kind of diagnostic called a "remark", which represents informat - When applicable, phrase diagnostics as rules rather than reporting that the compiler failed to do something. Example: - - Normal: "cannot call 'super.init' outside of an initializer" - - Better: "'super.init' cannot be called outside of an initializer" + - Normal: `cannot call 'super.init' outside of an initializer` + - Better: `'super.init' cannot be called outside of an initializer` + +- Use `'` to quote attributes, symbol names, and any other text that is + referred to as code or a token. + Some idiomatic Swift tokens, such as `protocol`, by themselves are or appear + in Swift terms of art. + Terms of art are written in plain text and must not be quoted. + If you are not certain whether a Swift token has an associated term of art, + consult the [book]. + For example: + - `'mutating' is only valid on methods`, but + `cannot call mutating method on immutable value`. + - `'@autoclosure' only applies to function types`. + - `subscript access can throw but is not marked with 'try'`. + - `expected '{' after 'defer'`. + - `type 'S' does not conform to protocol 'Sequence'`. - When referring to attributes by name, use *either* "the 'foo' attribute" or "'@foo'", rather than "the '@foo' attribute". @@ -53,6 +68,8 @@ Clang also has a kind of diagnostic called a "remark", which represents informat - If possible, it is best to include the name of the type or function that has the error, e.g. "non-actor type 'Nope' cannot ..." is better than "non-actor type cannot ...". It helps developers relate the error message to the specific type the error is about, even if the error would highlight the appropriate line / function in other ways. +[book]: https://docs.swift.org/swift-book/documentation/the-swift-programming-language + ### Locations and Highlights ### - Diagnostics are always emitted at a particular line and column. Try to be specific. @@ -109,7 +126,7 @@ To add a new diagnostics group: - An entry in a `Diagnostics*.def` file describing the diagnostic. If there are any closely related diagnostics the note should also be attached to, they can usually be found nearby. - Each point in the compiler source where the diagnostic is emitted. This can be helpful in determining the exact circumstances which cause it to be emitted. 4. Add a new Markdown file in the `userdocs/diagnostics/` directory in the swift repository containing the documentation. When writing a note, keep the writing guidelines from the section above in mind. The existing notes in the directory are another useful guide. -5. Create a new entry in `DiagnosticGroups.def` that provides the name for your new diagnostic group along with the name of the file you added in step (4). +5. Create a new entry in `DiagnosticGroups.def` that provides the name for your new diagnostic group along with the name of the file you added in step (4), without an extension. 6. Find each diagnostic you want to make part of this group in the various `Diagnostics*.def` files. For each diagnostic, replace the `ERROR` or `WARNING` with `GROUPED_ERROR` or `GROUPED_WARNING`, respectively, and put the diagnostic group name after the string literal for the diagnostic message. 7. If possible, rebuild the compiler and try recompiling your test program. Your new diagnostic group should appear as `[#]` at the end of the diagnostic, with a link to the diagnostic file. 8. That's it! The new diagnostic group is now ready to be submitted as a pull request on GitHub. diff --git a/docs/ReferenceGuides/UnderscoredAttributes.md b/docs/ReferenceGuides/UnderscoredAttributes.md index 07d66bc5013b9..a9db7c7ea998e 100644 --- a/docs/ReferenceGuides/UnderscoredAttributes.md +++ b/docs/ReferenceGuides/UnderscoredAttributes.md @@ -600,6 +600,43 @@ inherit the actor context (i.e. what actor it should be run on) based on the declaration site of the closure rather than be non-Sendable. This does not do anything if the closure is synchronous. +This works with global actors as expected: + +```swift +@MainActor +func test() { + Task { /* main actor isolated */ } +} +``` + +However, for the inference to work with instance actors (i.e. `isolated` parameters), +the closure must capture the isolated parameter explicitly: + +```swift +func test(actor: isolated (any Actor)) { + Task { /* non isolated */ } // !!! +} + +func test(actor: isolated (any Actor)) { + Task { // @_inheritActorContext + _ = actor // 'actor'-isolated + } +} +``` + +The attribute takes an optional modifier '`always`', which changes this behavior +and *always* captures the enclosing isolated context, rather than forcing developers +to perform the explicit capture themselfes: + +```swift +func test(actor: isolated (any Actor)) { + Task.immediate { // @_inheritActorContext(always) + // 'actor'-isolated! + // (without having to capture 'actor explicitly') + } +} +``` + DISCUSSION: The reason why this does nothing when the closure is synchronous is since it does not have the ability to hop to the appropriate executor before it is run, so we may create concurrency errors. diff --git a/docs/SIL/Instructions.md b/docs/SIL/Instructions.md index 9f9691b964f59..d5b163e530990 100644 --- a/docs/SIL/Instructions.md +++ b/docs/SIL/Instructions.md @@ -2146,6 +2146,22 @@ not replace this reference with a not uniquely reference object. For details see [Copy-on-Write Representation](SIL.md#Copy-on-Write-Representation). +### end_cow_mutation_addr + +``` +sil-instruction ::= 'end_cow_mutation_addr' sil-operand + +end_cow_mutation_addr %0 : $*T +// %0 must be of an address $*T type +``` + +This instruction marks the end of mutation of an address. The address could be +an opaque archetype, a struct, tuple or enum type and the end_cow_mutation_addr +will apply to all members contained within it. +It is currently only generated in cases where we maybe deriving a MutableSpan from +`%0` since it is not possible to schedule an `end_cow_mutation` in the standard +library automatically for Array.mutableSpan etc. + ### destroy_not_escaped_closure ``` @@ -2599,11 +2615,11 @@ except: instead of its normal results. The final (in the case of `@yield_once`) or penultimate (in the case of -`@yield_once_2`) result of a `begin_apply` is a "token", a special -value which can only be used as the operand of an `end_apply` or -`abort_apply` instruction. Before this second instruction is executed, -the coroutine is said to be "suspended", and the token represents a -reference to its suspended activation record. +`@yield_once_2`) result of a `begin_apply` is a "token", a special value which +can only be used as the operand of an `end_apply`, `abort_apply`, or +`end_borrow` instruction. Before this second instruction is executed, the +coroutine is said to be "suspended", and the token represents a reference to its +suspended activation record. If the coroutine's kind `yield_once_2`, its final result is an address of a "token", representing the allocation done by the callee diff --git a/include/swift-c/DependencyScan/DependencyScan.h b/include/swift-c/DependencyScan/DependencyScan.h index b558643cbb850..223816b363661 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 2 -#define SWIFTSCAN_VERSION_MINOR 1 +#define SWIFTSCAN_VERSION_MINOR 2 SWIFTSCAN_BEGIN_DECLS @@ -49,6 +49,9 @@ 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 import info. +typedef struct swiftscan_import_info_s *swiftscan_import_info_t; + /// Opaque container to a macro dependency. typedef struct swiftscan_macro_dependency_s *swiftscan_macro_dependency_t; @@ -76,6 +79,18 @@ typedef struct { size_t count; } swiftscan_link_library_set_t; +/// Set of details about source imports +typedef struct { + swiftscan_import_info_t *imports; + size_t count; +} swiftscan_import_info_set_t; + +/// Set of source location infos +typedef struct { + swiftscan_source_location_t *source_locations; + size_t count; +} swiftscan_source_location_set_t; + /// Set of macro dependency typedef struct { swiftscan_macro_dependency_t *macro_dependencies; @@ -89,6 +104,15 @@ typedef enum { SWIFTSCAN_DIAGNOSTIC_SEVERITY_REMARK = 3 } swiftscan_diagnostic_severity_t; +// Must maintain consistency with swift::AccessLevel +typedef enum { + SWIFTSCAN_ACCESS_LEVEL_PRIVATE = 0, + SWIFTSCAN_ACCESS_LEVEL_FILEPRIVATE = 1, + SWIFTSCAN_ACCESS_LEVEL_INTERNAL = 2, + SWIFTSCAN_ACCESS_LEVEL_PACKAGE = 3, + SWIFTSCAN_ACCESS_LEVEL_PUBLIC = 4 +} swiftscan_access_level_t; + typedef struct { swiftscan_diagnostic_info_t *diagnostics; size_t count; @@ -148,10 +172,23 @@ 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_import_info_set_t * +swiftscan_module_info_get_imports(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 ------------------------------------===// +//=== Import Details Functions -------------------------------------------===// +SWIFTSCAN_PUBLIC swiftscan_source_location_set_t * +swiftscan_import_info_get_source_locations(swiftscan_import_info_t info); + +SWIFTSCAN_PUBLIC swiftscan_string_ref_t +swiftscan_import_info_get_identifier(swiftscan_import_info_t info); + +SWIFTSCAN_PUBLIC swiftscan_access_level_t +swiftscan_import_info_get_access_level(swiftscan_import_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); @@ -212,6 +249,10 @@ SWIFTSCAN_PUBLIC swiftscan_string_set_t * swiftscan_swift_textual_detail_get_swift_overlay_dependencies( swiftscan_module_details_t details); +SWIFTSCAN_PUBLIC swiftscan_string_set_t * +swiftscan_swift_textual_detail_get_swift_source_import_module_dependencies( +swiftscan_module_details_t details); + SWIFTSCAN_PUBLIC swiftscan_string_ref_t swiftscan_swift_textual_detail_get_cas_fs_root_id( swiftscan_module_details_t details); diff --git a/include/swift/ABI/Executor.h b/include/swift/ABI/Executor.h index 1257673826434..4f4fcf8927253 100644 --- a/include/swift/ABI/Executor.h +++ b/include/swift/ABI/Executor.h @@ -17,10 +17,10 @@ #ifndef SWIFT_ABI_EXECUTOR_H #define SWIFT_ABI_EXECUTOR_H -#include #include "swift/ABI/Actor.h" #include "swift/ABI/HeapObject.h" #include "swift/Runtime/Casting.h" +#include namespace swift { class AsyncContext; @@ -77,10 +77,10 @@ class SerialExecutorRef { /// Executor that may need to participate in complex "same context" checks, /// by invoking `isSameExclusiveExecutionContext` when comparing execution contexts. ComplexEquality = 0b01, - /// Mark this executor as the one used by `Task.startSynchronously`, + /// Mark this executor as the one used by `Task.immediate`, /// It cannot participate in switching. // TODO: Perhaps make this a generic "cannot switch" rather than start synchronously specific. - StartSynchronously = 0b10, + Immediate = 0b10, }; static_assert(static_cast(ExecutorKind::Ordinary) == 0); @@ -107,12 +107,12 @@ class SerialExecutorRef { static SerialExecutorRef forSynchronousStart() { auto wtable = reinterpret_cast(nullptr) | - static_cast(ExecutorKind::StartSynchronously); + static_cast(ExecutorKind::Immediate); return SerialExecutorRef(nullptr, wtable); } bool isForSynchronousStart() const { return getIdentity() == nullptr && - getExecutorKind() == ExecutorKind::StartSynchronously; + getExecutorKind() == ExecutorKind::Immediate; } /// Given a pointer to a serial executor and its SerialExecutor @@ -413,6 +413,23 @@ class AsyncFunctionPointer { uint32_t ExpectedContextSize; }; +/// Type-safe wrapper around the return value of `isIsolatingCurrentContext`. +enum class IsIsolatingCurrentContextDecision : int8_t { + // The function call could not determine if the current context is isolated + // by this executor or not. Default value for executors which do not implement + // `isIsolatingCurrentContext`. + Unknown = -1, + // The current context is definitely not isolated by this executor. + NotIsolated = 0, + // The current context is definitely isolated by this executor. + Isolated = 1, +}; + +IsIsolatingCurrentContextDecision +getIsIsolatingCurrentContextDecisionFromInt(int8_t value); + +StringRef getIsIsolatingCurrentContextDecisionNameStr(IsIsolatingCurrentContextDecision decision); + } #endif diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 0789767055800..d2a14e21ca3bf 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -2792,11 +2792,22 @@ using ResilientWitnessesHeader = TargetResilientWitnessesHeader; /// global actor protocol. template struct TargetGlobalActorReference { +private: + using SignedDescriptorPointer = + const TargetProtocolConformanceDescriptor + *__ptrauth_swift_protocol_conformance_descriptor; + +public: /// The type of the global actor. RelativeDirectPointer type; /// The conformance of the global actor to the GlobalActor protocol. - TargetRelativeProtocolConformanceDescriptorPointer conformance; + RelativeIndirectablePointer< + const TargetProtocolConformanceDescriptor, + /*nullable*/ false, + /*offset*/ int32_t, + /*indirect type*/ SignedDescriptorPointer> + conformance; }; /// Describes the context of a protocol conformance that is relevant when @@ -2984,14 +2995,6 @@ struct TargetProtocolConformanceDescriptor final return Demangle::makeSymbolicMangledNameStringRef(this->template getTrailingObjects>()->type); } - /// True if this is a conformance to 'SerialExecutor' which has a non-default - /// (i.e. not the stdlib's default implementation) witness. This means that - /// the developer has implemented this method explicitly and we should prefer - /// calling it. - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext() const { - return Flags.hasNonDefaultSerialExecutorIsIsolatingCurrentContext(); - } - /// Retrieve the protocol conformance of the global actor type to the /// GlobalActor protocol. const TargetProtocolConformanceDescriptor * diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 8007e3ab75e82..df242e7bab056 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -165,18 +165,19 @@ class TargetValueWitnessFlags { // flags for the struct. (The "non-inline" and "has-extra-inhabitants" bits // still require additional fixup.) enum : uint32_t { - AlignmentMask = 0x000000FF, - // unused 0x0000FF00, - IsNonPOD = 0x00010000, - IsNonInline = 0x00020000, - // unused 0x00040000, - HasSpareBits = 0x00080000, - IsNonBitwiseTakable = 0x00100000, - HasEnumWitnesses = 0x00200000, - Incomplete = 0x00400000, - IsNonCopyable = 0x00800000, - IsNonBitwiseBorrowable = 0x01000000, - // unused 0xFE000000, + AlignmentMask = 0x000000FF, + // unused 0x0000FF00, + IsNonPOD = 0x00010000, + IsNonInline = 0x00020000, + // unused 0x00040000, + HasSpareBits = 0x00080000, + IsNonBitwiseTakable = 0x00100000, + HasEnumWitnesses = 0x00200000, + Incomplete = 0x00400000, + IsNonCopyable = 0x00800000, + IsNonBitwiseBorrowable = 0x01000000, + IsAddressableForDependencies = 0x02000000, + // unused 0xFC000000, }; static constexpr const uint32_t MaxNumExtraInhabitants = 0x7FFFFFFF; @@ -268,6 +269,19 @@ class TargetValueWitnessFlags { return TargetValueWitnessFlags((Data & ~IsNonCopyable) | (isCopyable ? 0 : IsNonCopyable)); } + + /// True if values of this type are addressable-for-dependencies, meaning + /// that values of this type should be passed indirectly to functions that + /// produce lifetime-dependent values that could possibly contain pointers + /// to the inline storage of this type. + bool isAddressableForDependencies() const { + return Data & IsAddressableForDependencies; + } + constexpr TargetValueWitnessFlags withAddressableForDependencies(bool afd) const { + return TargetValueWitnessFlags((Data & ~IsAddressableForDependencies) | + (afd ? IsAddressableForDependencies : 0)); + } + /// True if this type's binary representation is that of an enum, and the /// enum value witness table entries are available in this type's value @@ -374,8 +388,6 @@ class MethodDescriptorFlags { Setter, ModifyCoroutine, ReadCoroutine, - Read2Coroutine, - Modify2Coroutine, }; private: @@ -438,23 +450,27 @@ class MethodDescriptorFlags { /// Note that 'init' is not considered an instance member. bool isInstance() const { return Value & IsInstanceMask; } - bool isAsync() const { return Value & IsAsyncMask; } + bool _hasAsyncBitSet() const { return Value & IsAsyncMask; } - bool isCalleeAllocatedCoroutine() const { + bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); } + + bool isCoroutine() const { switch (getKind()) { case Kind::Method: case Kind::Init: case Kind::Getter: case Kind::Setter: + return false; case Kind::ModifyCoroutine: case Kind::ReadCoroutine: - return false; - case Kind::Read2Coroutine: - case Kind::Modify2Coroutine: return true; } } + bool isCalleeAllocatedCoroutine() const { + return isCoroutine() && _hasAsyncBitSet(); + } + bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); } uint16_t getExtraDiscriminator() const { @@ -615,8 +631,6 @@ class ProtocolRequirementFlags { ModifyCoroutine, AssociatedTypeAccessFunction, AssociatedConformanceAccessFunction, - Read2Coroutine, - Modify2Coroutine, }; private: @@ -666,26 +680,30 @@ class ProtocolRequirementFlags { /// Note that 'init' is not considered an instance member. bool isInstance() const { return Value & IsInstanceMask; } - bool isAsync() const { return Value & IsAsyncMask; } + bool _hasAsyncBitSet() const { return Value & IsAsyncMask; } - bool isCalleeAllocatedCoroutine() const { + bool isAsync() const { return !isCoroutine() && _hasAsyncBitSet(); } + + bool isCoroutine() const { switch (getKind()) { case Kind::BaseProtocol: case Kind::Method: case Kind::Init: case Kind::Getter: case Kind::Setter: - case Kind::ReadCoroutine: - case Kind::ModifyCoroutine: case Kind::AssociatedTypeAccessFunction: case Kind::AssociatedConformanceAccessFunction: return false; - case Kind::Read2Coroutine: - case Kind::Modify2Coroutine: + case Kind::ReadCoroutine: + case Kind::ModifyCoroutine: return true; } } + bool isCalleeAllocatedCoroutine() const { + return isCoroutine() && _hasAsyncBitSet(); + } + bool isData() const { return isAsync() || isCalleeAllocatedCoroutine(); } bool isSignedWithAddress() const { @@ -750,14 +768,6 @@ class ConformanceFlags { IsConformanceOfProtocolMask = 0x01u << 18, HasGlobalActorIsolation = 0x01u << 19, - // Used to detect if this is a conformance to SerialExecutor that has - // an user defined implementation of 'isIsolatingCurrentContext'. This - // requirement is special in the sense that if a non-default impl is present - // we will avoid calling the `checkIsolated` method which would lead to a - // crash. In other words, this API "soft replaces" 'checkIsolated' so we - // must at runtime the presence of a non-default implementation. - HasNonDefaultSerialExecutorIsIsolatingCurrentContext = 0x01u << 20, - NumConditionalPackDescriptorsMask = 0xFFu << 24, NumConditionalPackDescriptorsShift = 24 }; @@ -824,15 +834,7 @@ class ConformanceFlags { : 0)); } - ConformanceFlags withHasNonDefaultSerialExecutorIsIsolatingCurrentContext( - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext) const { - return ConformanceFlags((Value & ~HasNonDefaultSerialExecutorIsIsolatingCurrentContext) - | (hasNonDefaultSerialExecutorIsIsolatingCurrentContext - ? HasNonDefaultSerialExecutorIsIsolatingCurrentContext - : 0)); - } - - /// Retrieve the type reference kind kind. + /// Retrieve the type reference kind. TypeReferenceKind getTypeReferenceKind() const { return TypeReferenceKind( (Value & TypeMetadataKindMask) >> TypeMetadataKindShift); @@ -876,10 +878,6 @@ class ConformanceFlags { return Value & HasGlobalActorIsolation; } - bool hasNonDefaultSerialExecutorIsIsolatingCurrentContext() const { - return Value & HasNonDefaultSerialExecutorIsIsolatingCurrentContext; - } - /// Retrieve the # of conditional requirements. unsigned getNumConditionalRequirements() const { return (Value & NumConditionalRequirementsMask) @@ -1761,7 +1759,7 @@ namespace SpecialPointerAuthDiscriminators { const uint16_t AsyncContextParent = 0xbda2; // = 48546 const uint16_t AsyncContextResume = 0xd707; // = 55047 const uint16_t AsyncContextYield = 0xe207; // = 57863 - const uint16_t CancellationNotificationFunction = 0x1933; // = 6451 + const uint16_t CancellationNotificationFunction = 0x0f08; // = 3848 const uint16_t EscalationNotificationFunction = 0x7861; // = 30817 const uint16_t AsyncThinNullaryFunction = 0x0f08; // = 3848 const uint16_t AsyncFutureFunction = 0x720f; // = 29199 @@ -2762,7 +2760,7 @@ class TaskCreateFlags : public FlagSet { /// /// Supported starting in Swift 6.1. Task_IsTaskFunctionConsumed = 15, - Task_IsStartSynchronouslyTask = 16, + Task_IsImmediateTask = 16, }; explicit constexpr TaskCreateFlags(size_t bits) : FlagSet(bits) {} @@ -2795,9 +2793,9 @@ class TaskCreateFlags : public FlagSet { FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsTaskFunctionConsumed, isTaskFunctionConsumed, setIsTaskFunctionConsumed) - FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsStartSynchronouslyTask, - isSynchronousStartTask, - setIsSYnchronousStartTask) + FLAGSET_DEFINE_FLAG_ACCESSORS(Task_IsImmediateTask, + isImmediateTask, + setIsImmediateTask) }; /// Flags for schedulable jobs. diff --git a/include/swift/ABI/Task.h b/include/swift/ABI/Task.h index a81ffdfdfa764..1961ec2514996 100644 --- a/include/swift/ABI/Task.h +++ b/include/swift/ABI/Task.h @@ -29,6 +29,17 @@ #include "bitset" #include "queue" // TODO: remove and replace with our own mpsc +// Does the runtime provide priority escalation support? +#ifndef SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION +#if SWIFT_CONCURRENCY_ENABLE_DISPATCH && \ + __has_include() && __APPLE__ && \ + (defined(__arm64__) || defined(__x86_64__)) +#define SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION 1 +#else +#define SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION 0 +#endif +#endif /* SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION */ + namespace swift { class AsyncTask; class AsyncContext; @@ -301,15 +312,16 @@ class AsyncTask : public Job { #if SWIFT_CONCURRENCY_ENABLE_PRIORITY_ESCALATION && SWIFT_POINTER_IS_4_BYTES static constexpr size_t ActiveTaskStatusSize = 4 * sizeof(void *); #else - static constexpr size_t ActiveTaskStatusSize = 4 * sizeof(void *); + static constexpr size_t ActiveTaskStatusSize = 2 * sizeof(void *); #endif // Private storage is currently 6 pointers, 16 bytes of non-pointer data, - // the ActiveTaskStatus, and a RecursiveMutex. + // 8 bytes of padding, the ActiveTaskStatus, and a RecursiveMutex. static constexpr size_t PrivateStorageSize = - 6 * sizeof(void *) + 16 + ActiveTaskStatusSize + sizeof(RecursiveMutex); + 6 * sizeof(void *) + 16 + 8 + ActiveTaskStatusSize + + sizeof(RecursiveMutex); - void *Storage[PrivateStorageSize]; + char Storage[PrivateStorageSize]; /// Initialize this storage during the creation of a task. void initialize(JobPriority basePri); diff --git a/include/swift/ABI/TaskGroup.h b/include/swift/ABI/TaskGroup.h index b1c821d8e1cba..03f7e101cce06 100644 --- a/include/swift/ABI/TaskGroup.h +++ b/include/swift/ABI/TaskGroup.h @@ -44,6 +44,12 @@ class alignas(Alignment_TaskGroup) TaskGroup { /// Checks the cancellation status of the group. bool isCancelled(); + /// Only mark the task group as cancelled, without performing the follow-up + /// work of cancelling all the child tasks. + /// + /// Returns true if the group was already cancelled before this call. + bool statusCancel(); + // Add a child task to the task group. Always called while holding the // status record lock of the task group's owning task. void addChildTask(AsyncTask *task); diff --git a/include/swift/ABI/TaskStatus.h b/include/swift/ABI/TaskStatus.h index 2d5a3daf5e21d..56718978e8245 100644 --- a/include/swift/ABI/TaskStatus.h +++ b/include/swift/ABI/TaskStatus.h @@ -269,7 +269,7 @@ class CancellationNotificationStatusRecord : public TaskStatusRecord { /// subsequently used. class EscalationNotificationStatusRecord : public TaskStatusRecord { public: - using FunctionType = SWIFT_CC(swift) void(JobPriority, JobPriority, SWIFT_CONTEXT void *); + using FunctionType = SWIFT_CC(swift) void(uint8_t, uint8_t, SWIFT_CONTEXT void *); private: FunctionType *__ptrauth_swift_escalation_notification_function Function; @@ -282,7 +282,10 @@ class EscalationNotificationStatusRecord : public TaskStatusRecord { } void run(JobPriority oldPriority, JobPriority newPriority) { - Function(oldPriority, newPriority, Argument); + Function( + static_cast(oldPriority), + static_cast(newPriority), + Argument); } static bool classof(const TaskStatusRecord *record) { diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 31cce3d1ff0c2..03ff13ae7fac5 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -393,6 +393,7 @@ struct BridgedDeclObj { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj Class_getDestructor() const; BRIDGED_INLINE bool AbstractFunction_isOverridden() const; BRIDGED_INLINE bool Destructor_isIsolated() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef AccessorDecl_getKindName() const; }; enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedASTNodeKind : uint8_t { @@ -910,16 +911,6 @@ void BridgedAvailableAttr_setIsGroupedWithWildcard(BridgedAvailableAttr cAttr); SWIFT_NAME("BridgedAvailableAttr.setIsGroupTerminator(self:)") void BridgedAvailableAttr_setIsGroupTerminator(BridgedAvailableAttr cAttr); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionKind { - BridgedExecutionKindConcurrent, - BridgedExecutionKindCaller, -}; - -SWIFT_NAME("BridgedExecutionAttr.createParsed(_:atLoc:range:behavior:)") -BridgedExecutionAttr BridgedExecutionAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc atLoc, - BridgedSourceRange range, BridgedExecutionKind behavior); - enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedAccessLevel { BridgedAccessLevelPrivate, BridgedAccessLevelFilePrivate, @@ -1086,8 +1077,9 @@ BridgedInlineAttr BridgedInlineAttr_createParsed(BridgedASTContext cContext, enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedParsedLifetimeDependenceKind { BridgedParsedLifetimeDependenceKindDefault, - BridgedParsedLifetimeDependenceKindScope, + BridgedParsedLifetimeDependenceKindBorrow, BridgedParsedLifetimeDependenceKindInherit, + BridgedParsedLifetimeDependenceKindInout }; class BridgedLifetimeDescriptor { @@ -1152,10 +1144,11 @@ BridgedLifetimeEntry BridgedLifetimeEntry_createParsed( BridgedASTContext cContext, BridgedSourceRange cRange, BridgedArrayRef cSources, BridgedLifetimeDescriptor cTarget); -SWIFT_NAME("BridgedLifetimeAttr.createParsed(_:atLoc:range:entry:)") +SWIFT_NAME( + "BridgedLifetimeAttr.createParsed(_:atLoc:range:entry:isUnderscored:)") BridgedLifetimeAttr BridgedLifetimeAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceRange cRange, BridgedLifetimeEntry cEntry); + BridgedSourceRange cRange, BridgedLifetimeEntry cEntry, bool isUnderscored); enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedMacroSyntax { BridgedMacroSyntaxFreestanding, @@ -1234,11 +1227,30 @@ BridgedNonSendableAttr BridgedNonSendableAttr_createParsed( BridgedASTContext cContext, BridgedSourceLoc cAtLoc, BridgedSourceRange cRange, BridgedNonSendableKind cKind); -SWIFT_NAME("BridgedNonisolatedAttr.createParsed(_:atLoc:range:isUnsafe:)") +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonIsolatedModifier { + BridgedNonIsolatedModifierNone, + BridgedNonIsolatedModifierUnsafe, + BridgedNonIsolatedModifierNonSending +}; + +SWIFT_NAME("BridgedNonisolatedAttr.createParsed(_:atLoc:range:modifier:)") BridgedNonisolatedAttr BridgedNonisolatedAttr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceRange cRange, bool isUnsafe); + BridgedSourceRange cRange, + BridgedNonIsolatedModifier modifier); + +enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedInheritActorContextModifier { + BridgedInheritActorContextModifierNone, + BridgedInheritActorContextModifierAlways, +}; + +SWIFT_NAME("BridgedInheritActorContextAttr.createParsed(_:atLoc:range:modifier:)") +BridgedInheritActorContextAttr +BridgedInheritActorContextAttr_createParsed(BridgedASTContext cContext, + BridgedSourceLoc cAtLoc, + BridgedSourceRange cRange, + BridgedInheritActorContextModifier modifier); SWIFT_NAME("BridgedObjCAttr.createParsedUnnamed(_:atLoc:attrNameLoc:)") BridgedObjCAttr @@ -1703,6 +1715,19 @@ BridgedImportDecl BridgedImportDecl_createParsed( BridgedSourceLoc cImportKeywordLoc, BridgedImportKind cImportKind, BridgedSourceLoc cImportKindLoc, BridgedArrayRef cImportPathElements); +enum ENUM_EXTENSIBILITY_ATTR(open) BridgedUsingSpecifier { + BridgedUsingSpecifierMainActor, + BridgedUsingSpecifierNonisolated, +}; + +SWIFT_NAME("BridgedUsingDecl.createParsed(_:declContext:usingKeywordLoc:" + "specifierLoc:specifier:)") +BridgedUsingDecl BridgedUsingDecl_createParsed(BridgedASTContext cContext, + BridgedDeclContext cDeclContext, + BridgedSourceLoc usingKeywordLoc, + BridgedSourceLoc specifierLoc, + BridgedUsingSpecifier specifier); + SWIFT_NAME("BridgedSubscriptDecl.createParsed(_:declContext:staticLoc:" "staticSpelling:subscriptKeywordLoc:genericParamList:parameterList:" "arrowLoc:returnType:genericWhereClause:)") @@ -2589,11 +2614,6 @@ BridgedConventionTypeAttr BridgedConventionTypeAttr_createParsed( BridgedSourceLoc cNameLoc, BridgedDeclNameRef cWitnessMethodProtocol, BridgedStringRef cClangType, BridgedSourceLoc cClangTypeLoc); -enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionTypeAttrExecutionKind { - BridgedExecutionTypeAttrExecutionKind_Concurrent, - BridgedExecutionTypeAttrExecutionKind_Caller -}; - SWIFT_NAME("BridgedDifferentiableTypeAttr.createParsed(_:atLoc:nameLoc:" "parensRange:kind:kindLoc:)") BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( @@ -2601,14 +2621,6 @@ BridgedDifferentiableTypeAttr BridgedDifferentiableTypeAttr_createParsed( BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, BridgedDifferentiabilityKind cKind, BridgedSourceLoc cKindLoc); -SWIFT_NAME("BridgedExecutionTypeAttr.createParsed(_:atLoc:nameLoc:parensRange:" - "behavior:behaviorLoc:)") -BridgedExecutionTypeAttr BridgedExecutionTypeAttr_createParsed( - BridgedASTContext cContext, BridgedSourceLoc cAtLoc, - BridgedSourceLoc cNameLoc, BridgedSourceRange cParensRange, - BridgedExecutionTypeAttrExecutionKind behavior, - BridgedSourceLoc cBehaviorLoc); - SWIFT_NAME("BridgedIsolatedTypeAttr.createParsed(_:atLoc:nameLoc:parensRange:" "isolationKind:isolationKindLoc:)") BridgedIsolatedTypeAttr BridgedIsolatedTypeAttr_createParsed( @@ -2776,6 +2788,12 @@ BridgedSendingTypeRepr_createParsed(BridgedASTContext cContext, BridgedTypeRepr base, BridgedSourceLoc cSpecifierLoc); +SWIFT_NAME("BridgedCallerIsolatedTypeRepr.createParsed(_:base:specifierLoc:)") +BridgedCallerIsolatedTypeRepr +BridgedCallerIsolatedTypeRepr_createParsed(BridgedASTContext cContext, + BridgedTypeRepr base, + BridgedSourceLoc cSpecifierLoc); + SWIFT_NAME( "BridgedTupleTypeRepr.createParsed(_:elements:leftParenLoc:rightParenLoc:)") BridgedTupleTypeRepr BridgedTupleTypeRepr_createParsed( @@ -3057,8 +3075,6 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedMacroDefinitionKind : size_t { BridgedBuiltinExternalMacro, /// The builtin definition for the "isolation" macro. BridgedBuiltinIsolationMacro, - /// The builtin definition for the "SwiftSetting" macro. - BridgedBuiltinSwiftSettingsMacro, }; struct BridgedASTType { @@ -3108,6 +3124,7 @@ struct BridgedASTType { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getBuiltinVectorElementType() const; BRIDGED_INLINE bool isBuiltinFixedWidthInteger(SwiftInt width) const; BRIDGED_INLINE bool isOptional() const; + BRIDGED_INLINE bool isBuiltinType() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getNominalOrBoundGenericNominal() const; BRIDGED_INLINE TraitResult canBeClass() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getAnyNominal() const; diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index ac8d117cc9aef..459ef7bd64ab5 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -531,6 +531,10 @@ bool BridgedASTType::isUnownedStorageType() const { return unbridged()->is(); } +bool BridgedASTType::isBuiltinType() const { + return unbridged()->isBuiltinType(); +} + OptionalBridgedDeclObj BridgedASTType::getNominalOrBoundGenericNominal() const { return {unbridged()->getNominalOrBoundGenericNominal()}; } diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index e980d009d73f5..0ac4b2fedb54d 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -620,7 +620,7 @@ class ASTContext final { /// For example, if '-module-alias Foo=X -module-alias Bar=Y' input is passed in, the aliases Foo and Bar are /// the names of the imported or referenced modules in source files in the main module, and X and Y /// are the real (physical) module names on disk. - void setModuleAliases(const llvm::StringMap &aliasMap); + void setModuleAliases(const llvm::StringMap &aliasMap); /// Adds a given alias to the map of Identifiers between module aliases and /// their actual names. @@ -1090,13 +1090,6 @@ class ASTContext final { /// Retrieve the module interface checker associated with this AST context. ModuleInterfaceChecker *getModuleInterfaceChecker() const; - /// Compute the extra implicit framework search paths on Apple platforms: - /// $SDKROOT/System/Library/Frameworks/ and $SDKROOT/Library/Frameworks/. - std::vector getDarwinImplicitFrameworkSearchPaths() const; - - /// Return a set of all possible filesystem locations where modules can be found. - llvm::StringSet<> getAllModuleSearchPathsSet() const; - /// Load extensions to the given nominal type from the external /// module loaders. /// @@ -1337,10 +1330,10 @@ class ASTContext final { getNormalConformance(Type conformingType, ProtocolDecl *protocol, SourceLoc loc, + TypeRepr *inheritedTypeRepr, DeclContext *dc, ProtocolConformanceState state, - ProtocolConformanceOptions options, - SourceLoc preconcurrencyLoc = SourceLoc()); + ProtocolConformanceOptions options); /// Produce a self-conformance for the given protocol. SelfProtocolConformance * diff --git a/include/swift/AST/ASTContextGlobalCache.h b/include/swift/AST/ASTContextGlobalCache.h index 1925fe7885f03..a57e5bc249f66 100644 --- a/include/swift/AST/ASTContextGlobalCache.h +++ b/include/swift/AST/ASTContextGlobalCache.h @@ -55,6 +55,7 @@ struct WitnessIsolationError { /// Describes an isolation error involving an associated conformance. struct AssociatedConformanceIsolationError { ProtocolConformance *isolatedConformance; + DiagnosticBehavior behavior = DiagnosticBehavior::Unspecified; /// Diagnose this associated conformance isolation error. void diagnose(const NormalProtocolConformance *conformance) const; diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 037cd4e4f732c..8f292e19ab20b 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -453,7 +453,8 @@ class ASTMangler : public Mangler { const ValueDecl *forDecl = nullptr); void appendDeclName( - const ValueDecl *decl, DeclBaseName name = DeclBaseName()); + const ValueDecl *decl, DeclBaseName name = DeclBaseName(), + bool skipLocalDiscriminator = false); GenericTypeParamType *appendAssocType(DependentMemberType *DepTy, GenericSignature sig, diff --git a/include/swift/AST/ASTNode.h b/include/swift/AST/ASTNode.h index 5516762853b48..bab6ad3b3aa0c 100644 --- a/include/swift/AST/ASTNode.h +++ b/include/swift/AST/ASTNode.h @@ -21,6 +21,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerUnion.h" #include "swift/Basic/Debug.h" +#include "swift/Basic/SourceManager.h" #include "swift/AST/TypeAlignments.h" namespace llvm { @@ -98,6 +99,12 @@ namespace swift { return llvm::hash_value(N.getOpaqueValue()); } }; + + /// Find the outermost range that \p range was originally generated from. + /// Returns an invalid source range if \p range wasn't generated from a macro. + SourceRange getUnexpandedMacroRange(const SourceManager &SM, + SourceRange range); + } // namespace swift namespace llvm { diff --git a/include/swift/AST/ASTWalker.h b/include/swift/AST/ASTWalker.h index e8f42599f1f15..f8fed39a1c6fc 100644 --- a/include/swift/AST/ASTWalker.h +++ b/include/swift/AST/ASTWalker.h @@ -603,6 +603,13 @@ class ASTWalker { /// params in AbstractFunctionDecl and NominalTypeDecl. virtual bool shouldWalkIntoGenericParams() { return false; } + /// Whether the walker should walk into any attached CustomAttrs. + virtual bool shouldWalkIntoCustomAttrs() const { + // Default to false currently since some walkers don't handle this case + // well. + return false; + } + /// This method configures how the walker should walk the initializers of /// lazy variables. These initializers are semantically different from other /// initializers in their context and so sometimes should be visited as part diff --git a/include/swift/AST/ActorIsolation.h b/include/swift/AST/ActorIsolation.h index 9d2f60388e90a..af036c944d50a 100644 --- a/include/swift/AST/ActorIsolation.h +++ b/include/swift/AST/ActorIsolation.h @@ -88,21 +88,75 @@ class ActorIsolation { /// Set to true if this was parsed from SIL. unsigned silParsed : 1; - unsigned parameterIndex : 27; + /// The opaque value of an EncodedParameterIndex. + /// Only meaningful for ActorInstance. + unsigned encodedParameterIndex : 27; + + class EncodedParameterIndex { + enum : unsigned { + SpecialIndex_Capture, + SpecialIndex_Self, + NumSpecialIndexes + }; + + /// Either a special index or (parameter index + NumSpecialIndexes). + unsigned value; + + constexpr EncodedParameterIndex(unsigned value) : value(value) {} - ActorIsolation(Kind kind, NominalTypeDecl *actor, unsigned parameterIndex); + public: + static constexpr EncodedParameterIndex parameter(unsigned index) { + return EncodedParameterIndex(NumSpecialIndexes + index); + } + static constexpr EncodedParameterIndex self() { + return EncodedParameterIndex(SpecialIndex_Self); + } + static constexpr EncodedParameterIndex capture() { + return EncodedParameterIndex(SpecialIndex_Capture); + } - ActorIsolation(Kind kind, VarDecl *actor, unsigned parameterIndex); + unsigned getParameterIndex() const { + assert(value >= NumSpecialIndexes); + return value - NumSpecialIndexes; + } + bool isSelf() const { + return value == SpecialIndex_Self; + } + bool isCapture() const { + return value == SpecialIndex_Capture; + } - ActorIsolation(Kind kind, Expr *actor, unsigned parameterIndex); + static EncodedParameterIndex fromOpaqueValue(unsigned value) { + return EncodedParameterIndex(value); + } + unsigned getOpaqueValue() const { + return value; + } + }; + + ActorIsolation(Kind kind, NominalTypeDecl *actor, + EncodedParameterIndex parameterIndex); + + ActorIsolation(Kind kind, VarDecl *actor, + EncodedParameterIndex parameterIndex); + + ActorIsolation(Kind kind, Expr *actor, + EncodedParameterIndex parameterIndex); ActorIsolation(Kind kind, Type globalActor); + EncodedParameterIndex getEncodedParameterIndex() const { + return EncodedParameterIndex::fromOpaqueValue(encodedParameterIndex); + } + public: // No-argument constructor needed for DenseMap use in PostfixCompletion.cpp explicit ActorIsolation(Kind kind = Unspecified, bool isSILParsed = false) : pointer(nullptr), kind(kind), isolatedByPreconcurrency(false), - silParsed(isSILParsed), parameterIndex(0) {} + silParsed(isSILParsed), encodedParameterIndex(0) { + // SIL's use of this has weaker invariants for now. + assert(kind != ActorInstance || isSILParsed); + } static ActorIsolation forUnspecified() { return ActorIsolation(Unspecified); @@ -125,19 +179,22 @@ class ActorIsolation { static ActorIsolation forActorInstanceParameter(NominalTypeDecl *actor, unsigned parameterIndex) { - return ActorIsolation(ActorInstance, actor, parameterIndex + 1); + return ActorIsolation(ActorInstance, actor, + EncodedParameterIndex::parameter(parameterIndex)); } static ActorIsolation forActorInstanceParameter(VarDecl *actor, unsigned parameterIndex) { - return ActorIsolation(ActorInstance, actor, parameterIndex + 1); + return ActorIsolation(ActorInstance, actor, + EncodedParameterIndex::parameter(parameterIndex)); } static ActorIsolation forActorInstanceParameter(Expr *actor, unsigned parameterIndex); static ActorIsolation forActorInstanceCapture(VarDecl *capturedActor) { - return ActorIsolation(ActorInstance, capturedActor, 0); + return ActorIsolation(ActorInstance, capturedActor, + EncodedParameterIndex::capture()); } static ActorIsolation forGlobalActor(Type globalActor) { @@ -153,21 +210,14 @@ class ActorIsolation { static std::optional forSILString(StringRef string) { auto kind = llvm::StringSwitch>(string) - .Case("unspecified", - std::optional(ActorIsolation::Unspecified)) - .Case("actor_instance", - std::optional(ActorIsolation::ActorInstance)) - .Case("nonisolated", - std::optional(ActorIsolation::Nonisolated)) - .Case("nonisolated_unsafe", std::optional( - ActorIsolation::NonisolatedUnsafe)) - .Case("global_actor", - std::optional(ActorIsolation::GlobalActor)) - .Case("global_actor_unsafe", - std::optional(ActorIsolation::GlobalActor)) + .Case("unspecified", ActorIsolation::Unspecified) + .Case("actor_instance", ActorIsolation::ActorInstance) + .Case("nonisolated", ActorIsolation::Nonisolated) + .Case("nonisolated_unsafe", ActorIsolation::NonisolatedUnsafe) + .Case("global_actor", ActorIsolation::GlobalActor) + .Case("global_actor_unsafe", ActorIsolation::GlobalActor) .Case("caller_isolation_inheriting", - std::optional( - ActorIsolation::CallerIsolationInheriting)) + ActorIsolation::CallerIsolationInheriting) .Default(std::nullopt); if (kind == std::nullopt) return std::nullopt; @@ -187,17 +237,22 @@ class ActorIsolation { bool isNonisolatedUnsafe() const { return kind == NonisolatedUnsafe; } /// Retrieve the parameter to which actor-instance isolation applies. - /// - /// Parameter 0 is `self`. - unsigned getActorInstanceParameter() const { + unsigned getActorInstanceParameterIndex() const { assert(getKind() == ActorInstance); - return parameterIndex; + return getEncodedParameterIndex().getParameterIndex(); + } + + /// Given that this is actor instance isolation, is it a capture? + bool isActorInstanceForCapture() const { + assert(getKind() == ActorInstance); + return getEncodedParameterIndex().isCapture(); } /// Returns true if this is an actor-instance isolation that additionally /// applies to the self parameter of a method. bool isActorInstanceForSelfParameter() const { - return getActorInstanceParameter() == 0; + assert(getKind() == ActorInstance); + return getEncodedParameterIndex().isSelf(); } bool isSILParsed() const { return silParsed; } @@ -217,6 +272,10 @@ class ActorIsolation { } } + /// In the debugger return the index for the stored actorInstance pointer + /// union index. Asserts if not an actor instance. + SWIFT_DEBUG_HELPER(unsigned getActorInstanceUnionIndex() const); + NominalTypeDecl *getActor() const; VarDecl *getActorInstance() const; @@ -281,13 +340,13 @@ class ActorIsolation { id.AddPointer(pointer); id.AddBoolean(isolatedByPreconcurrency); id.AddBoolean(silParsed); - id.AddInteger(parameterIndex); + id.AddInteger(encodedParameterIndex); } friend llvm::hash_code hash_value(const ActorIsolation &state) { return llvm::hash_combine(state.kind, state.pointer, state.isolatedByPreconcurrency, state.silParsed, - state.parameterIndex); + state.encodedParameterIndex); } void print(llvm::raw_ostream &os) const; diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 9f6d49eb6bf36..a0e2bf98f2f9a 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -226,8 +226,12 @@ class DeclAttribute : public AttributeBase { isEarlyAdopter : 1 ); - SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, 1, - isUnsafe : 1 + SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, NumNonIsolatedModifierBits, + Modifier : NumNonIsolatedModifierBits + ); + + SWIFT_INLINE_BITFIELD(InheritActorContextAttr, DeclAttribute, NumInheritActorContextKindBits, + Modifier : NumInheritActorContextKindBits ); SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 1+31, @@ -237,8 +241,8 @@ class DeclAttribute : public AttributeBase { NumFeatures : 31 ); - SWIFT_INLINE_BITFIELD(ExecutionAttr, DeclAttribute, NumExecutionKindBits, - Behavior : NumExecutionKindBits + SWIFT_INLINE_BITFIELD(LifetimeAttr, DeclAttribute, 1, + isUnderscored : 1 ); } Bits; // clang-format on @@ -384,21 +388,14 @@ class DeclAttribute : public AttributeBase { /// valid if they match. EquivalentInABIAttr = 1ull << 18, - /// Attribute can be used in an \c \@abi attribute, but must match - /// equivalent on API decl; if omitted, API decl's attribute will be - /// cloned. Use where you would want to use \c EquivalentInABIAttr but - /// repeating the attribute is judged too burdensome. - InferredInABIAttr = 1ull << 19, - /// Use for attributes which are \em only valid on declarations that cannot /// have an \c @abi attribute, such as \c ImportDecl . - UnreachableInABIAttr = 1ull << 20, + UnreachableInABIAttr = 1ull << 19, }; enum : uint64_t { InABIAttrMask = ForbiddenInABIAttr | UnconstrainedInABIAttr - | EquivalentInABIAttr | InferredInABIAttr - | UnreachableInABIAttr + | EquivalentInABIAttr | UnreachableInABIAttr }; LLVM_READNONE @@ -2978,17 +2975,28 @@ class ObjCImplementationAttr final : public DeclAttribute { /// Represents nonisolated modifier. class NonisolatedAttr final : public DeclAttribute { public: - NonisolatedAttr(SourceLoc atLoc, SourceRange range, bool unsafe, - bool implicit) + NonisolatedAttr(SourceLoc atLoc, SourceRange range, + NonIsolatedModifier modifier, bool implicit) : DeclAttribute(DeclAttrKind::Nonisolated, atLoc, range, implicit) { - Bits.NonisolatedAttr.isUnsafe = unsafe; - assert((isUnsafe() == unsafe) && "not enough bits for unsafe state"); + Bits.NonisolatedAttr.Modifier = static_cast(modifier); + assert((getModifier() == modifier) && "not enough bits for modifier"); } - NonisolatedAttr(bool unsafe, bool implicit) - : NonisolatedAttr({}, {}, unsafe, implicit) {} + NonIsolatedModifier getModifier() const { + return static_cast(Bits.NonisolatedAttr.Modifier); + } - bool isUnsafe() const { return Bits.NonisolatedAttr.isUnsafe; } + bool isUnsafe() const { return getModifier() == NonIsolatedModifier::Unsafe; } + bool isNonSending() const { + return getModifier() == NonIsolatedModifier::NonSending; + } + + static NonisolatedAttr * + createImplicit(ASTContext &ctx, + NonIsolatedModifier modifier = NonIsolatedModifier::None) { + return new (ctx) NonisolatedAttr(/*atLoc*/ {}, /*range*/ {}, modifier, + /*implicit=*/true); + } static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Nonisolated; @@ -2996,11 +3004,55 @@ class NonisolatedAttr final : public DeclAttribute { /// Create a copy of this attribute. NonisolatedAttr *clone(ASTContext &ctx) const { - return new (ctx) NonisolatedAttr(AtLoc, Range, isUnsafe(), isImplicit()); + return new (ctx) NonisolatedAttr(AtLoc, Range, getModifier(), isImplicit()); } bool isEquivalent(const NonisolatedAttr *other, Decl *attachedTo) const { - return isUnsafe() == other->isUnsafe(); + return getModifier() == other->getModifier(); + } +}; + +/// Represents @_inheritActorContext modifier. +class InheritActorContextAttr final : public DeclAttribute { +public: + InheritActorContextAttr(SourceLoc atLoc, SourceRange range, + InheritActorContextModifier modifier, bool implicit) + : DeclAttribute(DeclAttrKind::InheritActorContext, atLoc, range, + implicit) { + Bits.InheritActorContextAttr.Modifier = static_cast(modifier); + assert((getModifier() == modifier) && "not enough bits for modifier"); + } + + InheritActorContextModifier getModifier() const { + return static_cast( + Bits.InheritActorContextAttr.Modifier); + } + + bool isAlways() const { + return getModifier() == InheritActorContextModifier::Always; + } + + static InheritActorContextAttr * + createImplicit(ASTContext &ctx, InheritActorContextModifier modifier = + InheritActorContextModifier::None) { + return new (ctx) + InheritActorContextAttr(/*atLoc*/ {}, /*range*/ {}, modifier, + /*implicit=*/true); + } + + static bool classof(const DeclAttribute *DA) { + return DA->getKind() == DeclAttrKind::InheritActorContext; + } + + /// Create a copy of this attribute. + InheritActorContextAttr *clone(ASTContext &ctx) const { + return new (ctx) + InheritActorContextAttr(AtLoc, Range, getModifier(), isImplicit()); + } + + bool isEquivalent(const InheritActorContextAttr *other, + Decl *attachedTo) const { + return getModifier() == other->getModifier(); } }; @@ -3171,26 +3223,33 @@ class LifetimeAttr final : public DeclAttribute { LifetimeEntry *entry; LifetimeAttr(SourceLoc atLoc, SourceRange baseRange, bool implicit, - LifetimeEntry *entry) + LifetimeEntry *entry, bool isUnderscored) : DeclAttribute(DeclAttrKind::Lifetime, atLoc, baseRange, implicit), - entry(entry) {} + entry(entry) { + Bits.LifetimeAttr.isUnderscored = isUnderscored; + } public: static LifetimeAttr *create(ASTContext &context, SourceLoc atLoc, SourceRange baseRange, bool implicit, - LifetimeEntry *entry); + LifetimeEntry *entry, bool isUnderscored); LifetimeEntry *getLifetimeEntry() const { return entry; } + bool isUnderscored() const { return bool(Bits.LifetimeAttr.isUnderscored); } + static bool classof(const DeclAttribute *DA) { return DA->getKind() == DeclAttrKind::Lifetime; } /// Create a copy of this attribute. LifetimeAttr *clone(ASTContext &ctx) const { - return new (ctx) LifetimeAttr(AtLoc, Range, isImplicit(), entry); + return new (ctx) + LifetimeAttr(AtLoc, Range, isImplicit(), entry, isUnderscored()); } + std::string getString() const; + bool isEquivalent(const LifetimeAttr *other, Decl *attachedTo) const; }; @@ -3275,34 +3334,6 @@ class ABIAttr : public DeclAttribute { } }; -class ExecutionAttr : public DeclAttribute { -public: - ExecutionAttr(SourceLoc AtLoc, SourceRange Range, - ExecutionKind behavior, - bool Implicit) - : DeclAttribute(DeclAttrKind::Execution, AtLoc, Range, Implicit) { - Bits.ExecutionAttr.Behavior = static_cast(behavior); - } - - ExecutionAttr(ExecutionKind behavior, bool Implicit) - : ExecutionAttr(/*AtLoc=*/SourceLoc(), /*Range=*/SourceRange(), behavior, - Implicit) {} - - ExecutionKind getBehavior() const { - return static_cast(Bits.ExecutionAttr.Behavior); - } - - static bool classof(const DeclAttribute *DA) { - return DA->getKind() == DeclAttrKind::Execution; - } - - UNIMPLEMENTED_CLONE(ExecutionAttr) - - bool isEquivalent(const ExecutionAttr *other, Decl *attachedTo) const { - return getBehavior() == other->getBehavior(); - } -}; - /// Attributes that may be applied to declarations. class DeclAttributes { /// Linked list of declaration attributes. @@ -3605,13 +3636,23 @@ class SemanticAvailableAttr final { /// The source range of the `introduced:` version component. SourceRange getIntroducedSourceRange() const { return attr->IntroducedRange; } - /// Returns the effective introduction range indicated by this attribute. - /// This may correspond to the version specified by the `introduced:` - /// component (remapped or canonicalized if necessary) or it may be "always" - /// for an attribute indicating availability in a version-less domain. Returns - /// `std::nullopt` if the attribute does not indicate introduction. + /// See `getIntroducedDomainAndRange()`. std::optional - getIntroducedRange(const ASTContext &Ctx) const; + getIntroducedRange(const ASTContext &ctx) const { + if (auto domainAndRange = getIntroducedDomainAndRange(ctx)) + return domainAndRange->getRange(); + return std::nullopt; + } + + /// Returns the effective introduction range indicated by this attribute, + /// along with the domain that it applies to (which may be different than the + /// domain which the attribute was written with if a remap is required). This + /// may correspond to the version specified by the `introduced:` component + /// (remapped or canonicalized if necessary) or it may be "always" for an + /// attribute indicating availability in a version-less domain. Returns + /// `std::nullopt` if the attribute does not indicate introduction. + std::optional + getIntroducedDomainAndRange(const ASTContext &ctx) const; /// The version tuple for the `deprecated:` component. std::optional getDeprecated() const; @@ -3619,13 +3660,23 @@ class SemanticAvailableAttr final { /// The source range of the `deprecated:` version component. SourceRange getDeprecatedSourceRange() const { return attr->DeprecatedRange; } - /// Returns the effective deprecation range indicated by this attribute. - /// This may correspond to the version specified by the `deprecated:` - /// component (remapped or canonicalized if necessary) or it may be "always" - /// for an unconditional deprecation attribute. Returns `std::nullopt` if the - /// attribute does not indicate deprecation. + /// See `getDeprecatedDomainAndRange()`. std::optional - getDeprecatedRange(const ASTContext &Ctx) const; + getDeprecatedRange(const ASTContext &ctx) const { + if (auto domainAndRange = getDeprecatedDomainAndRange(ctx)) + return domainAndRange->getRange(); + return std::nullopt; + } + + /// Returns the effective deprecation range indicated by this attribute, along + /// with the domain that it applies to (which may be different than the domain + /// which the attribute was written with if a remap is required). This may + /// correspond to the version specified by the `deprecated:` component + /// (remapped or canonicalized if necessary) or it may be "always" for an + /// unconditional deprecation attribute. Returns `std::nullopt` if the + /// attribute does not indicate deprecation. + std::optional + getDeprecatedDomainAndRange(const ASTContext &ctx) const; /// The version tuple for the `obsoleted:` component. std::optional getObsoleted() const; @@ -3633,13 +3684,23 @@ class SemanticAvailableAttr final { /// The source range of the `obsoleted:` version component. SourceRange getObsoletedSourceRange() const { return attr->ObsoletedRange; } - /// Returns the effective obsoletion range indicated by this attribute. - /// This always corresponds to the version specified by the `obsoleted:` - /// component (remapped or canonicalized if necessary). Returns `std::nullopt` - /// if the attribute does not indicate obsoletion (note that unavailability is - /// separate from obsoletion. + /// See `getObsoletedDomainAndRange()`. std::optional - getObsoletedRange(const ASTContext &Ctx) const; + getObsoletedRange(const ASTContext &ctx) const { + if (auto domainAndRange = getObsoletedDomainAndRange(ctx)) + return domainAndRange->getRange(); + return std::nullopt; + } + + /// Returns the effective obsoletion range indicated by this attribute, along + /// with the domain that it applies to (which may be different than the domain + /// which the attribute was written with if a remap is required). This always + /// corresponds to the version specified by the `obsoleted:` component + /// (remapped or canonicalized if necessary). Returns `std::nullopt` if the + /// attribute does not indicate obsoletion (note that unavailability is + /// separate from obsoletion. + std::optional + getObsoletedDomainAndRange(const ASTContext &ctx) const; /// Returns the `message:` field of the attribute, or an empty string. StringRef getMessage() const { return attr->Message; } @@ -3762,10 +3823,6 @@ class alignas(1 << AttrAlignInBits) TypeAttribute SWIFT_INLINE_BITFIELD_FULL(IsolatedTypeAttr, TypeAttribute, 8, Kind : 8 ); - - SWIFT_INLINE_BITFIELD_FULL(ExecutionTypeAttr, TypeAttribute, 8, - Behavior : 8 - ); } Bits; // clang-format on @@ -4033,28 +4090,6 @@ class IsolatedTypeAttr : public SimpleTypeAttrWithArgs { void printImpl(ASTPrinter &printer, const PrintOptions &options) const; }; -/// The @execution function type attribute. -class ExecutionTypeAttr : public SimpleTypeAttrWithArgs { - SourceLoc BehaviorLoc; - -public: - ExecutionTypeAttr(SourceLoc atLoc, SourceLoc kwLoc, SourceRange parensRange, - Located behavior) - : SimpleTypeAttr(atLoc, kwLoc, parensRange), BehaviorLoc(behavior.Loc) { - Bits.ExecutionTypeAttr.Behavior = uint8_t(behavior.Item); - } - - ExecutionKind getBehavior() const { - return ExecutionKind(Bits.ExecutionTypeAttr.Behavior); - } - - SourceLoc getBehaviorLoc() const { - return BehaviorLoc; - } - - void printImpl(ASTPrinter &printer, const PrintOptions &options) const; -}; - using TypeOrCustomAttr = llvm::PointerUnion; diff --git a/include/swift/AST/AttrKind.h b/include/swift/AST/AttrKind.h index d56edbc4b6e31..1d1a6226f7a91 100644 --- a/include/swift/AST/AttrKind.h +++ b/include/swift/AST/AttrKind.h @@ -130,14 +130,33 @@ enum class ExternKind: uint8_t { enum : unsigned { NumExternKindBits = countBitsUsed(static_cast(ExternKind::Last_ExternKind)) }; -enum class ExecutionKind : uint8_t { - Concurrent = 0, - Caller, - Last_ExecutionKind = Caller +enum class NonIsolatedModifier : uint8_t { + None = 0, + Unsafe, + NonSending, + Last_NonIsolatedModifier = NonSending }; -enum : unsigned { NumExecutionKindBits = - countBitsUsed(static_cast(ExecutionKind::Last_ExecutionKind)) }; +enum : unsigned { + NumNonIsolatedModifierBits = countBitsUsed( + static_cast(NonIsolatedModifier::Last_NonIsolatedModifier)) +}; + +enum class InheritActorContextModifier : uint8_t { + /// Inherit the actor execution context if the isolated parameter was + /// captured by the closure, context is nonisolated or isolated to a + /// global actor. + None = 0, + /// Always inherit the actor context, even when the isolated parameter + /// for the context is not closed over explicitly. + Always, + Last_InheritActorContextKind = Always +}; + +enum : unsigned { + NumInheritActorContextKindBits = countBitsUsed(static_cast( + InheritActorContextModifier::Last_InheritActorContextKind)) +}; enum class DeclAttrKind : unsigned { #define DECL_ATTR(_, CLASS, ...) CLASS, diff --git a/include/swift/AST/AvailabilityConstraint.h b/include/swift/AST/AvailabilityConstraint.h index ba9e70230dfc1..3505a76bb7c47 100644 --- a/include/swift/AST/AvailabilityConstraint.h +++ b/include/swift/AST/AvailabilityConstraint.h @@ -132,10 +132,10 @@ class AvailabilityConstraint { /// Returns the domain that the constraint applies to. AvailabilityDomain getDomain() const { return getAttr().getDomain(); } - /// Returns the required range for `IntroducedInNewerVersion` requirements, or - /// `std::nullopt` otherwise. - std::optional - getPotentiallyUnavailableRange(const ASTContext &ctx) const; + /// Returns the domain and range (remapped if necessary) in which the + /// constraint must be satisfied. How the range should be interpreted depends + /// on the reason for the constraint. + AvailabilityDomainAndRange getDomainAndRange(const ASTContext &ctx) const; /// Some availability constraints are active for type-checking but cannot /// be translated directly into an `if #available(...)` runtime query. diff --git a/include/swift/AST/AvailabilityDomain.h b/include/swift/AST/AvailabilityDomain.h index 8aa9266115c25..e16f5c6b8057a 100644 --- a/include/swift/AST/AvailabilityDomain.h +++ b/include/swift/AST/AvailabilityDomain.h @@ -32,6 +32,7 @@ namespace swift { class ASTContext; class CustomAvailabilityDomain; +class Decl; class DeclContext; class ModuleDecl; @@ -148,6 +149,11 @@ class AvailabilityDomain final { return AvailabilityDomain(Kind::Embedded); } + /// If `decl` represents an availability domain, returns the corresponding + /// `AvailabilityDomain` value. Otherwise, returns `std::nullopt`. + static std::optional forCustom(Decl *decl, + const ASTContext &ctx); + static AvailabilityDomain forCustom(const CustomAvailabilityDomain *domain) { return AvailabilityDomain(domain); } @@ -203,6 +209,10 @@ class AvailabilityDomain final { /// version ranges. bool isVersioned() const; + /// Returns true if the given version is a valid version number for this + /// domain. It is an error to call this on an un-versioned domain. + bool isVersionValid(const llvm::VersionTuple &version) const; + /// Returns true if availability of the domain can be refined using /// `@available` attributes and `if #available` queries. If not, then the /// domain's availability is fixed by compilation settings. For example, @@ -236,6 +246,10 @@ class AvailabilityDomain final { /// Returns the string to use when printing an `@available` attribute. llvm::StringRef getNameForAttributePrinting() const; + /// Returns the decl that represents the domain, or `nullptr` if the domain + /// does not have a decl. + Decl *getDecl() const; + /// Returns the module that the domain belongs to, if it is a custom domain. ModuleDecl *getModule() const; @@ -253,6 +267,20 @@ class AvailabilityDomain final { /// descendants of the iOS domain. AvailabilityDomain getRootDomain() const; + /// Returns the canonical domain that versions in this domain must be remapped + /// to before making availability comparisons in the current compilation + /// context. Sets \p didRemap to `true` if a remap was required. + const AvailabilityDomain getRemappedDomain(const ASTContext &ctx, + bool &didRemap) const; + + /// Returns the canonical domain that versions in this domain must be remapped + /// to before making availability comparisons in the current compilation + /// context. + const AvailabilityDomain getRemappedDomain(const ASTContext &ctx) const { + bool unused; + return getRemappedDomain(ctx, unused); + } + bool operator==(const AvailabilityDomain &other) const { return storage.getOpaqueValue() == other.storage.getOpaqueValue(); } @@ -307,24 +335,26 @@ class CustomAvailabilityDomain : public llvm::FoldingSetNode { Identifier name; Kind kind; ModuleDecl *mod; + Decl *decl; - CustomAvailabilityDomain(Identifier name, ModuleDecl *mod, Kind kind); + CustomAvailabilityDomain(Identifier name, Kind kind, ModuleDecl *mod, + Decl *decl); public: - static const CustomAvailabilityDomain *get(StringRef name, ModuleDecl *mod, - Kind kind, const ASTContext &ctx); + static const CustomAvailabilityDomain *get(StringRef name, Kind kind, + ModuleDecl *mod, Decl *decl, + const ASTContext &ctx); Identifier getName() const { return name; } Kind getKind() const { return kind; } ModuleDecl *getModule() const { return mod; } + Decl *getDecl() const { return decl; } /// Uniquing for `ASTContext`. static void Profile(llvm::FoldingSetNodeID &ID, Identifier name, - ModuleDecl *mod, Kind kind); + ModuleDecl *mod); - void Profile(llvm::FoldingSetNodeID &ID) const { - Profile(ID, name, mod, kind); - } + void Profile(llvm::FoldingSetNodeID &ID) const { Profile(ID, name, mod); } }; /// Represents either a resolved availability domain or an identifier written @@ -408,6 +438,20 @@ class AvailabilityDomainOrIdentifier { void print(llvm::raw_ostream &os) const; }; +/// Represents an `AvailabilityRange` paired with the `AvailabilityDomain` that +/// the range applies to. +class AvailabilityDomainAndRange { + AvailabilityDomain domain; + AvailabilityRange range; + +public: + AvailabilityDomainAndRange(AvailabilityDomain domain, AvailabilityRange range) + : domain(domain), range(range) {}; + + AvailabilityDomain getDomain() const { return domain; } + AvailabilityRange getRange() const { return range; } +}; + } // end namespace swift namespace llvm { diff --git a/include/swift/AST/AvailabilityInference.h b/include/swift/AST/AvailabilityInference.h index cfc9d871476c4..fa22c08633c4b 100644 --- a/include/swift/AST/AvailabilityInference.h +++ b/include/swift/AST/AvailabilityInference.h @@ -81,11 +81,6 @@ class AvailabilityInference { const SemanticAvailableAttr &attr, const ASTContext &ctx, AvailabilityDomain &domain, llvm::VersionTuple &platformVer); - static void - updateAvailabilityDomainForFallback(const SemanticAvailableAttr &attr, - const ASTContext &ctx, - AvailabilityDomain &domain); - /// For the attribute's before version, update the platform and version /// values to the re-mapped platform's, if using a fallback platform. /// Returns `true` if a remap occured. diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 1d4ad98881ceb..269809e44b791 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -673,6 +673,13 @@ BUILTIN_MISC_OPERATION(ExtractElement, "extractelement", "n", Special) /// InsertElement has type (Vector, T, Int32) -> Vector. BUILTIN_MISC_OPERATION(InsertElement, "insertelement", "n", Special) +/// Select has type either +/// (VecN, VecN, VecN) -> VecN +/// or +/// (Int1, T, T) -> T +/// T must be trivial. +BUILTIN_MISC_OPERATION(Select, "select", "n", Special) + // Shufflevector has type (VecN, VecN, VecM) -> VecM BUILTIN_MISC_OPERATION(ShuffleVector, "shufflevector", "n", Special) diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index 8213540c0a595..d6a07148660d3 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -216,6 +216,9 @@ class ClangModuleLoader : public ModuleLoader { DeclContext *newContext, ClangInheritanceInfo inheritance) = 0; + /// Returnes the original method if \param decl is a clone from a base class + virtual ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) = 0; + /// Emits diagnostics for any declarations named name /// whose direct declaration context is a TU. virtual void diagnoseTopLevelValue(const DeclName &name) = 0; diff --git a/include/swift/AST/Concurrency.h b/include/swift/AST/Concurrency.h index 3d19fa40bbe80..c5e0de233c4b4 100644 --- a/include/swift/AST/Concurrency.h +++ b/include/swift/AST/Concurrency.h @@ -19,6 +19,11 @@ namespace swift { +/// Find the imported module that treats the given nominal type as "preconcurrency", or return `nullptr` +/// if there is no such module. +ModuleDecl *moduleImportForPreconcurrency(NominalTypeDecl *nominal, + const DeclContext *fromDC); + /// Determinate the appropriate diagnostic behavior to used when emitting /// concurrency diagnostics when referencing the given nominal type from the /// given declaration context. diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 5a5d40dc56920..18efc38168122 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -213,7 +213,8 @@ enum class DescriptiveDeclKind : uint8_t { OpaqueResultType, OpaqueVarType, Macro, - MacroExpansion + MacroExpansion, + Using }; /// Describes which spelling was used in the source for the 'static' or 'class' @@ -267,6 +268,16 @@ static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) < "Self Access Kind is too small to fit in SelfAccess kind bits. " "Please expand "); +enum class UsingSpecifier : uint8_t { + MainActor, + Nonisolated, + LastSpecifier = Nonisolated, +}; +enum : unsigned { + NumUsingSpecifierBits = + countBitsUsed(static_cast(UsingSpecifier::LastSpecifier)) +}; + /// Diagnostic printing of \c SelfAccessKind. llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK); @@ -310,6 +321,9 @@ struct OverloadSignature { /// Whether this is a macro. unsigned IsMacro : 1; + /// Whether this is a generic argument. + unsigned IsGenericArg : 1; + /// Whether this signature is part of a protocol extension. unsigned InProtocolExtension : 1; @@ -323,8 +337,10 @@ struct OverloadSignature { OverloadSignature() : UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false), IsVariable(false), IsFunction(false), IsAsyncFunction(false), - IsDistributed(false), InProtocolExtension(false), - InExtensionOfGenericType(false), HasOpaqueReturnType(false) { } + IsDistributed(false), IsEnumElement(false), IsNominal(false), + IsTypeAlias(false), IsMacro(false), IsGenericArg(false), + InProtocolExtension(false), InExtensionOfGenericType(false), + HasOpaqueReturnType(false) { } }; /// Determine whether two overload signatures conflict. @@ -825,6 +841,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated, public Swi NumPathElements : 8 ); + SWIFT_INLINE_BITFIELD(UsingDecl, Decl, NumUsingSpecifierBits, + Specifier : NumUsingSpecifierBits + ); + SWIFT_INLINE_BITFIELD(ExtensionDecl, Decl, 4+1, /// An encoding of the default and maximum access level for this extension. /// The value 4 corresponds to AccessLevel::Public @@ -1149,6 +1169,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated, public Swi /// constructed from a serialized module. bool isInMacroExpansionInContext() const; + /// Whether this declaration is within a macro expansion relative to + /// its decl context, and the macro was attached to a node imported from clang. + bool isInMacroExpansionFromClangHeader() const; + /// Returns the appropriate kind of entry point to generate for this class, /// based on its attributes. /// @@ -2040,7 +2064,8 @@ class ExtensionDecl final : public GenericContext, public Decl, NominalTypeDecl *getExtendedNominal() const; /// Compute the nominal type declaration that is being extended. - NominalTypeDecl *computeExtendedNominal() const; + NominalTypeDecl *computeExtendedNominal( + bool excludeMacroExpansions=false) const; /// \c hasBeenBound means nothing if this extension can never been bound /// because it is not at the top level. @@ -2110,7 +2135,10 @@ class ExtensionDecl final : public GenericContext, public Decl, /// Determine whether this extension context is in the same defining module as /// the original nominal type context. - bool isInSameDefiningModule() const; + /// + /// \param RespectOriginallyDefinedIn Whether to respect + /// \c @_originallyDefinedIn attributes or the actual location of the decls. + bool isInSameDefiningModule(bool RespectOriginallyDefinedIn = true) const; /// Determine whether this extension is equivalent to one that requires at /// at least some constraints to be written in the source. @@ -2287,6 +2315,7 @@ class PatternBindingEntry { // Flags::Checked. friend class PatternBindingEntryRequest; friend class PatternBindingCheckedAndContextualizedInitRequest; + friend class PatternBindingCaptureInfoRequest; bool isFullyValidated() const { return InitContextAndFlags.getInt().contains( @@ -2435,8 +2464,20 @@ class PatternBindingEntry { /// from the source range. SourceRange getSourceRange(bool omitAccessors = false) const; - CaptureInfo getCaptureInfo() const { return Captures; } - void setCaptureInfo(CaptureInfo captures) { Captures = captures; } + /// Retrieve the computed capture info, or \c nullopt if it hasn't been + /// computed yet. + std::optional getCachedCaptureInfo() const { + if (!Captures.hasBeenComputed()) + return std::nullopt; + + return Captures; + } + + void setCaptureInfo(CaptureInfo captures) { + ASSERT(!Captures.hasBeenComputed()); + ASSERT(captures.hasBeenComputed()); + Captures = captures; + } private: SourceLoc getLastAccessorEndLoc() const; @@ -2460,6 +2501,7 @@ class PatternBindingDecl final : public Decl, friend class Decl; friend class PatternBindingEntryRequest; friend class PatternBindingCheckedAndContextualizedInitRequest; + friend class PatternBindingCaptureInfoRequest; SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present. SourceLoc VarLoc; ///< Location of the 'var' keyword. @@ -2639,13 +2681,9 @@ class PatternBindingDecl final : public Decl, getMutablePatternList()[i].setInitContext(init); } - CaptureInfo getCaptureInfo(unsigned i) const { - return getPatternList()[i].getCaptureInfo(); - } - - void setCaptureInfo(unsigned i, CaptureInfo captures) { - getMutablePatternList()[i].setCaptureInfo(captures); - } + /// Retrieve the capture info for the initializer at the given index, + /// computing if needed. + CaptureInfo getCaptureInfo(unsigned i) const; /// Given that this PBD is the parent pattern for the specified VarDecl, /// return the entry of the VarDecl in our PatternList. For example, in: @@ -6232,10 +6270,16 @@ class AbstractStorageDecl : public ValueDecl { bool forConformance=false) const; /// Determine how this storage declaration should actually be accessed. - AccessStrategy getAccessStrategy(AccessSemantics semantics, - AccessKind accessKind, ModuleDecl *module, - ResilienceExpansion expansion, - bool useOldABI) const; + AccessStrategy getAccessStrategy( + AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module, + ResilienceExpansion expansion, + std::optional> location, + bool useOldABI) const; + + /// Whether access is via physical storage. + bool isAccessedViaPhysicalStorage(AccessSemantics semantics, + AccessKind accessKind, ModuleDecl *module, + ResilienceExpansion expansion) const; /// Do we need to use resilient access patterns outside of this /// property's resilience domain? @@ -6256,9 +6300,12 @@ class AbstractStorageDecl : public ValueDecl { /// Otherwise, its override must be referenced. bool isValidKeyPathComponent() const; - /// True if the storage exports a property descriptor for key paths in - /// other modules. - bool exportsPropertyDescriptor() const; + /// If the storage exports a property descriptor for key paths in other + /// modules, this returns the generic signature in which its member methods + /// are emitted. If the storage does not export a property descriptor, + /// returns `std::nullopt`. + std::optional + getPropertyDescriptorGenericSignature() const; /// True if any of the accessors to the storage is private or fileprivate. bool hasPrivateAccessor() const; @@ -6895,6 +6942,9 @@ class ParamDecl : public VarDecl { /// Whether or not this parameter is 'sending'. IsSending = 1 << 4, + + /// Whether or not this parameter is isolated to a caller. + IsCallerIsolated = 1 << 5, }; /// The type repr and 3 bits used for flags. @@ -6972,6 +7022,10 @@ class ParamDecl : public VarDecl { /// Create a an identical copy of this ParamDecl. static ParamDecl *clone(const ASTContext &Ctx, ParamDecl *PD); + static ParamDecl *cloneAccessor(const ASTContext &Ctx, + ParamDecl const *subscriptParam, + DeclContext *Parent); + static ParamDecl * createImplicit(ASTContext &Context, SourceLoc specifierLoc, SourceLoc argumentNameLoc, Identifier argumentName, @@ -7183,6 +7237,18 @@ class ParamDecl : public VarDecl { removeFlag(Flag::IsSending); } + /// Whether or not this parameter is marked with 'nonisolated(nonsending)'. + bool isCallerIsolated() const { + return getOptions().contains(Flag::IsCallerIsolated); + } + + void setCallerIsolated(bool value = true) { + if (value) + addFlag(Flag::IsCallerIsolated); + else + removeFlag(Flag::IsCallerIsolated); + } + /// Whether or not this parameter is marked with '@_addressable'. bool isAddressable() const { return getOptions().contains(Flag::IsAddressable); @@ -8139,8 +8205,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl { return cast_or_null(ValueDecl::getOverriddenDecl()); } - std::optional getExecutionBehavior() const; - /// Whether the declaration is later overridden in the module /// /// Overrides are resolved during type checking; only query this field after @@ -8719,7 +8783,8 @@ class EnumCaseDecl final : public Decl, /// EnumCaseDecl. class EnumElementDecl : public DeclContext, public ValueDecl { friend class EnumRawValuesRequest; - + friend class LifetimeDependenceInfoRequest; + /// This is the type specified with the enum element, for /// example 'Int' in 'case Y(Int)'. This is null if there is no type /// associated with this element, as in 'case Z' or in all elements of enum @@ -8731,6 +8796,11 @@ class EnumElementDecl : public DeclContext, public ValueDecl { /// The raw value literal for the enum element, or null. LiteralExpr *RawValueExpr; +protected: + struct { + unsigned NoLifetimeDependenceInfo : 1; + } LazySemanticInfo = {}; + public: EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name, ParameterList *Params, @@ -9693,6 +9763,34 @@ class MacroExpansionDecl : public Decl, public FreestandingMacroExpansion { } }; +/// UsingDecl - This represents a single `using` declaration, e.g.: +/// using @MainActor +class UsingDecl : public Decl { + friend class Decl; + +private: + SourceLoc UsingLoc, SpecifierLoc; + + UsingDecl(SourceLoc usingLoc, SourceLoc specifierLoc, + UsingSpecifier specifier, DeclContext *parent); + +public: + UsingSpecifier getSpecifier() const { + return static_cast(Bits.UsingDecl.Specifier); + } + + std::string getSpecifierName() const; + + SourceLoc getLocFromSource() const { return UsingLoc; } + SourceRange getSourceRange() const { return {UsingLoc, SpecifierLoc}; } + + static UsingDecl *create(ASTContext &ctx, SourceLoc usingLoc, + SourceLoc specifierLoc, UsingSpecifier specifier, + DeclContext *parent); + + static bool classof(const Decl *D) { return D->getKind() == DeclKind::Using; } +}; + inline void AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) { Accessors.setInt(accessLevel); diff --git a/include/swift/AST/DeclAttr.def b/include/swift/AST/DeclAttr.def index 654d9cf221688..ba2e8c28a28c6 100644 --- a/include/swift/AST/DeclAttr.def +++ b/include/swift/AST/DeclAttr.def @@ -143,7 +143,7 @@ SIMPLE_DECL_ATTR(NSManaged, NSManaged, CONTEXTUAL_SIMPLE_DECL_ATTR(lazy, Lazy, OnVar, - DeclModifier | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + DeclModifier | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | UnconstrainedInABIAttr, 16) SIMPLE_DECL_ATTR(LLDBDebuggerFunction, LLDBDebuggerFunction, @@ -163,7 +163,7 @@ SIMPLE_DECL_ATTR(unsafe_no_objc_tagged_pointer, UnsafeNoObjCTaggedPointer, DECL_ATTR(inline, Inline, OnVar | OnSubscript | OnAbstractFunction, - ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 20) DECL_ATTR(_semantics, Semantics, @@ -193,7 +193,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(postfix, Postfix, SIMPLE_DECL_ATTR(_transparent, Transparent, OnFunc | OnAccessor | OnConstructor | OnVar | OnDestructor, - UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 26) SIMPLE_DECL_ATTR(requires_stored_property_inits, RequiresStoredPropertyInits, @@ -216,7 +216,7 @@ SIMPLE_DECL_ATTR(_fixed_layout, FixedLayout, SIMPLE_DECL_ATTR(inlinable, Inlinable, OnVar | OnSubscript | OnAbstractFunction, - ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 32) DECL_ATTR(_specialize, Specialize, @@ -455,7 +455,7 @@ DECL_ATTR(_dynamicReplacement, DynamicReplacement, SIMPLE_DECL_ATTR(_borrowed, Borrowed, OnVar | OnSubscript, - UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 81) DECL_ATTR(_private, PrivateImport, @@ -465,7 +465,7 @@ DECL_ATTR(_private, PrivateImport, SIMPLE_DECL_ATTR(_alwaysEmitIntoClient, AlwaysEmitIntoClient, OnVar | OnSubscript | OnAbstractFunction, - UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | InferredInABIAttr, + UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 83) SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly, @@ -619,9 +619,10 @@ SIMPLE_DECL_ATTR(_implicitSelfCapture, ImplicitSelfCapture, UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove | ForbiddenInABIAttr, 115) -SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext, +DECL_ATTR(_inheritActorContext, InheritActorContext, OnParam, - UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove | ForbiddenInABIAttr, + // since the _inheritActorContext(always) forces an actor capture, it changes ABI of the closure this applies to + UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, 116) SIMPLE_DECL_ATTR(_eagerMove, EagerMove, @@ -832,7 +833,7 @@ SIMPLE_DECL_ATTR(sensitive, Sensitive, 159) SIMPLE_DECL_ATTR(unsafe, Unsafe, - OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType | OnExtension | OnTypeAlias | OnEnumElement, + OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType | OnExtension | OnTypeAlias | OnEnumElement | OnImport, UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 160) @@ -840,6 +841,7 @@ DECL_ATTR(lifetime, Lifetime, OnAccessor | OnConstructor | OnFunc | OnSubscript, LongAttribute | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | AllowMultipleAttributes | EquivalentInABIAttr, 161) +DECL_ATTR_ALIAS(_lifetime, Lifetime) SIMPLE_DECL_ATTR(_addressableSelf, AddressableSelf, OnAccessor | OnConstructor | OnFunc | OnSubscript, @@ -860,13 +862,8 @@ DECL_ATTR(abi, ABI, OnConstructor | OnFunc | OnSubscript | OnVar, LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr, 165) -DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute) -DECL_ATTR(execution, Execution, - OnFunc | OnConstructor | OnSubscript | OnVar, - ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, - 166) -DECL_ATTR_FEATURE_REQUIREMENT(Execution, ExecutionAttribute) +// Unused '166': Used to be `@execution(caller | concurrent)` replaced with `@concurrent` and `nonisolated(nonsending)` SIMPLE_DECL_ATTR(const, ConstVal, OnParam | OnVar | OnFunc, @@ -879,7 +876,12 @@ SIMPLE_DECL_ATTR(constInitialized, ConstInitialized, 168) DECL_ATTR_FEATURE_REQUIREMENT(ConstInitialized, CompileTimeValues) -LAST_DECL_ATTR(ConstInitialized) +SIMPLE_DECL_ATTR(concurrent, Concurrent, + OnFunc | OnConstructor | OnSubscript | OnVar, + ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UnconstrainedInABIAttr, + 170) + +LAST_DECL_ATTR(Concurrent) #undef DECL_ATTR_ALIAS #undef CONTEXTUAL_DECL_ATTR_ALIAS diff --git a/include/swift/AST/DeclExportabilityVisitor.h b/include/swift/AST/DeclExportabilityVisitor.h index 6eb9c46c928d9..732113d55a056 100644 --- a/include/swift/AST/DeclExportabilityVisitor.h +++ b/include/swift/AST/DeclExportabilityVisitor.h @@ -158,6 +158,7 @@ class DeclExportabilityVisitor UNREACHABLE(MissingMember); UNREACHABLE(GenericTypeParam); UNREACHABLE(Param); + UNREACHABLE(Using); #undef UNREACHABLE diff --git a/include/swift/AST/DeclNodes.def b/include/swift/AST/DeclNodes.def index 2f02c4bf5aac8..ef83c8a92777f 100644 --- a/include/swift/AST/DeclNodes.def +++ b/include/swift/AST/DeclNodes.def @@ -190,6 +190,7 @@ DECL(Missing, Decl) DECL(MissingMember, Decl) DECL(PatternBinding, Decl) DECL(EnumCase, Decl) +DECL(Using, Decl) ABSTRACT_DECL(Operator, Decl) OPERATOR_DECL(InfixOperator, OperatorDecl) diff --git a/include/swift/AST/DiagnosticBridge.h b/include/swift/AST/DiagnosticBridge.h index b110f530e9b6b..81a161aa3a549 100644 --- a/include/swift/AST/DiagnosticBridge.h +++ b/include/swift/AST/DiagnosticBridge.h @@ -46,6 +46,10 @@ class DiagnosticBridge { void enqueueDiagnostic(SourceManager &SM, const DiagnosticInfo &Info, unsigned innermostBufferID); + /// Emit a single diagnostic without location information. + void emitDiagnosticWithoutLocation( + const DiagnosticInfo &Info, llvm::raw_ostream &out, bool forceColors); + /// Flush all enqueued diagnostics. void flush(llvm::raw_ostream &OS, bool includeTrailingBreak, bool forceColors); diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 56c9868b0593a..949a9f73d5f7b 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -767,6 +767,17 @@ namespace swift { return limitBehaviorUntilSwiftVersion(limit, languageMode); } + /// Limit the diagnostic behavior to warning until the next future + /// language mode. + /// + /// This should be preferred over passing the next major version to + /// `warnUntilSwiftVersion` to make it easier to find and update clients + /// when a new language mode is introduced. + /// + /// This helps stage in fixes for stricter diagnostics as warnings + /// until the next major language version. + InFlightDiagnostic &warnUntilFutureSwiftVersion(); + /// Limit the diagnostic behavior to warning until the specified version. /// /// This helps stage in fixes for stricter diagnostics as warnings @@ -841,9 +852,6 @@ namespace swift { static const char *fixItStringFor(const FixItID id); - /// Get the best location where an 'import' fixit might be offered. - SourceLoc getBestAddImportFixItLoc(const Decl *Member) const; - /// Add a token-based replacement fix-it to the currently-active /// diagnostic. template @@ -987,7 +995,10 @@ namespace swift { /// Figure out the Behavior for the given diagnostic, taking current /// state such as fatality into account. - DiagnosticBehavior determineBehavior(const Diagnostic &diag); + DiagnosticBehavior determineBehavior(const Diagnostic &diag) const; + + /// Updates the diagnostic state for a diagnostic to emit. + void updateFor(DiagnosticBehavior behavior); bool hadAnyError() const { return anyErrorOccurred; } bool hasFatalErrorOccurred() const { return fatalErrorOccurred; } @@ -1015,7 +1026,7 @@ namespace swift { /// Returns a Boolean value indicating whether warnings belonging to the /// diagnostic group identified by `id` should be escalated to errors. - bool getWarningsAsErrorsForDiagGroupID(DiagGroupID id) { + bool getWarningsAsErrorsForDiagGroupID(DiagGroupID id) const { return warningsAsErrors[(unsigned)id]; } @@ -1561,11 +1572,7 @@ namespace swift { SourceLoc getDefaultDiagnosticLoc() const { return bufferIndirectlyCausingDiagnostic; } - SourceLoc getBestAddImportFixItLoc(const Decl *Member, - SourceFile *sourceFile) const; - SourceLoc getBestAddImportFixItLoc(const Decl *Member) const { - return getBestAddImportFixItLoc(Member, nullptr); - } + SourceLoc getBestAddImportFixItLoc(SourceFile *sf) const; }; inline SourceManager &InFlightDiagnostic::getSourceManager() { diff --git a/include/swift/AST/DiagnosticGroups.def b/include/swift/AST/DiagnosticGroups.def index 0b93805b8f417..8972554df073a 100644 --- a/include/swift/AST/DiagnosticGroups.def +++ b/include/swift/AST/DiagnosticGroups.def @@ -12,6 +12,24 @@ // // This file defines diagnostic groups and links between them. // +// The GROUP(Name, Filename) macro is used to define each diagnostic group. +// These groups are used to associate documentation with particular set of +// diagnostics and also to provide more control over whether the warnings +// in the group are escalated to errors (via the -Wwarning and -Werror flags.) +// A given warning or error can be associated with a diagnostic group by using +// GROUPED_WARNING or GROUPED_ERROR, respectively. New warnings and errors +// should be introduced along with groups to improve documentation. +// +// - Name: the name of the group that will be shown in diagnostic messages +// (e.g., StrictMemorySafety) and used in command-line options like +// -Wwarning and -Werror. Once assigned, the group name for a particular +// diagnostic should not be changed, because it will affect existing users +// of the command-line flags. +// - Filename: the name of the file that provides documentation for this +// diagnostic group. There should be a corresponding Markdown file in +// userdocs/diagnostics providing short-form documentation that helps +// explain the diagnostic and how to resolve the problem. +// //===----------------------------------------------------------------------===// #define DEFINE_DIAGNOSTIC_GROUPS_MACROS @@ -22,31 +40,37 @@ GROUP(no_group, "") -GROUP(ActorIsolatedCall, "actor-isolated-call.md") -GROUP(AsyncCallerExecution, "async-caller-execution.md") -GROUP(ConformanceIsolation, "conformance-isolation.md") -GROUP(DeprecatedDeclaration, "deprecated-declaration.md") -GROUP(DynamicCallable, "dynamic-callable-requirements.md") -GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version.md") -GROUP(ExistentialAny, "existential-any.md") -GROUP(ExistentialMemberAccess, "existential-member-access-limitations.md") -GROUP(IsolatedConformances, "isolated-conformances.md") -GROUP(MultipleInheritance, "multiple-inheritance.md") -GROUP(MutableGlobalVariable, "mutable-global-variable.md") -GROUP(NominalTypes, "nominal-types.md") -GROUP(OpaqueTypeInference, "opaque-type-inference.md") -GROUP(PreconcurrencyImport, "preconcurrency-import.md") -GROUP(PropertyWrappers, "property-wrapper-requirements.md") -GROUP(ProtocolTypeNonConformance, "protocol-type-non-conformance.md") -GROUP(ResultBuilderMethods, "result-builder-methods.md") -GROUP(SendableClosureCaptures, "sendable-closure-captures.md") -GROUP(SendingRisksDataRace, "sending-risks-data-race.md") -GROUP(StrictLanguageFeatures, "strict-language-features.md") -GROUP(StrictMemorySafety, "strict-memory-safety.md") -GROUP(StringInterpolationConformance, "string-interpolation-conformance.md") -GROUP(TemporaryPointers, "temporary-pointers.md") -GROUP(TrailingClosureMatching, "trailing-closure-matching.md") -GROUP(UnknownWarningGroup, "unknown-warning-group.md") +GROUP(ActorIsolatedCall, "actor-isolated-call") +GROUP(AvailabilityUnrecognizedName, "availability-unrecognized-name") +GROUP(ClangDeclarationImport, "clang-declaration-import") +GROUP(ConformanceIsolation, "conformance-isolation") +GROUP(DeprecatedDeclaration, "deprecated-declaration") +GROUP(DynamicCallable, "dynamic-callable-requirements") +GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version") +GROUP(ExistentialAny, "existential-any") +GROUP(ExistentialMemberAccess, "existential-member-access-limitations") +GROUP(ImplementationOnlyDeprecated, "implementation-only-deprecated") +GROUP(IsolatedConformances, "isolated-conformances") +GROUP(MemberImportVisibility, "member-import-visibility") +GROUP(MissingModuleOnKnownPaths, "missing-module-on-known-paths") +GROUP(MultipleInheritance, "multiple-inheritance") +GROUP(MutableGlobalVariable, "mutable-global-variable") +GROUP(NominalTypes, "nominal-types") +GROUP(NonisolatedNonsendingByDefault, "nonisolated-nonsending-by-default") +GROUP(OpaqueTypeInference, "opaque-type-inference") +GROUP(PreconcurrencyImport, "preconcurrency-import") +GROUP(PropertyWrappers, "property-wrapper-requirements") +GROUP(ProtocolTypeNonConformance, "protocol-type-non-conformance") +GROUP(ResultBuilderMethods, "result-builder-methods") +GROUP(SendableClosureCaptures, "sendable-closure-captures") +GROUP(SendableMetatypes, "sendable-metatypes") +GROUP(SendingRisksDataRace, "sending-risks-data-race") +GROUP(StrictLanguageFeatures, "strict-language-features") +GROUP(StrictMemorySafety, "strict-memory-safety") +GROUP(StringInterpolationConformance, "string-interpolation-conformance") +GROUP(TemporaryPointers, "temporary-pointers") +GROUP(TrailingClosureMatching, "trailing-closure-matching") +GROUP(UnknownWarningGroup, "unknown-warning-group") #define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS #include "swift/AST/DefineDiagnosticGroupsMacros.h" diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index d6f27a807cbcb..8ab826cc04839 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -51,10 +51,10 @@ ERROR(emit_pcm_error,Fatal, ERROR(dump_pcm_error,Fatal, "failed to dump precompiled module '%0'", (StringRef)) -WARNING(invalid_swift_name_method,none, +GROUPED_WARNING(invalid_swift_name_method, ClangDeclarationImport, none, "too %select{few|many}0 parameters in swift_name attribute (expected %1; " "got %2)", (bool, unsigned, unsigned)) -WARNING(invalid_swift_name_for_decl,none, +GROUPED_WARNING(invalid_swift_name_for_decl, ClangDeclarationImport, none, "custom Swift name '%0' ignored because it is not valid for %kindonly1; " "imported as %1 instead", (StringRef, ValueDecl *)) @@ -67,20 +67,20 @@ ERROR(swift_name_protocol_static, none, "swift_name cannot be used to define " ERROR(swift_name_no_prototype, none, "swift_name cannot be used on a non-prototyped function declaration", ()) -WARNING(inconsistent_swift_name,none, +GROUPED_WARNING(inconsistent_swift_name, ClangDeclarationImport, none, "inconsistent Swift name for Objective-C %select{method|property}0 " "'%1' in '%2' (%3 in '%4' vs. %5 in '%6')", (bool, StringRef, StringRef, DeclName, StringRef, DeclName, StringRef)) -WARNING(swift_name_circular_context_import,none, +GROUPED_WARNING(swift_name_circular_context_import, ClangDeclarationImport, none, "cycle detected while resolving '%0' in swift_name attribute for '%1'", (StringRef, StringRef)) NOTE(swift_name_circular_context_import_other,none, "while resolving '%0' in swift_name attribute for '%1'", (StringRef, StringRef)) -WARNING(unresolvable_clang_decl,none, +GROUPED_WARNING(unresolvable_clang_decl, ClangDeclarationImport, none, "imported declaration '%0' could not be mapped to '%1'", (StringRef, StringRef)) @@ -88,38 +88,35 @@ NOTE(unresolvable_clang_decl_is_a_framework_bug,none, "please report this issue to the owners of '%0'", (StringRef)) -WARNING(clang_swift_attr_unhandled,none, +GROUPED_WARNING(clang_swift_attr_unhandled, ClangDeclarationImport, none, "ignoring unknown Swift attribute or modifier '%0'", (StringRef)) -WARNING(clang_error_code_must_be_sendable,none, - "cannot make error code type '%0' non-sendable because Swift errors " +GROUPED_WARNING(clang_error_code_must_be_sendable, ClangDeclarationImport, none, + "cannot make error code type '%0' non-Sendable because Swift errors " "are always sendable", (StringRef)) -WARNING(clang_ignored_sendable_attr,none, +GROUPED_WARNING(clang_ignored_sendable_attr, ClangDeclarationImport, none, "cannot make type %0 sendable because '@Sendable' and '& Sendable' " "cannot be added to it", (Type)) -NOTE(clang_param_should_be_implicitly_sendable,none, - "parameter should be implicitly 'Sendable' because it is a completion " - "handler", ()) WARNING(implicit_bridging_header_imported_from_module,none, "implicit import of bridging header '%0' via module %1 " "is deprecated and will be removed in a later version of Swift", (StringRef, Identifier)) -WARNING(import_multiple_mainactor_attr,none, +GROUPED_WARNING(import_multiple_mainactor_attr, ClangDeclarationImport, none, "this attribute for global actor '%0' is invalid; the declaration already has attribute for global actor '%1'", (StringRef, StringRef)) -WARNING(contradicting_mutation_attrs,none, +GROUPED_WARNING(contradicting_mutation_attrs, ClangDeclarationImport, none, "attribute '%0' is ignored when combined with attribute '%1'", (StringRef, StringRef)) -WARNING(nonmutating_without_const,none, +GROUPED_WARNING(nonmutating_without_const, ClangDeclarationImport, none, "attribute 'nonmutating' has no effect on non-const method", ()) -WARNING(nonmutating_without_mutable_fields,none, +GROUPED_WARNING(nonmutating_without_mutable_fields, ClangDeclarationImport, none, "attribute 'nonmutating' has no effect without any mutable fields", ()) ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef)) @@ -135,7 +132,7 @@ WARNING(libstdcxx_modulemap_not_found, none, "module map for libstdc++ not found for '%0'; C++ stdlib may be unavailable", (StringRef)) -WARNING(api_pattern_attr_ignored, none, +GROUPED_WARNING(api_pattern_attr_ignored, ClangDeclarationImport, none, "'%0' Swift attribute ignored on type '%1': type is not copyable or destructible", (StringRef, StringRef)) @@ -226,7 +223,7 @@ ERROR(private_fileid_attr_repeated, none, NOTE(private_fileid_attr_here, none, "SWIFT_PRIVATE_FILEID annotation found here", ()) - WARNING(private_fileid_attr_format_invalid, none, + GROUPED_WARNING(private_fileid_attr_format_invalid, ClangDeclarationImport, none, "SWIFT_PRIVATE_FILEID annotation on '%0' does not have a valid file ID", (StringRef)) REMARK(private_fileid_attr_format_specification, none, @@ -302,12 +299,12 @@ ERROR(returns_retained_or_returns_unretained_for_non_cxx_frt_values, none, // TODO: In the next C++ interop version, convert this warning into an error and // stop importing unannotated C++ APIs that return SWIFT_SHARED_REFERENCE. // rdar://138806722 -WARNING(no_returns_retained_returns_unretained, none, +GROUPED_WARNING(no_returns_retained_returns_unretained, ClangDeclarationImport, none, "%0 should be annotated with either SWIFT_RETURNS_RETAINED or " "SWIFT_RETURNS_UNRETAINED as it is returning a SWIFT_SHARED_REFERENCE", (const clang::NamedDecl *)) -WARNING(returns_retained_returns_unretained_on_overloaded_operator, none, +GROUPED_WARNING(returns_retained_returns_unretained_on_overloaded_operator, ClangDeclarationImport, none, "SWIFT_RETURNS_RETAINED and SWIFT_RETURNS_UNRETAINED is not supported " "yet for overloaded C++ %0. Overloaded C++ operators always " "return " @@ -318,7 +315,7 @@ WARNING(returns_retained_returns_unretained_on_overloaded_operator, none, // stop importing C++ types that inherit from SWIFT_SHARED_REFERENCE if the // Swift compiler cannot find unique retain/release functions. // rdar://145194375 -WARNING(cant_infer_frt_in_cxx_inheritance, none, +GROUPED_WARNING(cant_infer_frt_in_cxx_inheritance, ClangDeclarationImport, none, "unable to infer SWIFT_SHARED_REFERENCE for %0, although one of its " "transitive base types is marked as SWIFT_SHARED_REFERENCE", (const clang::NamedDecl *)) @@ -351,8 +348,12 @@ NOTE(forward_declared_protocol_clashes_with_imported_objc_Swift_protocol, none, "its name conflicts with a %1 in module %2", (const clang::NamedDecl*, StringRef, StringRef)) -WARNING(return_escapable_with_lifetimebound, none, "the returned type '%0' is annotated as escapable; it cannot have lifetime dependencies", (StringRef)) -WARNING(return_nonescapable_without_lifetimebound, none, "the returned type '%0' is annotated as non-escapable; its lifetime dependencies must be annotated", (StringRef)) +GROUPED_WARNING(return_escapable_with_lifetimebound, ClangDeclarationImport, none, + "the returned type '%0' is annotated as escapable; it cannot have lifetime dependencies", + (StringRef)) +GROUPED_WARNING(return_nonescapable_without_lifetimebound, ClangDeclarationImport, none, + "the returned type '%0' is annotated as non-escapable; its lifetime dependencies must be annotated", + (StringRef)) ERROR(unknown_template_parameter,none, "template parameter '%0' does not exist", (StringRef)) @@ -373,5 +374,9 @@ NOTE(ptr_to_nonescapable,none, "pointer to non-escapable type %0 cannot be imported", (const clang::Type*)) +NOTE(nonescapable_field_of_escapable, none, + "escapable record %0 cannot have non-escapable field '%1'", + (const clang::NamedDecl *, StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 14c2e9b76cc31..b1639844e7b33 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -87,7 +87,7 @@ ERROR(require_literal_initializer_for_literal,none, "_const let should be initialized with a literal value", ()) ERROR(require_const_initializer_for_const,none, - "@const value should be initialized with a compile-time value", ()) + "'@const' value should be initialized with a compile-time value", ()) ERROR(require_const_arg_for_parameter,none, "expected a compile-time value argument for a '@const' parameter", ()) diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 41736350078fa..2405f6228fe33 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -59,9 +59,9 @@ GROUPED_WARNING(cannot_disable_feature_with_mode, StrictLanguageFeatures, none, "'%0' argument '%1' cannot specify a mode", (StringRef, StringRef)) -GROUPED_WARNING(feature_does_not_support_adoption_mode, StrictLanguageFeatures, +GROUPED_WARNING(feature_does_not_support_migration_mode, StrictLanguageFeatures, none, - "feature '%0' does not support adoption mode", + "feature '%0' does not support migration mode", (StringRef)) ERROR(error_unknown_library_level, none, @@ -193,6 +193,8 @@ ERROR(cannot_emit_ir_skipping_function_bodies,none, WARNING(emit_reference_dependencies_without_primary_file,none, "ignoring -emit-reference-dependencies (requires -primary-file)", ()) +WARNING(ignoring_option_obsolete,none, + "ignoring '%0'; this option is obsolete", (StringRef)) WARNING(ignoring_option_requires_option,none, "ignoring %0 (requires %1)", (StringRef, StringRef)) WARNING(warn_ignore_option_overriden_by,none, @@ -518,14 +520,21 @@ REMARK(matching_output_produced,none, // Caching related diagnostics ERROR(error_caching_no_cas_fs, none, - "caching is enabled without -cas-fs option, input is not immutable", ()) + "caching is enabled without CAS file-system options, input is not immutable", ()) ERROR(error_prefix_mapping, none, "cannot create scanner prefix mapping: '%0'", (StringRef)) REMARK(replay_output, none, "replay output file '%0': key '%1'", (StringRef, StringRef)) REMARK(output_cache_miss, none, "cache miss for input file '%0': key '%1'", (StringRef, StringRef)) // CAS related diagnostics -ERROR(error_cas, none, "CAS error encountered: %0", (StringRef)) +ERROR(error_invalid_cas_id, none, "CAS cannot parse id '%0': %1", (StringRef, StringRef)) +ERROR(error_cas, none, "CAS error encountered during %0: %1", (StringRef, StringRef)) +ERROR(error_cas_fs_creation, none, "cannot create CAS filesystem: %0", (StringRef)) +ERROR(error_cache_key_creation, none, "cannot create cache key for compilation %0: %1", (StringRef, StringRef)) +ERROR(error_cas_file_ref, none, "cannot load file %0 from CAS filesystem", (StringRef)) +ERROR(error_cas_conflict_options, none, "cannot setup CAS due to conflicting '-cas-*' options", ()) +ERROR(error_cas_initialization, none, "CAS cannot be initialized from the specified '-cas-*' options: %0", (StringRef)) +ERROR(error_cas_malformed_input, none, "CAS input '%0' is malformed: %1", (StringRef, StringRef)) WARNING(cache_replay_failed, none, "cache replay failed: %0", (StringRef)) ERROR(error_failed_cached_diag, none, "failed to serialize cached diagnostics: %0", (StringRef)) @@ -618,5 +627,16 @@ ERROR(ast_format_requires_dump_ast,none, ERROR(unknown_dump_ast_format,none, "unknown format '%0' requested with '-dump-ast-format'", (StringRef)) +WARNING(dependency_scan_unexpected_variant, none, + "unexpected module variant during dependency scanning on module '%0', " + "compilation of this target is likely to fail or succeed in a way that is not deterministic", (StringRef)) +NOTE(dependency_scan_unexpected_variant_context_hash_note, none, + "first module context hash: '%0', second module context hash: '%1'", (StringRef, StringRef)) +NOTE(dependency_scan_unexpected_variant_module_map_note, none, + "first module module map: '%0', second module module map: '%1'", (StringRef, StringRef)) +NOTE(dependency_scan_unexpected_variant_extra_arg_note, none, + "%select{first|second}0 module command-line has extra argument: '%1'", (bool, StringRef)) + + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsIRGen.def b/include/swift/AST/DiagnosticsIRGen.def index ad85f2f9df6e7..4f93def59a63f 100644 --- a/include/swift/AST/DiagnosticsIRGen.def +++ b/include/swift/AST/DiagnosticsIRGen.def @@ -42,12 +42,12 @@ ERROR(no_input_files_for_mt,none, "no swift input files for multi-threaded compilation", ()) ERROR(alignment_dynamic_type_layout_unsupported,none, - "@_alignment is not supported on types with dynamic layout", ()) + "'@_alignment' is not supported on types with dynamic layout", ()) ERROR(alignment_less_than_natural,none, - "@_alignment cannot decrease alignment below natural alignment of %0", + "'@_alignment' cannot decrease alignment below natural alignment of %0", (unsigned)) ERROR(alignment_more_than_maximum,none, - "@_alignment cannot increase alignment above maximum alignment of %0", + "'@_alignment' cannot increase alignment above maximum alignment of %0", (unsigned)) ERROR(temporary_allocation_size_negative,none, diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def index 7e295ba80e805..d74b6d349c201 100644 --- a/include/swift/AST/DiagnosticsModuleDiffer.def +++ b/include/swift/AST/DiagnosticsModuleDiffer.def @@ -66,7 +66,7 @@ ERROR(optional_req_changed,APIDigesterBreakage,"%0 is %select{now|no longer}1 an ERROR(no_longer_open,APIDigesterBreakage,"%0 is no longer open for subclassing", (StringRef)) -ERROR(func_type_escaping_changed,APIDigesterBreakage,"%0 has %select{removed|added}2 @escaping in %1", (StringRef, StringRef, bool)) +ERROR(func_type_escaping_changed,APIDigesterBreakage,"%0 has %select{removed|added}2 '@escaping' in %1", (StringRef, StringRef, bool)) ERROR(func_self_access_change,APIDigesterBreakage,"%0 has self access kind changing from %1 to %2", (StringRef, StringRef, StringRef)) @@ -78,7 +78,7 @@ ERROR(decl_new_witness_table_entry,APIDigesterBreakage,"%0 now requires%select{| ERROR(class_member_moved_to_extension,APIDigesterBreakage,"Non-final class member %0 is moved to extension", (StringRef)) -WARNING(new_decl_without_intro,APIDigesterBreakage,"%0 is a new API without @available attribute", (StringRef)) +WARNING(new_decl_without_intro,APIDigesterBreakage,"%0 is a new API without '@available'", (StringRef)) ERROR(objc_name_change,APIDigesterBreakage,"%0 has ObjC name change from %1 to %2", (StringRef, StringRef, StringRef)) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 6d3f9b400f73b..37136b7d8c7b8 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -497,7 +497,7 @@ ERROR(expected_precedencegroup_relation,none, ERROR(expected_sil_keyword,none, "expected SIL keyword", ()) ERROR(inout_not_attribute, none, - "@inout is no longer an attribute", ()) + "'inout' is no longer an attribute", ()) ERROR(only_allowed_in_sil,none, "'%0' only allowed in SIL modules", (StringRef)) ERROR(expected_sil_type,none, @@ -520,7 +520,7 @@ ERROR(silfunc_and_silarg_have_incompatible_sil_value_ownership,none, "Function type specifies: '@%0'. SIL argument specifies: '@%1'.", (StringRef, StringRef)) ERROR(sil_arg_both_lexical_and_eagerMove,none, - "Function argument is annotated both @_eagerMove and @_noEagerMove, " + "Function argument is annotated both '@_eagerMove' and '@_noEagerMove', " "but these are incompatible alternatives", ()) ERROR(expected_sil_colon,none, "expected ':' before %0", (StringRef)) @@ -1568,6 +1568,11 @@ ERROR(attr_unsupported_on_target, none, ERROR(attr_name_unsupported_on_target, none, "attribute '%0' is unsupported on target '%1'", (StringRef, StringRef)) +// abi attribute +ERROR(attr_abi_incompatible_kind,none, + "cannot use %0 in '@abi'", + (DescriptiveDeclKind)) + // availability ERROR(attr_availability_platform,none, "expected platform name or '*' for '%0' attribute", (StringRef)) @@ -1624,14 +1629,14 @@ ERROR(attr_availability_duplicate,none, // originallyDefinedIn ERROR(originally_defined_in_missing_rparen,none, - "expected ')' in @_originallyDefinedIn argument list", ()) + "expected ')' in '@_originallyDefinedIn' argument list", ()) ERROR(originally_defined_in_need_original_module_name,none, "expected 'module: \"original\"' in the first argument to " - "@_originallyDefinedIn", ()) + "'@_originallyDefinedIn'", ()) ERROR(originally_defined_in_need_nonempty_module_name,none, - "original module name cannot be empty in @_originallyDefinedIn", ()) + "original module name cannot be empty in '@_originallyDefinedIn'", ()) // backDeploy ERROR(attr_back_deploy_expected_before_label,none, @@ -1662,25 +1667,25 @@ ERROR(convention_attribute_witness_method_expected_protocol,none, // objc ERROR(attr_objc_missing_colon,none, - "missing ':' after selector piece in @objc attribute", ()) + "missing ':' after selector piece in '@objc'", ()) ERROR(attr_objc_expected_rparen,none, - "expected ')' after name for @objc", ()) + "expected ')' after name for '@objc'", ()) ERROR(attr_objc_empty_name,none, - "expected name within parentheses of @objc attribute", ()) + "expected name within parentheses of '@objc'", ()) ERROR(attr_dynamic_replacement_expected_rparen,none, - "expected ')' after function name for @_dynamicReplacement", ()) + "expected ')' after function name for '@_dynamicReplacement'", ()) ERROR(attr_dynamic_replacement_expected_function,none, - "expected a function name in @_dynamicReplacement(for:)", ()) + "expected a function name in '@_dynamicReplacement(for:)'", ()) ERROR(attr_dynamic_replacement_expected_for,none, "expected 'for' in '_dynamicReplacement' attribute", ()) ERROR(attr_dynamic_replacement_expected_colon,none, - "expected ':' after @_dynamicReplacement(for", ()) + "expected ':' after '@_dynamicReplacement(for'", ()) ERROR(attr_type_eraser_expected_type_name,none, - "expected a type name in @_typeEraser()", ()) + "expected a type name in '@_typeEraser()'", ()) ERROR(attr_type_eraser_expected_rparen,none, - "expected ')' after type name for @_typeEraser", ()) + "expected ')' after type name for '@_typeEraser'", ()) ERROR(expected_thrown_error_type,none, "expected thrown error type after 'throws('", ()) @@ -1697,22 +1702,14 @@ ERROR(attr_isolated_expected_rparen,none, ERROR(attr_isolated_expected_kind,none, "expected 'any' as the isolation kind", ()) -ERROR(attr_execution_expected_lparen,none, - "expected '(' after '@execution'", - ()) -ERROR(attr_execution_expected_rparen,none, - "expected ')' after execution behavior", ()) -ERROR(attr_execution_expected_kind,none, - "expected 'concurrent' or 'caller' as the execution behavior", ()) - ERROR(attr_private_import_expected_rparen,none, - "expected ')' after function name for @_private", ()) + "expected ')' after function name for '@_private'", ()) ERROR(attr_private_import_expected_sourcefile, none, "expected 'sourceFile' in '_private' attribute", ()) ERROR(attr_private_import_expected_sourcefile_name,none, - "expected a source file name in @_private(sourceFile:)", ()) + "expected a source file name in '@_private(sourceFile:)'", ()) ERROR(attr_private_import_expected_colon,none, - "expected ':' after @_private(sourceFile", ()) + "expected ':' after '@_private(sourceFile'", ()) // opened ERROR(opened_attribute_expected_lparen,none, @@ -1833,18 +1830,18 @@ ERROR(sil_inst_autodiff_expected_differentiability_witness_kind,PointsToFirstBad "'[vjp]', or '[transpose]'", ()) WARNING(warn_attr_unsafe_removed,none, - "'%0' attribute has been removed in favor of @preconcurrency", + "'%0' attribute has been removed in favor of '@preconcurrency'", (StringRef)) // _documentation ERROR(documentation_attr_expected_argument,none, - "@_documentation attribute expected 'visibility' or 'metadata' argument", + "'_documentation' attribute expected 'visibility' or 'metadata' argument", ()) ERROR(documentation_attr_unknown_argument,none, "unknown argument '%0', expected 'visibility' or 'metadata'", (StringRef)) ERROR(documentation_attr_expected_access_level,none, - "@_documentation attribute's 'visibility' argument expected an access level", + "'_documentation' attribute's 'visibility' argument expected an access level", ()) ERROR(documentation_attr_unknown_access_level,none, "unknown visibility '%0', expected an access level keyword", @@ -1852,26 +1849,26 @@ ERROR(documentation_attr_unknown_access_level,none, ERROR(documentation_attr_duplicate_visibility,none, "cannot give more than one visibility to the same item", ()) ERROR(documentation_attr_metadata_expected_text,none, - "@_documentation attribute's 'metadata' argument expected an identifier or " + "'_documentation' attribute's 'metadata' argument expected an identifier or " "quoted string", ()) ERROR(documentation_attr_duplicate_metadata,none, "cannot give more than one metadata argument to the same item", ()) ERROR(attr_rawlayout_expected_label,none, - "expected %0 argument to @_rawLayout attribute", (StringRef)) + "expected %0 argument to '@_rawLayout'", (StringRef)) ERROR(attr_rawlayout_expected_integer_size,none, - "expected integer literal size in @_rawLayout attribute", ()) + "expected integer literal size in '@_rawLayout'", ()) ERROR(attr_rawlayout_expected_integer_alignment,none, - "expected integer literal alignment in @_rawLayout attribute", ()) + "expected integer literal alignment in '@_rawLayout'", ()) ERROR(attr_rawlayout_expected_params,none, - "expected %1 argument after %0 argument in @_rawLayout attribute", (StringRef, StringRef)) + "expected %1 argument after %0 argument in '@_rawLayout'", (StringRef, StringRef)) ERROR(attr_extern_expected_label,none, - "expected %0 argument to @_extern attribute", (StringRef)) + "expected %0 argument to '@_extern'", (StringRef)) ERROR(attr_expected_feature_name,none, - "expected feature name in @%0 attribute", (StringRef)) + "expected feature name in '@%0'", (StringRef)) //------------------------------------------------------------------------------ // MARK: Generics parsing diagnostics @@ -2064,13 +2061,13 @@ ERROR(macro_role_syntax_mismatch,PointsToFirstBadToken, "%select{a freestanding|an attached}0 macro cannot have the %1 role", (bool, Identifier)) ERROR(macro_attribute_unknown_label,PointsToFirstBadToken, - "@%select{freestanding|attached}0 has no argument with label %1", + "'@%select{freestanding|attached}0' has no argument with label %1", (bool, Identifier)) ERROR(macro_attribute_duplicate_label,PointsToFirstBadToken, - "@%select{freestanding|attached}0 already has an argument with " + "'@%select{freestanding|attached}0' already has an argument with " "label %1", (bool, StringRef)) ERROR(macro_attribute_missing_label,none, - "@%select{freestanding|attached}0 argument is missing label '%1'", + "'@%select{freestanding|attached}0' argument is missing label '%1'", (bool, StringRef)) ERROR(macro_attribute_unknown_name_kind,PointsToFirstBadToken, "unknown introduced name kind %0", (Identifier)) @@ -2081,7 +2078,8 @@ ERROR(macro_attribute_introduced_name_requires_argument,PointsToFirstBadToken, ERROR(macro_attribute_introduced_name_requires_no_argument,PointsToFirstBadToken, "introduced name kind %0 must not have an argument", (Identifier)) WARNING(macro_expression_attribute_removed,PointsToFirstBadToken, - "@expression has been removed in favor of @freestanding(expression)", ()) + "'@expression' has been removed in favor of '@freestanding(expression)'", + ()) ERROR(unexpected_attribute_expansion,PointsToFirstBadToken, "unexpected token '%0' in expanded attribute list", @@ -2117,16 +2115,16 @@ ERROR(init_accessor_is_not_in_the_primary_declaration,none, ()) ERROR(missing_storage_restrictions_attr_label,none, - "missing label in @storageRestrictions attribute", ()) + "missing label in '@storageRestrictions'", ()) ERROR(invalid_storage_restrictions_attr_label,none, - "unexpected label %0 in @storageRestrictions attribute", (Identifier)) + "unexpected label %0 in '@storageRestrictions'", (Identifier)) ERROR(duplicate_storage_restrictions_attr_label,none, - "duplicate label %0 in @storageRestrictions attribute", (Identifier)) + "duplicate label %0 in '@storageRestrictions'", (Identifier)) ERROR(storage_restrictions_attr_expected_name,none, - "expected property name in @storageRestrictions list", ()) + "expected property name in '@storageRestrictions' list", ()) ERROR(requires_experimental_feature, none, "'%0' %select{attribute|parameter specifier}1 is only valid when experimental feature " @@ -2142,7 +2140,7 @@ ERROR(expected_lparen_after_lifetime_dependence, PointsToFirstBadToken, ERROR(expected_identifier_or_index_or_self_after_lifetime_dependence, PointsToFirstBadToken, - "expected identifier, index or self in lifetime dependence specifier", + "expected 'copy', 'borrow', or '&' followed by an identifier, index or 'self' in lifetime dependence specifier", ()) ERROR(expected_rparen_after_lifetime_dependence, PointsToFirstBadToken, @@ -2169,5 +2167,27 @@ ERROR(sil_thunkinst_failed_to_parse_kind,none, ERROR(sil_failed_to_parse_sil_optional,none, "Expected SIL optional value of the form '[' NAME ']'", ()) +//------------------------------------------------------------------------------ +// MARK: nonisolated(nonsending) +//------------------------------------------------------------------------------ + +ERROR(nonisolated_nonsending_expected_lparen,PointsToFirstBadToken, + "expected '(' following 'nonisolated'", ()) +ERROR(nonisolated_nonsending_incorrect_modifier,PointsToFirstBadToken, + "expected 'nonsending' in modifier", ()) +ERROR(nonisolated_nonsending_expected_rparen,PointsToFirstBadToken, + "expected ')' after 'nonisolated' modifier", ()) +ERROR(nonisolated_nonsending_repeated,none, + "parameter may have at most one 'nonisolated(nonsending)' specifier", ()) + +//------------------------------------------------------------------------------ +// MARK: using @ or using +//------------------------------------------------------------------------------ +ERROR(using_decl_invalid_specifier,PointsToFirstBadToken, + "default isolation can only be set to '@MainActor' or 'nonisolated'", + ()) +ERROR(experimental_using_decl_disabled,PointsToFirstBadToken, + "'using' is an experimental feature that is currently disabled", ()) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 8237db1f11b8c..943e67e29be8f 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -143,7 +143,7 @@ ERROR(deserialize_function_type_mismatch,Fatal, (StringRef, Type, Type)) ERROR(without_actually_escaping_on_isolated_any,none, - "withoutActuallyEscaping is currently unimplemented for @isolated(any) " + "withoutActuallyEscaping is currently unimplemented for '@isolated(any)' " "function values", ()) // Capture before declaration diagnostics. @@ -315,12 +315,12 @@ ERROR(missing_never_call_closure,none, (Type)) ERROR(missing_return_decl,none, - "missing return in %1 expected to return %0", - (Type, DescriptiveDeclKind)) + "missing return in %kindonly1 expected to return %0", + (Type, const AbstractFunctionDecl *)) ERROR(missing_never_call_decl,none, - "%1 with uninhabited return type %0 is missing " + "%kindonly1 with uninhabited return type %0 is missing " "call to another never-returning function on all paths", - (Type, DescriptiveDeclKind)) + (Type, const AbstractFunctionDecl *)) NOTE(missing_return_last_expr_note,none, "did you mean to return the last expression?", ()) @@ -389,9 +389,9 @@ ERROR(embedded_swift_existential_type,none, ERROR(embedded_swift_existential,none, "cannot use a value of protocol type in embedded Swift", ()) ERROR(perf_diag_existential_type,none, - "cannot use a value of protocol type %0 in @_noExistential function", (Type)) + "cannot use a value of protocol type %0 in '@_noExistential' function", (Type)) ERROR(perf_diag_existential,none, - "cannot use a value of protocol type in @_noExistential function", ()) + "cannot use a value of protocol type in '@_noExistential' function", ()) ERROR(embedded_swift_value_deinit,none, "cannot de-virtualize deinit of type %0", (Type)) ERROR(embedded_swift_metatype_type,none, @@ -701,8 +701,9 @@ WARNING(warning_int_to_fp_inexact, none, // Flow-isolation diagnostics ERROR(isolated_after_nonisolated, none, - "cannot access %1 %2 here in %select{nonisolated initializer|deinitializer}0", - (bool, DescriptiveDeclKind, DeclName)) + "cannot access %kind1 here in " + "%select{nonisolated initializer|deinitializer}0", + (bool, const ValueDecl *)) NOTE(nonisolated_blame, none, "after %1%2 %3, " "only nonisolated properties of 'self' can be accessed from " "%select{this init|a deinit}0", (bool, StringRef, StringRef, DeclName)) @@ -809,7 +810,7 @@ NOTE(capturepromotion_variable_defined_here,none, // noimplicitcopy on generic or existential binding ERROR(noimplicitcopy_used_on_generic_or_existential, none, - "@_noImplicitCopy can not be used on a generic or existential typed " + "'@_noImplicitCopy' can not be used on a generic or existential typed " "binding or a nominal type containing such typed things", ()) // discard statement @@ -840,7 +841,8 @@ ERROR(sil_movechecking_borrowed_parameter_captured_by_closure, none, "parameter", (StringRef)) ERROR(sil_movechecking_capture_consumed, none, - "noncopyable '%0' cannot be consumed when captured by an escaping closure", (StringRef)) + "noncopyable '%0' cannot be consumed when captured by an escaping closure or borrowed by a non-Escapable type", + (StringRef)) ERROR(sil_movechecking_not_reinitialized_before_end_of_function, none, "missing reinitialization of %select{inout parameter|closure capture}1 '%0' " "after consume", (StringRef, bool)) @@ -864,7 +866,8 @@ ERROR(sil_movechecking_cannot_destructure_imported_nonfrozen, none, "cannot partially consume '%0' of non-frozen type %1 imported from %2", (StringRef, Type, const ModuleDecl*)) ERROR(sil_movechecking_cannot_destructure_exported_usableFromInline_alwaysEmitIntoClient, none, - "cannot partially consume '%0' of non-frozen usableFromInline type %1 within a function annotated @_alwaysEmitIntoClient", + "cannot partially consume '%0' of non-frozen usableFromInline type %1 " + "within a function annotated '@_alwaysEmitIntoClient'", (StringRef, Type)) ERROR(sil_movechecking_cannot_destructure, none, "cannot partially consume '%0'", @@ -876,7 +879,8 @@ ERROR(sil_movechecking_cannot_partially_reinit_nonfrozen, none, "cannot partially reinitialize '%0' of non-frozen type %1 imported from %2; only full reinitialization is allowed", (StringRef, Type, const ModuleDecl*)) ERROR(sil_movechecking_cannot_partially_reinit_exported_usableFromInline_alwaysEmitIntoClient, none, - "cannot partially reinitialize '%0' of non-frozen usableFromInline type %1 within a function annotated @_alwaysEmitIntoClient", + "cannot partially reinitialize '%0' of non-frozen usableFromInline type " + "%1 within a function annotated '@_alwaysEmitIntoClient'", (StringRef, Type)) ERROR(sil_movechecking_cannot_partially_reinit, none, "cannot partially reinitialize '%0' after it has been consumed; only full reinitialization is allowed", @@ -979,23 +983,23 @@ GROUPED_ERROR(regionbasedisolation_type_send_yields_race, SendingRisksDataRace, (Type)) NOTE(regionbasedisolation_type_use_after_send, none, "sending value of non-Sendable type %0 to %1 callee risks causing data races between %1 and local %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(regionbasedisolation_type_use_after_send_callee, none, - "sending value of non-Sendable type %0 to %1 %2 %3 risks causing data " - "races between %1 and local %4 uses", - (Type, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending value of non-Sendable type %0 to %1 %kind2 risks causing data " + "races between %1 and local %3 uses", + (Type, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race, none, - "sending %1%0 to %2 callee risks causing data races between %2 and local %3 uses", - (Identifier, StringRef, ActorIsolation, ActorIsolation)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and local %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_info_send_yields_race_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and local %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, ActorIsolation)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and local %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) // Use after send closure. NOTE(regionbasedisolation_type_isolated_capture_yields_race, none, "sending value of non-Sendable type %0 to %1 closure due to closure capture risks causing races in between %1 and %2 uses", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) // Value captured in async let and reused. NOTE(regionbasedisolation_named_nonisolated_asynclet_name, none, @@ -1006,33 +1010,33 @@ NOTE(regionbasedisolation_named_value_used_after_explicit_sending, none, "%0 used after being passed as a 'sending' parameter; Later uses could race", (Identifier)) NOTE(regionbasedisolation_named_isolated_closure_yields_race, none, - "%0%1 is captured by a %2 closure. %2 uses in closure may race against later %3 uses", - (StringRef, Identifier, ActorIsolation, ActorIsolation)) + "%select{%1 |}0%2 is captured by a %3 closure. %3 uses in closure may race against later %4 uses", + (bool, StringRef, Identifier, StringRef, StringRef)) NOTE(regionbasedisolation_typed_use_after_sending, none, "Passing value of non-Sendable type %0 as a 'sending' argument risks causing races in between local and caller code", (Type)) NOTE(regionbasedisolation_typed_use_after_sending_callee, none, - "Passing value of non-Sendable type %0 as a 'sending' argument to %1 %2 risks causing races in between local and caller code", - (Type, DescriptiveDeclKind, DeclName)) + "Passing value of non-Sendable type %0 as a 'sending' argument to %kind1 risks causing races in between local and caller code", + (Type, const ValueDecl *)) //=== // Sending Never Sendable Emitter NOTE(regionbasedisolation_named_send_never_sendable, none, - "sending %1%0 to %2 callee risks causing data races between %2 and %3 uses", - (Identifier, StringRef, ActorIsolation, StringRef)) + "sending %select{%2 |}0%1 to %3 callee risks causing data races between %3 and %4 uses", + (bool, Identifier, StringRef, StringRef, StringRef)) NOTE(regionbasedisolation_named_send_never_sendable_callee, none, - "sending %1%0 to %2 %3 %4 risks causing data races between %2 and %5 uses", - (Identifier, StringRef, ActorIsolation, DescriptiveDeclKind, DeclName, StringRef)) + "sending %select{%2 |}0%1 to %3 %kind4 risks causing data races between %3 and %5 uses", + (bool, Identifier, StringRef, StringRef, const ValueDecl *, StringRef)) NOTE(regionbasedisolation_named_send_into_sending_param, none, - "%0%1 is passed as a 'sending' parameter; Uses in callee may race with " - "later %0uses", - (StringRef, Identifier)) + "%select{%1 |}0%2 is passed as a 'sending' parameter; Uses in callee may race with " + "later %1 uses", + (bool, StringRef, Identifier)) NOTE(regionbasedisolation_named_nosend_send_into_result, none, - "%0%1 cannot be a 'sending' result. %2 uses may race with caller uses", - (StringRef, Identifier, StringRef)) + "%select{%1 |}0%2 cannot be a 'sending' result. %3 uses may race with caller uses", + (bool, StringRef, Identifier, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending, none, "Passing %0 value of non-Sendable type %1 as a 'sending' parameter risks " "causing races inbetween %0 uses and uses reachable from the callee", @@ -1048,8 +1052,8 @@ NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_ "closure captures %0 which is accessible to code in the current task", (DeclName)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_boxed_value_task_isolated, none, - "closure captures reference to mutable %1 %0 which is accessible to code in the current task", - (DeclName, DescriptiveDeclKind)) + "closure captures reference to mutable %kind0 which is accessible to code in the current task", + (const ValueDecl *)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_closure_helper_have_value_region, none, "closure captures %1 which is accessible to %0 code", (StringRef, DeclName)) @@ -1065,18 +1069,22 @@ NOTE(regionbasedisolation_closure_captures_actor, none, (DeclName, StringRef)) NOTE(regionbasedisolation_typed_tns_passed_to_sending_callee, none, - "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %2 %3 risks causing races inbetween %0 uses and uses reachable from %3", - (StringRef, Type, DescriptiveDeclKind, DeclName)) + "Passing %0 value of non-Sendable type %1 as a 'sending' parameter to %kind2 risks causing races inbetween %0 uses and uses reachable from %2", + (StringRef, Type, const ValueDecl *)) NOTE(regionbasedisolation_named_send_nt_asynclet_capture, none, "sending %1 %0 into async let risks causing data races between nonisolated and %1 uses", (Identifier, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg, none, "sending %0 value of non-Sendable type %1 to %2 callee risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation)) + (StringRef, Type, StringRef)) NOTE(regionbasedisolation_typed_sendneversendable_via_arg_callee, none, - "sending %0 value of non-Sendable type %1 to %2 %3 %4 risks causing races in between %0 and %2 uses", - (StringRef, Type, ActorIsolation, DescriptiveDeclKind, DeclName)) + "sending %0 value of non-Sendable type %1 to %2 %kind3 risks causing races in between %0 and %2 uses", + (StringRef, Type, StringRef, const ValueDecl *)) + +NOTE(regionbasedisolation_isolated_conformance_introduced, none, + "isolated conformance to %kind0 can be introduced here", + (const ValueDecl *)) // Error that is only used when the send non sendable emitter cannot discover any // information to give a better diagnostic. @@ -1090,10 +1098,10 @@ NOTE(regionbasedisolation_inout_sending_must_be_reinitialized, none, "'inout sending' parameter must be reinitialized before function exit with a non-actor isolated value", ()) ERROR(regionbasedisolation_inout_sending_cannot_be_actor_isolated, none, - "'inout sending' parameter %0 cannot be %1at end of function", + "'inout sending' parameter %0 cannot be %1 at end of function", (Identifier, StringRef)) NOTE(regionbasedisolation_inout_sending_cannot_be_actor_isolated_note, none, - "%1%0 risks causing races in between %1uses and caller uses since caller assumes value is not actor isolated", + "%1 %0 risks causing races in between %1 uses and caller uses since caller assumes value is not actor isolated", (Identifier, StringRef)) //=== @@ -1118,10 +1126,10 @@ NOTE(regionbasedisolation_out_sending_cannot_be_actor_isolated_note_named, none, // Example: returning main-actor isolated result to a custom-actor isolated context risks causing data races ERROR(rbi_isolation_crossing_result, none, "non-Sendable %0-typed result can not be returned from %1 %kind2 to %3 context", - (Type, ActorIsolation, const ValueDecl *, ActorIsolation)) + (Type, StringRef, const ValueDecl *, StringRef)) ERROR(rbi_isolation_crossing_result_no_decl, none, "non-Sendable %0-typed result can not be returned from %1 function to %2 context", - (Type, ActorIsolation, ActorIsolation)) + (Type, StringRef, StringRef)) NOTE(rbi_non_sendable_nominal,none, "%kind0 does not conform to the 'Sendable' protocol", (const ValueDecl *)) @@ -1136,12 +1144,9 @@ NOTE(rbi_add_generic_parameter_sendable_conformance,none, // Concurrency related diagnostics ERROR(cannot_find_executor_factory_type, none, - "the specified executor factory '%0' could not be found", (StringRef)) + "the DefaultExecutorFactory type could not be found", ()) ERROR(executor_factory_must_conform, none, - "the executor factory '%0' does not conform to 'ExecutorFactory'", - (StringRef)) -ERROR(executor_factory_not_supported, none, - "deployment target too low for executor factory specification", ()) + "the DefaultExecutorFactory does not conform to 'ExecutorFactory'", ()) //===----------------------------------------------------------------------===// // MARK: Misc Diagnostics @@ -1155,14 +1160,22 @@ ERROR(lifetime_variable_outside_scope, none, "lifetime-dependent variable '%0' escapes its scope", (Identifier)) ERROR(lifetime_value_outside_scope, none, "lifetime-dependent value escapes its scope", ()) +ERROR(lifetime_value_outside_accessor, none, + "lifetime-dependent value returned by generated accessor '%0'", (StringRef)) +ERROR(lifetime_value_outside_thunk, none, + "lifetime-dependent value returned by generated %select{function|thunk}0 '%1'", (bool, StringRef)) NOTE(lifetime_outside_scope_argument, none, "it depends on the lifetime of argument '%0'", (Identifier)) +NOTE(lifetime_outside_scope_synthesized_argument, none, + "it depends on the lifetime of an argument of '%0'", (Identifier)) NOTE(lifetime_outside_scope_access, none, "it depends on this scoped access to variable '%0'", (Identifier)) NOTE(lifetime_outside_scope_variable, none, "it depends on the lifetime of variable '%0'", (Identifier)) NOTE(lifetime_outside_scope_value, none, "it depends on the lifetime of this parent value", ()) +NOTE(lifetime_outside_scope_capture, none, + "it depends on a closure capture; this is not yet supported", ()) NOTE(lifetime_outside_scope_use, none, "this use of the lifetime-dependent value is out of scope", ()) NOTE(lifetime_outside_scope_escape, none, diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2e9f8b78c95f8..0c646d2c93458 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -165,11 +165,20 @@ ERROR(init_candidate_inaccessible,none, "'%select{private|fileprivate|internal|package|@_spi|@_spi}1' protection level", (Type, AccessLevel)) -ERROR(candidate_from_missing_import,none, - "%0 %1 is not available due to missing import of defining module %2", - (DescriptiveDeclKind, DeclName, ModuleDecl *)) +GROUPED_ERROR(member_from_missing_import,MemberImportVisibility,none, + "%kind0 is not available due to missing import of defining module %1", + (const ValueDecl *, const ModuleDecl *)) +GROUPED_ERROR(member_from_missing_imports_2_or_more,MemberImportVisibility,none, + "%kind0 is not available due to missing imports of defining modules " + "%2%select{ and|, }1 %3%select{|, and others}1", + (const ValueDecl *, bool, const ModuleDecl *, const ModuleDecl *)) NOTE(candidate_add_import,none, - "add import of module %0", (ModuleDecl *)) + "add import of module %0", (const ModuleDecl *)) + +GROUPED_WARNING(add_required_import_for_member,MemberImportVisibility,none, + "import of module %0 is required", (const ModuleDecl *)) +NOTE(decl_from_module_used_here,none, + "%kind0 from %1 used here", (const ValueDecl *, const ModuleDecl *)) ERROR(cannot_pass_rvalue_mutating_subelement,none, "cannot use mutating member on immutable value: %0", @@ -310,13 +319,13 @@ ERROR(incorrect_explicit_closure_result_vs_return_type,none, (Type, Type)) ERROR(addressable_not_enabled,none, - "@_addressable is an experimental feature", ()) + "'@_addressable' is an experimental feature", ()) ERROR(addressableSelf_not_on_method,none, - "@_addressableSelf cannot be applied to non-member declarations", ()) + "'@_addressableSelf' cannot be applied to non-member declarations", ()) ERROR(addressable_types_not_enabled,none, - "@_addressableForDependencies is an experimental feature", ()) + "'@_addressableForDependencies' is an experimental feature", ()) ERROR(class_cannot_be_addressable_for_dependencies,none, - "a class cannot be @_addressableForDependencies", ()) + "a class cannot be '@_addressableForDependencies'", ()) ERROR(unsupported_closure_attr,none, "%select{attribute |}0%1 is not supported on a closure", @@ -855,6 +864,14 @@ ERROR(serialization_failed,none, WARNING(can_import_invalid_swiftmodule,none, "canImport() evaluated to false due to invalid swiftmodule: %0", (StringRef)) +ERROR(map_os_version_from_textual_interface_failed,none, + "failed to map OS version from %0 to %1 in %2", + (StringRef, StringRef, StringRef)) + +ERROR(target_os_version_from_textual_interface_invalid,none, + "invalid target triple %0 in %1", + (StringRef, StringRef)) + ERROR(serialization_load_failed,Fatal, "failed to load module '%0'", (StringRef)) ERROR(module_interface_build_failed,Fatal, @@ -1211,11 +1228,13 @@ ERROR(module_not_compiled_with_library_evolution,none, "module %0 was not compiled with library evolution support; " "using it means binary compatibility for %1 can't be guaranteed", (Identifier, Identifier)) -WARNING(implementation_only_requires_library_evolution,none, +GROUPED_WARNING(implementation_only_requires_library_evolution, + ImplementationOnlyDeprecated,none, "using '@_implementationOnly' without enabling library evolution " "for %0 may lead to instability during execution", (Identifier)) -WARNING(implementation_only_deprecated,none, +GROUPED_WARNING(implementation_only_deprecated, + ImplementationOnlyDeprecated,none, "'@_implementationOnly' is deprecated, use 'internal import' instead", ()) @@ -1262,6 +1281,10 @@ REMARK(macro_loaded,none, "compiler plugin server '%2' with shared library '%3'}1", (Identifier, unsigned, StringRef, StringRef)) +ERROR(resolved_macro_changed,none, + "resolved macro library '%0' failed verification: %1", + (StringRef, StringRef)) + REMARK(transitive_dependency_behavior,none, "%1 has %select{a required|an optional|an ignored}2 " "transitive dependency on '%0'", @@ -1678,20 +1701,20 @@ NOTE(unbound_generic_parameter_explicit_fix,none, "explicitly specify the generic arguments to fix this issue", ()) GROUPED_ERROR(invalid_dynamic_callable_type,DynamicCallable,none, - "@dynamicCallable attribute requires %0 to have either a valid " + "'@dynamicCallable' requires %0 to have either a valid " "'dynamicallyCall(withArguments:)' method or " "'dynamicallyCall(withKeywordArguments:)' method", (Type)) GROUPED_ERROR(missing_dynamic_callable_kwargs_method,DynamicCallable,none, - "@dynamicCallable type %0 cannot be applied with keyword arguments; " + "'@dynamicCallable' type %0 cannot be applied with keyword arguments; " "missing 'dynamicCall(withKeywordArguments:)' method", (Type)) ERROR(invalid_dynamic_member_lookup_type,none, - "@dynamicMemberLookup attribute requires %0 to have a " + "'@dynamicMemberLookup' requires %0 to have a " "'subscript(dynamicMember:)' method that accepts either " "'ExpressibleByStringLiteral' or a key path", (Type)) NOTE(invalid_dynamic_member_subscript, none, "add an explicit argument label to this subscript to satisfy " - "the @dynamicMemberLookup requirement", ()) + "the '@dynamicMemberLookup' requirement", ()) ERROR(string_index_not_integer,none, "String must not be indexed with %0, it has variable size elements", @@ -1709,7 +1732,7 @@ ERROR(c_function_pointer_from_generic_function,none, "a C function pointer cannot be formed from a reference to a generic " "function", ()) ERROR(invalid_autoclosure_forwarding,none, - "add () to forward @autoclosure parameter", ()) + "add () to forward '@autoclosure' parameter", ()) ERROR(invalid_differentiable_function_conversion_expr,none, "a '@differentiable' function can only be formed from " "a reference to a 'func' or 'init' or a literal closure", ()) @@ -1764,25 +1787,25 @@ ERROR(transparent_in_classes_not_supported,none, "'@_transparent' attribute is not supported on declarations within classes", ()) ERROR(iboutlet_nonobjc_class,none, - "@IBOutlet property cannot %select{have|be an array of}0 " + "'@IBOutlet' property cannot %select{have|be an array of}0 " "non-'@objc' class type %1", (bool, Type)) ERROR(iboutlet_nonobjc_protocol,none, - "@IBOutlet property cannot %select{have|be an array of}0 " + "'@IBOutlet' property cannot %select{have|be an array of}0 " "non-'@objc' protocol type %1", (bool, Type)) ERROR(iboutlet_nonobject_type,none, - "@IBOutlet property cannot %select{have|be an array of}0 " + "'@IBOutlet' property cannot %select{have|be an array of}0 " "non-object type %1", (bool, Type)) ERROR(iboutlet_only_mutable,none, - "@IBOutlet attribute requires property to be mutable", ()) + "'@IBOutlet' requires property to be mutable", ()) ERROR(iboutlet_non_optional,none, - "@IBOutlet property has non-optional type %0", (Type)) + "'@IBOutlet' property has non-optional type %0", (Type)) NOTE(note_make_optional,none, "add '?' to form the optional type %0", (Type)) NOTE(note_make_implicitly_unwrapped_optional,none, "add '!' to form an implicitly unwrapped optional", ()) ERROR(invalid_ibdesignable_extension,none, - "@IBDesignable can only be applied to classes and extensions " + "'@IBDesignable' can only be applied to classes and extensions " "of classes", ()) ERROR(attr_must_be_used_on_class_instance,none, "only class instance properties can be declared %0", (DeclAttribute)) @@ -1811,11 +1834,11 @@ NOTE(remove_async_add_task,none, "remove 'async' and wrap in 'Task' to use concurrency in %0", (const FuncDecl *)) ERROR(no_objc_tagged_pointer_not_class_protocol,none, - "@unsafe_no_objc_tagged_pointer can only be applied to class protocols", + "'@unsafe_no_objc_tagged_pointer' can only be applied to class protocols", ()) ERROR(swift_native_objc_runtime_base_not_on_root_class,none, - "@_swift_native_objc_runtime_base_not_on_root_class can only be applied " - "to root classes", ()) + "'@_swift_native_objc_runtime_base_not_on_root_class' can only be " + "applied to root classes", ()) WARNING(objc_implementation_early_spelling_deprecated,none, "'@_objcImplementation' is deprecated; use '@implementation' instead", @@ -2032,13 +2055,13 @@ ERROR(cdecl_not_at_top_level,none, ERROR(cdecl_empty_name,none, "@_cdecl symbol name cannot be empty", ()) ERROR(cdecl_throws,none, - "raising errors from @_cdecl functions is not supported", ()) + "raising errors from '@_cdecl' functions is not supported", ()) // @_used and @_section ERROR(section_linkage_markers_disabled,none, "attribute requires '-enable-experimental-feature SymbolLinkageMarkers'", ()) ERROR(section_empty_name,none, - "@_section section name cannot be empty", ()) + "'@_section' section name cannot be empty", ()) // @_silgen_name and friends WARNING(reserved_runtime_symbol_name,none, @@ -2048,23 +2071,24 @@ WARNING(reserved_runtime_symbol_name,none, // @_extern ERROR(attr_extern_experimental,none, - "@_extern requires '-enable-experimental-feature Extern'", ()) + "'@_extern' requires '-enable-experimental-feature Extern'", ()) ERROR(extern_not_at_top_level_func,none, - "@_extern attribute can only be applied to global functions", ()) + "'@_extern' can only be applied to global functions", ()) ERROR(extern_empty_c_name,none, - "expected non-empty C name in @_extern attribute", ()) + "expected non-empty C name in '@_extern'", ()) ERROR(extern_only_non_other_attr,none, - "@_extern attribute cannot be applied to an %0 declaration", + "'@_extern' cannot be applied to an %0 declaration", (DeclAttribute)) WARNING(extern_c_maybe_invalid_name, none, - "C name '%0' may be invalid; explicitly specify the name in @_extern(c) to suppress this warning", + "C name '%0' may be invalid; explicitly specify the name in " + "'@_extern(c)' to suppress this warning", (StringRef)) // @_staticExclusiveOnly ERROR(attr_static_exclusive_only_disabled,none, "attribute requires '-enable-experimental feature StaticExclusiveOnly'", ()) ERROR(attr_static_exclusive_only_noncopyable,none, - "@_staticExclusiveOnly can only be applied to noncopyable types", ()) + "'@_staticExclusiveOnly' can only be applied to noncopyable types", ()) ERROR(attr_static_exclusive_only_let_only,none, "variable of type %0 must be declared with a 'let'", (Type)) NOTE(attr_static_exclusive_only_type_nonmutating,none, @@ -2078,11 +2102,12 @@ ERROR(attr_static_exclusive_no_setters,none, // @extractConstantsFromMembers ERROR(attr_extractConstantsFromMembers_experimental,none, - "@extractConstantsFromMembers requires '-enable-experimental-feature ExtractConstantsFromMembers'", ()) + "'@extractConstantsFromMembers' requires " + "'-enable-experimental-feature ExtractConstantsFromMembers'", ()) // @sensitive ERROR(attr_sensitive_experimental,none, - "@sensitive requires '-enable-experimental-feature Sensitive'", ()) + "'@sensitive' requires '-enable-experimental-feature Sensitive'", ()) ERROR(c_func_variadic, none, "cannot declare variadic argument %0 in %kind1", @@ -2098,18 +2123,20 @@ ERROR(c_func_throws,none, "raising errors from C functions is not supported", ()) ERROR(expose_wasm_not_at_top_level_func,none, - "@_expose attribute with 'wasm' can only be applied to global functions", ()) + "'@_expose' with 'wasm' can only be applied to global " + "functions", ()) ERROR(expose_only_non_other_attr,none, - "@_expose attribute cannot be applied to an '%0' declaration", (StringRef)) + "'@_expose' cannot be applied to an '%0' declaration", + (StringRef)) ERROR(expose_inside_unexposed_decl,none, - "@_expose attribute cannot be applied inside of unexposed declaration %0", + "'@_expose' cannot be applied inside of unexposed declaration %0", (const ValueDecl *)) ERROR(expose_invalid_name_pattern_init,none, - "invalid declaration name '%0' specified in an @_expose attribute; " + "invalid declaration name '%0' specified in '@_expose'; " "exposed initializer name must start with 'init'", (StringRef)) ERROR(expose_unsupported_objc_decl_to_cxx,none, - "@objc %kind0 can not yet be exposed to C++", (ValueDecl *)) + "'@objc' %kind0 can not yet be exposed to C++", (ValueDecl *)) ERROR(expose_unsupported_async_decl_to_cxx,none, "async %kind0 can not be exposed to C++", (ValueDecl *)) ERROR(expose_unsupported_actor_isolated_to_cxx,none, @@ -2232,7 +2259,7 @@ ERROR(attribute_does_not_apply_to_type,none, ERROR(optional_attribute_non_protocol,none, "'optional' can only be applied to protocol members", ()) ERROR(optional_attribute_non_objc_protocol,none, - "'optional' can only be applied to members of an @objc protocol", ()) + "'optional' can only be applied to members of an '@objc' protocol", ()) ERROR(optional_attribute_missing_explicit_objc,none, "'optional' requirements are an Objective-C compatibility feature; add '@objc'", ()) @@ -2241,25 +2268,25 @@ ERROR(objcmembers_attribute_nonclass,none, ERROR(optional_attribute_initializer,none, "'optional' cannot be applied to an initializer", ()) ERROR(unavailable_method_non_objc_protocol,none, - "protocol members can only be marked unavailable in an @objc protocol", + "protocol members can only be marked unavailable in an '@objc' protocol", ()) ERROR(spi_available_malformed,none, "SPI available only supports introducing version on specific platform", ()) ERROR(missing_in_class_init_1,none, "stored property %0 requires an initial value%select{| or should be " - "@NSManaged}1", (Identifier, bool)) + "'@NSManaged'}1", (Identifier, bool)) ERROR(missing_in_class_init_2,none, "stored properties %0 and %1 require initial values%select{| or should " - "be @NSManaged}2", + "be '@NSManaged'}2", (Identifier, Identifier, bool)) ERROR(missing_in_class_init_3plus,none, "stored properties %0, %1, %select{and %2|%2, and others}3 " - "require initial values%select{| or should be @NSManaged}4", + "require initial values%select{| or should be '@NSManaged'}4", (Identifier, Identifier, Identifier, bool, bool)) NOTE(requires_stored_property_inits_here,none, "%select{superclass|class}1 %0 requires all stored properties to have " - "initial values%select{| or use @NSManaged}2", (Type, bool, bool)) + "initial values%select{| or use '@NSManaged'}2", (Type, bool, bool)) ERROR(class_without_init,none, "%select{class|actor}0 %1 has no initializers", (bool, Type)) NOTE(note_no_in_class_init_1,none, @@ -2306,8 +2333,8 @@ ERROR(originally_definedin_must_not_before_available_version,none, "the OSs", ()) WARNING(spi_preferred_over_spi_available,none, - "symbols that are @_spi_available on all platforms should use @_spi " - "instead", ()) + "symbols that are '@_spi_available' on all platforms should use " + "'@_spi' instead", ()) // Alignment attribute ERROR(alignment_not_power_of_two,none, @@ -2315,13 +2342,20 @@ ERROR(alignment_not_power_of_two,none, // Dependency Scanning ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef)) +GROUPED_ERROR(dependency_scan_module_not_found_on_specified_search_paths, MissingModuleOnKnownPaths, none, + "Compilation search paths unable to resolve module dependency: '%0'", (StringRef)) NOTE(unresolved_import_location,none, "also imported here", ()) NOTE(dependency_as_imported_by_main_module,none, "a dependency of main module '%0'", (StringRef)) NOTE(dependency_as_imported_by, none, "a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool)) +NOTE(inherited_search_path_resolves_module,none, + "'%0' can be found using a search path that was specified when building module '%1' ('%2'). " + "This search path was not explicitly specified on the current compilation.", (StringRef, StringRef, StringRef)) + ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef)) +ERROR(clang_header_dependency_scan_error, none, "Bridging header dependency scan failure: %0", (StringRef)) // Enum annotations ERROR(indirect_case_without_payload,none, @@ -2740,16 +2774,16 @@ NOTE(non_sendable_nominal,none, NOTE(add_nominal_sendable_conformance,none, "consider making %kind0 conform to the 'Sendable' protocol", (const ValueDecl *)) -NOTE(add_generic_parameter_sendable_conformance,none, - "consider making generic parameter %0 conform to the 'Sendable' protocol", - (Type)) +NOTE(add_generic_parameter_conformance,none, + "consider making generic parameter %0 conform to the %1 protocol", + (Type, ProtocolDecl *)) WARNING(add_predates_concurrency_import,none, "add '@preconcurrency' to %select{suppress|treat}0 " "'Sendable'-related %select{warnings|errors}0 from module %1" "%select{| as warnings}0", (bool, Identifier)) GROUPED_WARNING(remove_predates_concurrency_import,PreconcurrencyImport, DefaultIgnore, - "'@preconcurrency' attribute on module %0 has no effect", (Identifier)) + "'@preconcurrency' on module %0 has no effect", (Identifier)) WARNING(remove_public_import,none, "public import of %0 was not used in public declarations or inlinable code", (Identifier)) @@ -2759,9 +2793,6 @@ WARNING(remove_package_import,none, WARNING(public_decl_needs_sendable,none, "public %kind0 does not specify whether it is 'Sendable' or not", (const ValueDecl *)) -NOTE(explicit_unchecked_sendable,none, - "add '@unchecked Sendable' conformance to %kind0 if this type manually implements concurrency safety", - (const ValueDecl *)) NOTE(explicit_disable_sendable,none, "make %kind0 explicitly non-Sendable to suppress this warning", (const ValueDecl *)) @@ -2877,11 +2908,11 @@ ERROR(non_class_cannot_conform_to_class_protocol,none, "non-class type %0 cannot conform to class protocol %1", (Type, Type)) ERROR(cf_class_cannot_conform_to_objc_protocol,none, - "Core Foundation class %0 cannot conform to @objc protocol %1 because " + "Core Foundation class %0 cannot conform to '@objc' protocol %1 because " "Core Foundation types are not classes in Objective-C", (Type, Type)) ERROR(objc_runtime_visible_cannot_conform_to_objc_protocol,none, - "class %0 cannot conform to @objc protocol %1 because " + "class %0 cannot conform to '@objc' protocol %1 because " "the class is only visible via the Objective-C runtime", (Type, Type)) ERROR(objc_generics_cannot_conditionally_conform,none, @@ -2889,13 +2920,13 @@ ERROR(objc_generics_cannot_conditionally_conform,none, "the type uses the Objective-C generics model", (Type, Type)) ERROR(objc_protocol_cannot_have_conditional_conformance,none, - "type %0 cannot conditionally conform to @objc protocol %1 because " + "type %0 cannot conditionally conform to '@objc' protocol %1 because " "Objective-C does not support conditional conformances", (Type, Type)) ERROR(objc_protocol_in_generic_extension,none, "conformance of " "%select{class from generic context|generic class}0 " - "%1 to @objc protocol %2 cannot be in an extension", + "%1 to '@objc' protocol %2 cannot be in an extension", (bool, Type, Type)) ERROR(conditional_conformances_cannot_imply_conformances,none, "conditional conformance of type %0 to protocol %1 does not imply conformance to " @@ -3290,7 +3321,7 @@ ERROR(typealias_outside_of_protocol,none, (DeclNameRef, Type)) ERROR(objc_protocol_inherits_non_objc_protocol,none, - "@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type)) + "'@objc' protocol %0 cannot refine non-'@objc' protocol %1", (Type, Type)) ERROR(protocol_where_clause_self_requirement,none, "constraint with subject type of 'Self' is not supported; " @@ -3425,7 +3456,7 @@ NOTE(overridden_near_match_here,none, "potential overridden %kind0 here", (const ValueDecl *)) ERROR(override_decl_extension,none, - "%select{|non-@objc}0 %kind2 %select{" + "%select{|non-'@objc'}0 %kind2 %select{" "is declared in extension of %3 and cannot be overridden|" "declared in %3 cannot be overridden from extension}1", (bool, bool, const ValueDecl *, DeclName)) @@ -3535,10 +3566,10 @@ ERROR(override_typed_throws,none, "%0 that throws %1 cannot override one that throws %2", (DescriptiveDeclKind, Type, Type)) ERROR(override_throws_objc,none, - "overriding a throwing @objc %select{method|initializer}0 with " + "overriding a throwing '@objc' %select{method|initializer}0 with " "a non-throwing %select{method|initializer}0 is not supported", (bool)) ERROR(satisfy_throws_objc,none, - "satisfying a throwing @objc %select{method|initializer}0 with " + "satisfying a throwing '@objc' %select{method|initializer}0 with " "a non-throwing %select{method|initializer}0 is not supported", (bool)) ERROR(override_optional_mismatch,none, @@ -4083,19 +4114,19 @@ ERROR(isolation_in_inherits_executor,none, "#isolation%select{| (introduced by a default argument)}0 cannot be used " "within an '@_unsafeInheritExecutor' function", (bool)) ERROR(unsafe_inherits_executor_deprecated,none, - "@_unsafeInheritExecutor attribute is deprecated; consider an " + "'@_unsafeInheritExecutor' is deprecated; consider an " "'isolated' parameter defaulted to '#isolation' instead", ()) ERROR(lifetime_invalid_global_scope,none, "%0 is only valid on methods", (DeclAttribute)) ERROR(eagermove_and_lexical_combined,none, - "@_eagerMove and @_noEagerMove attributes are alternate styles of lifetimes " + "'@_eagerMove' and '@_noEagerMove' are alternate styles of lifetimes " "and can't be combined", ()) ERROR(eagermove_and_noncopyable_combined,none, - "@_eagerMove cannot be applied to NonCopyable types", ()) + "'@_eagerMove' cannot be applied to NonCopyable types", ()) ERROR(autoclosure_function_type,none, - "@autoclosure attribute only applies to function types", + "'@autoclosure' only applies to function types", ()) ERROR(invalid_autoclosure_and_convention_attributes,none, @@ -4103,10 +4134,11 @@ ERROR(invalid_autoclosure_and_convention_attributes,none, (StringRef)) ERROR(autoclosure_function_input_nonunit,none, - "argument type of @autoclosure parameter must be '()'", ()) + "argument type of '@autoclosure' parameter must be '()'", ()) ERROR(escaping_non_function_parameter,none, - "@escaping attribute may only be used in function parameter position", ()) + "'@escaping' may only be used in function parameter position", + ()) ERROR(escaping_inout_parameter,none, "inout expression is implicitly escaping", ()) @@ -4127,34 +4159,34 @@ ERROR(instancemember_compilerinitialized,none, // @_nonEphemeral attribute ERROR(non_ephemeral_non_pointer_type,none, - "@_nonEphemeral attribute only applies to pointer types", ()) + "'@_nonEphemeral' only applies to pointer types", ()) // NSManaged attribute ERROR(attr_NSManaged_not_instance_member,none, - "@NSManaged only allowed on an instance property or method", ()) + "'@NSManaged' only allowed on an instance property or method", ()) ERROR(attr_NSManaged_not_stored,none, - "@NSManaged not allowed on %select{computed|observing|addressed}0 " + "'@NSManaged' not allowed on %select{computed|observing|addressed}0 " "properties", (unsigned)) ERROR(attr_NSManaged_let_property,none, - "@NSManaged not allowed on a 'let' property", ()) + "'@NSManaged' not allowed on a 'let' property", ()) ERROR(attr_NSManaged_initial_value,none, - "@NSManaged property cannot have an initial value", ()) + "'@NSManaged' property cannot have an initial value", ()) ERROR(attr_NSManaged_NSCopying,none, - "@NSManaged property cannot also be marked @NSCopying", ()) + "'@NSManaged' property cannot also be marked '@NSCopying'", ()) ERROR(attr_NSManaged_method_body,none, - "@NSManaged method cannot have a body; it must be provided at runtime",()) + "'@NSManaged' method cannot have a body; it must be provided at runtime",()) // NSCopying attribute ERROR(nscopying_only_on_class_properties,none, - "@NSCopying may only be used on properties in classes", + "'@NSCopying' may only be used on properties in classes", ()) ERROR(nscopying_only_mutable,none, - "@NSCopying requires property to be mutable", ()) + "'@NSCopying' requires property to be mutable", ()) ERROR(nscopying_only_stored_property,none, - "@NSCopying is only valid on stored properties", ()) + "'@NSCopying' is only valid on stored properties", ()) ERROR(nscopying_doesnt_conform,none, - "@NSCopying is only valid with types that conform to" + "'@NSCopying' is only valid with types that conform to" " the NSCopying protocol", ()) // UIApplicationMain/NSApplicationMain attribute @@ -4181,7 +4213,7 @@ ERROR(attr_ApplicationMain_deprecated,none, "%" SELECT_APPLICATION_MAIN "0 is deprecated", (unsigned)) NOTE(attr_ApplicationMain_deprecated_use_attr_main,none, - "use @main instead", ()) + "use '@main' instead", ()) NOTE(attr_ApplicationMain_parse_as_library,none, "pass '-parse-as-library' to compiler invocation if this is intentional", @@ -4191,8 +4223,8 @@ NOTE(attr_ApplicationMain_script_here,none, ()) ERROR(attr_MainType_without_main,none, - "%0 is annotated with @main and must provide a main static function of type %" - SELECT_APPLICATION_MAIN_TYPES "1", + "%0 is annotated with '@main' and must provide a main static function " + "of type %" SELECT_APPLICATION_MAIN_TYPES "1", (const ValueDecl *, bool)) #undef SELECT_APPLICATION_MAIN_TYPES @@ -4200,16 +4232,18 @@ ERROR(attr_MainType_without_main,none, #undef SELECT_APPLICATION_DELEGATE ERROR(attr_rawlayout_experimental,none, - "the @_rawLayout attribute is experimental", ()) + "the '@_rawLayout' attribute is experimental", ()) ERROR(attr_rawlayout_cannot_be_copyable,none, - "type with @_rawLayout cannot be copied and must be declared ~Copyable", ()) + "type with '@_rawLayout' cannot be copied and must be declared ~Copyable", + ()) ERROR(attr_rawlayout_cannot_have_stored_properties,none, - "type with @_rawLayout cannot have stored properties", ()) + "type with '@_rawLayout' cannot have stored properties", ()) ERROR(attr_rawlayout_cannot_have_alignment_attr,none, - "type with @_rawLayout cannot also have an @_alignment attribute", ()) + "type with '@_rawLayout' cannot also have an '@_alignment' attribute", ()) ERROR(attr_rawlayout_invalid_count_type,none, - "@_rawLayout count must either be integer literal or a generic argument", ()) - + "'@_rawLayout' count must either be integer literal or a generic " + "argument", ()) + // lazy ERROR(lazy_not_on_let,none, "'lazy' cannot be used on a let", ()) @@ -4233,14 +4267,14 @@ ERROR(lazy_var_storage_access,none, // Debugger function attribute. ERROR(attr_for_debugger_support_only,none, - "@LLDBDebuggerSupport may only be used when debugger support is on", ()) + "'@LLDBDebuggerSupport' may only be used when debugger support is on", ()) // @_implements ERROR(implements_attr_protocol_lacks_member,none, "protocol %0 has no member %1", (const ProtocolDecl *, DeclName)) ERROR(implements_attr_non_protocol_type,none, - "non-protocol type in @_implements attribute", ()) + "non-protocol type in '@_implements'", ()) ERROR(implements_attr_protocol_not_conformed_to,none, "containing type %0 does not conform to protocol %1", @@ -4887,7 +4921,7 @@ WARNING(bitcasting_away_noescape, none, "'withoutActuallyEscaping' to temporarily escape a function", (Type, Type)) WARNING(bitcasting_to_change_function_rep, none, - "'unsafeBitCast' from function type %0 to %1 changes @convention and " + "'unsafeBitCast' from function type %0 to %1 changes '@convention' and " "is undefined; use an implicit conversion to change conventions", (Type, Type)) WARNING(bitcasting_to_downcast, none, @@ -4958,6 +4992,8 @@ NOTE(iuo_to_any_coercion_note_func_result,none, (const ValueDecl *)) NOTE(default_optional_to_any,none, "provide a default value to avoid this warning", ()) +NOTE(default_optional_parameter,none, + "use a default value parameter to avoid this warning", ()) NOTE(force_optional_to_any,none, "force-unwrap the value to avoid this warning", ()) NOTE(silence_optional_to_any,none, @@ -4971,35 +5007,35 @@ NOTE(silence_debug_description_in_interpolation_segment_call,none, "use 'String(describing:)' to silence this warning", ()) NOTE(noescape_parameter,none, - "parameter %1 is implicitly %select{non-escaping|non-sendable}0", + "parameter %1 is implicitly %select{non-escaping|non-Sendable}0", (unsigned, Identifier)) NOTE(generic_parameters_always_escaping,none, "generic parameters are always considered '@escaping'", ()) ERROR(passing_noattrfunc_to_attrfunc,none, - "passing %select{non-escaping|non-sendable}0 parameter %1 to function " - "expecting %select{an @escaping|a @Sendable}0 closure", + "passing %select{non-escaping|non-Sendable}0 parameter %1 to function " + "expecting %select{an '@escaping'|a '@Sendable'}0 closure", (unsigned, Identifier)) ERROR(converting_noescape_param_to_generic_type,none, "converting non-escaping parameter %0 to generic parameter %1 may allow it to escape", (Identifier, Type)) ERROR(assigning_noattrfunc_to_attrfunc,none, - "assigning %select{non-escaping|non-sendable}0 parameter %1 to " - "%select{an @escaping|a @Sendable}0 closure", + "assigning %select{non-escaping|non-Sendable}0 parameter %1 to " + "%select{an '@escaping'|a '@Sendable'}0 closure", (unsigned, Identifier)) ERROR(general_noattrfunc_to_attr,none, - "using %select{non-escaping|non-sendable}0 parameter %1 in a context " - "expecting %select{an @escaping|a @Sendable}0 closure", + "using %select{non-escaping|non-Sendable}0 parameter %1 in a context " + "expecting %select{an '@escaping'|a '@Sendable'}0 closure", (unsigned, Identifier)) ERROR(converting_noattrfunc_to_type,none, - "converting %select{non-escaping|non-sendable function}0 value to %1 " + "converting %select{non-escaping|non-Sendable function}0 value to %1 " "may %select{allow it to escape|introduce data races}0", (unsigned, Type)) NOTE(escape_expected_at_parameter_position,none, "parameter #%0 expects escaping value of type %1", (unsigned, Type)) NOTE(add_explicit_escaping,none, - "add explicit @escaping to function parameter #%0", + "add explicit '@escaping' to function parameter #%0", (unsigned)) ERROR(converting_func_loses_global_actor,none, @@ -5009,6 +5045,10 @@ ERROR(capture_across_type_decl,none, "%0 declaration cannot close over value %1 defined in outer scope", (DescriptiveDeclKind, Identifier)) +ERROR(isolated_any_conversion_to_synchronous_func,none, + "converting @isolated(any) function of type %0 to synchronous function type %1 is not allowed", + (Type, Type)) + ERROR(reference_to_invalid_decl,none, "cannot reference invalid declaration %0", (const ValueDecl *)) @@ -5106,6 +5146,9 @@ ERROR(assignment_bang_has_immutable_subcomponent,none, NOTE(candidate_is_not_assignable,none, "candidate is not assignable: %kind0", (const ValueDecl *)) +NOTE(candidate_expects_inout_argument,none, + "candidate expects in-out value for parameter #%0 but argument is immutable", + (unsigned)) NOTE(change_to_mutating,none, "mark %select{method|%1}0 'mutating' to make 'self' mutable", @@ -5475,10 +5518,11 @@ ERROR(not_objc_function_async,none, NOTE(not_objc_function_type_async,none, "'async' function types cannot be represented in Objective-C", ()) ERROR(actor_isolated_objc,none, - "actor-isolated %kind0 cannot be @objc", + "actor-isolated %kind0 cannot be '@objc'", (const ValueDecl *)) NOTE(protocol_witness_async_conflict,none, - "candidate is %select{not |}0'async', but%select{| @objc}1 protocol requirement is%select{| not}0", + "candidate is %select{not |}0'async', but%select{| '@objc'}1 protocol " + "requirement is%select{| not}0", (bool, bool)) ERROR(async_autoclosure_nonasync_function,none, "'async' autoclosure parameter in a non-'async' function", ()) @@ -5560,6 +5604,9 @@ ERROR(actor_isolated_non_self_reference,none, "from a nonisolated autoclosure}2", (const ValueDecl *, unsigned, unsigned, Type, ActorIsolation)) +ERROR(actor_isolated_access_outside_of_actor_context,none, + "%0 %kind1 cannot be %select{accessed|called}2 from outside of the actor", + (ActorIsolation, const ValueDecl *, bool)) ERROR(distributed_actor_isolated_non_self_reference,none, "distributed actor-isolated %kind0 can not be accessed from a " "nonisolated context", @@ -5627,15 +5674,15 @@ GROUPED_ERROR(concurrent_access_of_inout_param,SendableClosureCaptures,none, "concurrently-executing code", (DeclName)) GROUPED_ERROR(non_sendable_capture,SendableClosureCaptures,none, - "capture of %1 with non-sendable type %0 in a '@Sendable' " + "capture of %1 with non-Sendable type %0 in a '@Sendable' " "%select{local function|closure}2", (Type, DeclName, bool)) ERROR(non_sendable_isolated_capture,none, - "capture of %1 with non-sendable type %0 in an isolated " + "capture of %1 with non-Sendable type %0 in an isolated " "%select{local function|closure}2", (Type, DeclName, bool)) -ERROR(non_sendable_metatype_capture,none, - "capture of non-sendable type %0 in an isolated " +GROUPED_ERROR(non_sendable_metatype_capture,SendableMetatypes,none, + "capture of non-Sendable type %0 in an isolated " "%select{local function|closure}1", (Type, bool)) ERROR(self_capture_deinit_task,none, @@ -5771,78 +5818,78 @@ NOTE(in_derived_witness, none, (DescriptiveDeclKind, DeclName, Type)) ERROR(non_sendable_arg_into_actor,none, - "non-sendable type %0 cannot be sent into %2 context in call to %kind1", + "non-Sendable type %0 cannot be sent into %2 context in call to %kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_arg_exits_actor,none, - "non-sendable type %0 cannot exit %2 context in call to nonisolated " + "non-Sendable type %0 cannot exit %2 context in call to nonisolated " "%kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_param_in_witness,none, - "non-sendable parameter type %0 cannot be sent from caller of " + "non-Sendable parameter type %0 cannot be sent from caller of " "protocol requirement %1 into %2 implementation", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_param_in_override,none, - "non-sendable parameter type %0 cannot be sent from caller of " + "non-Sendable parameter type %0 cannot be sent from caller of " "superclass %kind1 into %2 override", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_param_in_objc,none, - "non-sendable parameter type %0 of %2 '@objc' %kind1 cannot cross actor " + "non-Sendable parameter type %0 of %2 '@objc' %kind1 cannot cross actor " "boundary", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_result_into_actor,none, - "non-sendable result type %0 cannot be sent from %2 context in call " + "non-Sendable result type %0 cannot be sent from %2 context in call " "to %kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_result_exits_actor,none, - "non-sendable result type %0 cannot exit %2 context in call to " + "non-Sendable result type %0 cannot exit %2 context in call to " "nonisolated %kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_result_in_witness,none, - "non-sendable type %0 cannot be returned from %2 implementation " + "non-Sendable type %0 cannot be returned from %2 implementation " "to caller of protocol requirement %1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_result_in_override,none, - "non-sendable type %0 cannot be returned from %2 override to " + "non-Sendable type %0 cannot be returned from %2 override to " "caller of superclass %kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_result_in_objc,none, - "non-sendable type %0 returned by %2 '@objc' %kind1 cannot cross " + "non-Sendable type %0 returned by %2 '@objc' %kind1 cannot cross " "actor boundary", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_call_result_type,none, - "non-sendable result type %0 cannot be sent from %1 context in call " + "non-Sendable result type %0 cannot be sent from %1 context in call " "to async function", (Type, ActorIsolation)) ERROR(non_sendable_property_exits_actor,none, - "non-sendable type %0 of %kind1 cannot exit %2 context", + "non-Sendable type %0 of %kind1 cannot exit %2 context", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_property_into_actor,none, - "non-sendable type %0 of nonisolated %kind1 cannot be sent to " + "non-Sendable type %0 of nonisolated %kind1 cannot be sent to " "%2 context", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_property_in_witness,none, - "non-sendable type %0 cannot be returned from %2 implementation " + "non-Sendable type %0 cannot be returned from %2 implementation " "to caller of protocol requirement %1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_property_in_override,none, - "non-sendable type %0 cannot be returned from %2 override to " + "non-Sendable type %0 cannot be returned from %2 override to " "caller of superclass %kind1", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_property_in_objc,none, - "non-sendable type %0 returned by %2 '@objc' %kind1 cannot cross " + "non-Sendable type %0 returned by %2 '@objc' %kind1 cannot cross " "actor boundary", (Type, const ValueDecl *, ActorIsolation)) ERROR(non_sendable_keypath_capture,none, - "cannot form key path that captures non-sendable type %0", + "cannot form key path that captures non-Sendable type %0", (Type)) ERROR(non_concurrent_type_member,none, "%select{stored property %2|associated value %2}1 of " - "'Sendable'-conforming %kind3 has non-sendable type %0", - (Type, bool, DeclName, const ValueDecl *)) + "'Sendable'-conforming %kind3 %select{contains|has}4 non-Sendable type %0", + (Type, bool, DeclName, const ValueDecl *, bool)) ERROR(concurrent_value_class_mutable_property,none, "stored property %0 of 'Sendable'-conforming %kind1 is mutable", (DeclName, const ValueDecl *)) @@ -5859,8 +5906,11 @@ ERROR(concurrent_value_inherit,none, (bool, DeclName)) ERROR(non_sendable_type,none, "type %0 does not conform to the 'Sendable' protocol", (Type)) +GROUPED_ERROR(non_sendable_metatype_type,SendableMetatypes,none, + "type %0 does not conform to the 'SendableMetatype' protocol", (Type)) ERROR(sendable_raw_storage,none, - "struct %0 with @_rawLayout does not conform to the 'Sendable' protocol", (DeclName)) + "struct %0 with '@_rawLayout' does not conform to the 'Sendable' " + "protocol", (DeclName)) ERROR(typeattr_not_inheritance_clause,none, "'%0' attribute only applies in inheritance clauses", (StringRef)) @@ -5868,13 +5918,14 @@ ERROR(typeattr_not_existential,none, "'%0' attribute cannot apply to non-protocol type %1", (StringRef, Type)) WARNING(unchecked_conformance_not_special,none, - "@unchecked conformance to %0 has no meaning", (Type)) + "'@unchecked' conformance to %0 has no meaning", (Type)) WARNING(restate_unchecked_sendable,none, "class %0 must restate inherited '@unchecked Sendable' conformance", (DeclName)) WARNING(preconcurrency_conformance_not_used,none, - "@preconcurrency attribute on conformance to %0 has no effect", (Type)) + "'@preconcurrency' on conformance to %0 has no effect", + (Type)) ERROR(redundant_any_in_existential,none, "redundant 'any' in type %0", @@ -5933,7 +5984,7 @@ ERROR(nonisolated_lazy,none, ()) ERROR(non_sendable_from_deinit,none, - "cannot access %1 %2 with a non-sendable type %0 from nonisolated deinit", + "cannot access %1 %2 with a non-Sendable type %0 from nonisolated deinit", (Type, DescriptiveDeclKind, DeclName)) ERROR(actor_instance_property_wrapper,none, @@ -6015,7 +6066,7 @@ ERROR(actor_isolation_multiple_attr_2,none, "%kind0 has multiple actor-isolation attributes (%1 and %2)", (const Decl *, DeclAttribute, DeclAttribute)) ERROR(actor_isolation_multiple_attr_3,none, - "%0 %1 has multiple actor-isolation attributes (%2, %3 and %4)", + "%0 %1 has multiple actor-isolation attributes (%2, %3, and %4)", (const Decl *, DeclAttribute, DeclAttribute, DeclAttribute)) ERROR(actor_isolation_multiple_attr_4,none, "%0 %1 has multiple actor-isolation attributes (%2, %3, %4, and %5)", @@ -6276,8 +6327,9 @@ ERROR(unreferenced_generic_parameter,NoUsage, "generic parameter '%0' is not used in function signature", (StringRef)) ERROR(unexpected_ctype_for_non_c_convention,none, "convention '%0' does not support the 'cType' argument label, did you " - "mean @convention(c, cType: \"%1\") or @convention(block, cType: \"%1\") " - "instead?", (StringRef, StringRef)) + "mean '@convention(c, cType: \"%1\")' or " + "'@convention(block, cType: \"%1\")' instead?", + (StringRef, StringRef)) ERROR(unable_to_parse_c_function_type,none, "unable to parse '%0'; it should be a C function pointer type or a " "block pointer type", (StringRef)) @@ -6331,20 +6383,21 @@ ERROR(differentiable_function_type_no_differentiability_parameters, // SIL ERROR(opened_bad_constraint_type,none, - "@opened constraint type %0 is not a protocol or protocol composition", (Type)) + "'@opened' constraint type %0 is not a protocol or protocol composition", + (Type)) ERROR(opened_bad_interface_type,none, - "@opened interface type %0 is not a type parameter", (Type)) + "'@opened' interface type %0 is not a type parameter", (Type)) ERROR(sil_function_input_label,PointsToFirstBadToken, "SIL function types cannot have labeled inputs", ()) ERROR(sil_non_coro_yields,PointsToFirstBadToken, - "non-coroutine SIL function types cannot have @yield results", ()) + "non-coroutine SIL function types cannot have '@yield' results", ()) ERROR(sil_function_invalid_convention,PointsToFirstBadToken, "convention attribute isn't valid on a %select{parameter|result|callee}0", (unsigned)) ERROR(ast_subst_function_type,none, "substitutions cannot be provided on a formal function type", ()) ERROR(sil_function_multiple_error_results,PointsToFirstBadToken, - "SIL function types cannot have multiple @error results", ()) + "SIL function types cannot have multiple '@error' results", ()) ERROR(unsupported_sil_convention,none, "convention '%0' not supported in SIL", (StringRef)) ERROR(illegal_sil_type,none, @@ -6352,17 +6405,19 @@ ERROR(illegal_sil_type,none, ERROR(sil_box_arg_mismatch,none, "SIL box type has wrong number of generic arguments for layout", ()) ERROR(sil_pack_element_uuid_not_found,none, - "open_pack_element instruction not found for @pack_element type UUID; " + "open_pack_element instruction not found for '@pack_element' type UUID; " "possible forward reference?", ()) // SIL Metatypes ERROR(sil_metatype_without_repr,none, - "metatypes in SIL must have @thin, @thick, or @objc_metatype attribute", + "metatypes in SIL must be '@thin', '@thick', or '@objc_metatype'", ()) ERROR(sil_metatype_multiple_reprs,none, - "metatypes in SIL can only be one of @thin, @thick, or @objc_metatype", + "metatypes in SIL can only be one of '@thin', '@thick', or " + "'@objc_metatype'", ()) ERROR(sil_metatype_not_metatype,none, - "@thin, @thick, or @objc_metatype can only apply to metatype types in SIL", + "'@thin', '@thick', or '@objc_metatype' can only apply to metatype " + "types in SIL", ()) //------------------------------------------------------------------------------ @@ -6377,14 +6432,14 @@ ERROR(attr_used_without_required_module, none, (DeclAttribute, Identifier)) ERROR(invalid_objc_decl_context,none, - "@objc can only be used with members of classes, @objc protocols, and " - "concrete extensions of classes", ()) + "'@objc' can only be used with members of classes, '@objc' protocols, " + "and concrete extensions of classes", ()) ERROR(invalid_objc_decl,none, "only classes (and their extensions), non-marker protocols, methods, " "initializers, properties, and subscript declarations can be declared" - " @objc", ()) + " '@objc'", ()) ERROR(invalid_objc_swift_rooted_class,none, - "only classes that inherit from NSObject can be declared @objc", ()) + "only classes that inherit from NSObject can be declared '@objc'", ()) NOTE(invalid_objc_swift_root_class_insert_nsobject,none, "inherit from 'NSObject' to silence this error", ()) @@ -6400,12 +6455,13 @@ NOTE(objc_header_sorting_arbitrary_please_report,none, "declarations", ()) ERROR(invalid_nonobjc_decl,none, - "only class members and extensions of classes can be declared @nonobjc", ()) + "only class members and extensions of classes can be declared " + "'@nonobjc'", ()) ERROR(invalid_nonobjc_extension,none, - "only extensions of classes can be declared @nonobjc", ()) + "only extensions of classes can be declared '@nonobjc'", ()) ERROR(objc_in_extension_context,none, - "members of constrained extensions cannot be declared @objc", ()) + "members of constrained extensions cannot be declared '@objc'", ()) ERROR(objc_in_generic_extension,none, "extensions of %select{classes from generic context|generic classes}0 " "cannot contain '@objc' members", (bool)) @@ -6413,9 +6469,9 @@ ERROR(objc_in_resilient_extension,none, "'@objc' %0 in extension of subclass of %1 requires %2 %3", (DescriptiveDeclKind, Identifier, AvailabilityDomain, AvailabilityRange)) ERROR(objc_operator, none, - "operator methods cannot be declared @objc", ()) + "operator methods cannot be declared '@objc'", ()) ERROR(objc_operator_proto, none, - "@objc protocols must not have operator requirements", ()) + "'@objc' protocols must not have operator requirements", ()) ERROR(objc_for_generic_class,none, "generic subclasses of '@objc' classes cannot have an explicit '@objc' " @@ -6467,7 +6523,7 @@ ERROR(objc_cannot_infer_name_raw_identifier,none, (DescriptiveDeclKind)) // If you change this, also change enum ObjCReason -#define OBJC_ATTR_SELECT "select{marked @_cdecl|marked dynamic|marked @objc|marked @objcMembers|marked @IBOutlet|marked @IBAction|marked @IBSegueAction|marked @NSManaged|a member of an @objc protocol|implicitly @objc|an @objc override|an implementation of an @objc requirement|marked @IBInspectable|marked @GKInspectable|in an @objc extension of a class (without @nonobjc)|in an @objc @implementation extension of a class (without final or @nonobjc)|marked @objc by an access note}" +#define OBJC_ATTR_SELECT "select{marked '@_cdecl'|marked dynamic|marked '@objc'|marked '@objcMembers'|marked '@IBOutlet'|marked '@IBAction'|marked '@IBSegueAction'|marked '@NSManaged'|a member of an '@objc' protocol|implicitly '@objc'|an '@objc' override|an implementation of an '@objc' requirement|marked '@IBInspectable'|marked '@GKInspectable'|in an '@objc' extension of a class (without '@nonobjc')|in an '@objc @implementation' extension of a class (without final or '@nonobjc')|marked '@objc' by an access note}" ERROR(objc_invalid_on_var,none, "property cannot be %" OBJC_ATTR_SELECT "0 " @@ -6506,7 +6562,7 @@ NOTE(not_objc_non_trivial_cxx_class,none, NOTE(not_objc_tuple,none, "tuples cannot be represented in Objective-C", ()) NOTE(not_objc_swift_class,none, - "classes not annotated with @objc cannot be represented " + "classes not annotated with '@objc' cannot be represented " "in Objective-C", ()) NOTE(not_objc_swift_struct,none, "Swift structs cannot be represented in Objective-C", ()) @@ -6534,11 +6590,11 @@ ERROR(no_opaque_return_type_of,none, ERROR(objc_observing_accessor, none, "observers (%0) are not allowed to be marked '@objc'", (DescriptiveDeclKind)) ERROR(objc_init_accessor, none, - "init accessors cannot be marked @objc", ()) + "init accessors cannot be marked '@objc'", ()) ERROR(objc_addressor, none, - "addressors are not allowed to be marked @objc", ()) + "addressors are not allowed to be marked '@objc'", ()) ERROR(objc_coroutine_accessor, none, - "'read' and 'modify' accessors are not allowed to be marked @objc", ()) + "'read' and 'modify' accessors are not allowed to be marked '@objc'", ()) ERROR(objc_invalid_on_func_variadic,none, "method cannot be %" OBJC_ATTR_SELECT "0 because it has a variadic " "parameter", (unsigned)) @@ -6673,7 +6729,7 @@ WARNING(witness_non_objc_storage_optional,none, (bool, DeclName, Identifier)) ERROR(nonobjc_not_allowed,none, - "declaration is %" OBJC_ATTR_SELECT "0, and cannot be marked @nonobjc", + "declaration is %" OBJC_ATTR_SELECT "0, and cannot be marked '@nonobjc'", (unsigned)) #undef OBJC_DIAG_SELECT_2 @@ -6684,11 +6740,12 @@ ERROR(nonobjc_not_allowed,none, // MARK: @exclusivity //------------------------------------------------------------------------------ ERROR(exclusivity_on_wrong_decl,none, - "@exclusivity can only be used on class properties, static properties and global variables", + "'@exclusivity' can only be used on class properties, static properties " + "and global variables", ()) ERROR(exclusivity_on_computed_property,none, - "@exclusivity can only be used on stored properties", + "'@exclusivity' can only be used on stored properties", ()) //------------------------------------------------------------------------------ @@ -6698,7 +6755,7 @@ ERROR(borrowed_with_objc_dynamic,none, "%0 cannot be '@_borrowed' if it is '@objc dynamic'", (DescriptiveDeclKind)) ERROR(borrowed_on_objc_protocol_requirement,none, - "%0 cannot be '@_borrowed' if it is an @objc protocol requirement", + "%0 cannot be '@_borrowed' if it is an '@objc' protocol requirement", (DescriptiveDeclKind)) ERROR(borrowed_with_effect,none, "%0 cannot be '@_borrowed' if it is 'async' or 'throws'", @@ -6741,9 +6798,9 @@ ERROR(dynamic_replacement_not_in_extension, none, ERROR(dynamic_replacement_must_not_be_dynamic, none, "dynamicReplacement(for:) of %0 must not be dynamic itself", (DeclName)) ERROR(dynamic_replacement_replaced_not_objc_dynamic, none, - "%0 is not marked @objc dynamic", (DeclName)) + "%0 is not marked '@objc dynamic'", (DeclName)) ERROR(dynamic_replacement_replacement_not_objc_dynamic, none, - "%0 is marked @objc dynamic", (DeclName)) + "%0 is marked '@objc dynamic'", (DeclName)) ERROR(dynamic_replacement_replaced_constructor_is_convenience, none, "replaced initializer %0 is marked as convenience", (DeclNameRef)) ERROR(dynamic_replacement_replaced_constructor_is_not_convenience, none, @@ -6794,14 +6851,18 @@ ERROR(availability_must_occur_alone, none, (AvailabilityDomain, bool)) ERROR(availability_unexpected_version, none, "unexpected version number for %0", (AvailabilityDomain)) -WARNING(availability_unrecognized_platform_name, - PointsToFirstBadToken, "unrecognized platform name %0", (Identifier)) -WARNING(availability_suggest_platform_name, - PointsToFirstBadToken, "unrecognized platform name %0;" - " did you mean '%1'?", +GROUPED_ERROR(availability_unrecognized_platform_name, + AvailabilityUnrecognizedName, PointsToFirstBadToken, + "unrecognized platform name %0", (Identifier)) +GROUPED_ERROR(availability_suggest_platform_name, + AvailabilityUnrecognizedName, PointsToFirstBadToken, + "unrecognized platform name %0; did you mean '%1'?", (Identifier, StringRef)) WARNING(availability_unsupported_version_number, none, "'%0' is not a supported version number", (llvm::VersionTuple)) +WARNING(availability_invalid_version_number_for_domain, none, + "'%0' is not a valid version number for %1", + (llvm::VersionTuple, AvailabilityDomain)) WARNING(attr_availability_expected_deprecated_version, none, "expected version number with 'deprecated' in '%0' attribute for %1", @@ -6893,8 +6954,8 @@ ERROR(availability_parameterized_protocol_only_version_newer, none, (AvailabilityDomain, AvailabilityRange)) ERROR(availability_isolated_any_only_version_newer, none, - "runtime support for @isolated(any) function types is only available in " - "%0 %1 or newer", + "runtime support for '@isolated(any)' function types is only available " + "in %0 %1 or newer", (AvailabilityDomain, AvailabilityRange)) ERROR(availability_copyable_generics_casting_only_version_newer, none, @@ -6920,7 +6981,7 @@ NOTE(availability_guard_with_version_check, none, "add 'if #available' version check", ()) NOTE(availability_add_attribute, none, - "add @available attribute to enclosing %0", (DescriptiveDeclKind)) + "add '@available' attribute to enclosing %0", (DescriptiveDeclKind)) FIXIT(insert_available_attr, "@available(%0 %1, *)\n%2", (StringRef, StringRef, StringRef)) @@ -7056,7 +7117,8 @@ ERROR(unavailability_query_wildcard_not_required, none, //------------------------------------------------------------------------------ WARNING(discardable_result_on_void_never_function, none, - "@discardableResult declared on a function returning %select{Never|Void}0 " + "'@discardableResult' declared on a function returning " + "'%select{Never|Void}0' " "is unnecessary", (bool)) //------------------------------------------------------------------------------ @@ -7344,7 +7406,7 @@ GROUPED_ERROR(property_wrapper_ambiguous_value_property,PropertyWrappers,none, "named %1", (Type, Identifier)) GROUPED_ERROR(property_wrapper_wrong_initial_value_init,PropertyWrappers,none, "%0 parameter type (%1) must be the same as its " - "'wrappedValue' property type (%2) or an @autoclosure thereof", + "'wrappedValue' property type (%2) or an '@autoclosure' thereof", (DeclName, Type, Type)) GROUPED_ERROR(property_wrapper_failable_init,PropertyWrappers,none, "property wrapper initializer %0 cannot be failable", (DeclName)) @@ -7408,7 +7470,7 @@ ERROR(property_wrapper_effectful,none, ERROR(property_with_wrapper_conflict_attribute,none, "property %0 with a wrapper cannot also be " - "%select{lazy|@NSCopying|@NSManaged|weak|unowned|unmanaged}1", + "%select{lazy|'@NSCopying'|'@NSManaged'|'@abi'|weak|unowned|unmanaged}1", (Identifier, int)) ERROR(property_wrapper_not_single_var, none, "property wrapper can only apply to a single variable", ()) @@ -7798,8 +7860,9 @@ WARNING(macro_type_access_warn,none, ERROR(macro_in_nested,none, "macro %0 can only be declared at file scope", (DeclName)) ERROR(macro_without_role,none, - "macro %0 must declare its applicable roles via '@freestanding' or @attached'", - (DeclName)) + "macro %0 must declare its applicable roles via '@freestanding' or " + "'@attached'", + (DeclName)) ERROR(macro_result_type_cannot_be_used,none, "only a freestanding expression macro can produce a result of type %0", (Type)) @@ -7957,7 +8020,7 @@ NOTE(note_non_bitwise_copyable_type_indirect_enum_element,none, ERROR(non_bitwise_copyable_type_suppressed,none, "cannot both conform to and suppress conformance to 'BitwiseCopyable'", ()) ERROR(non_bitwise_copyable_type_sensitive,none, - "a @sensitive type cannot conform to 'BitwiseCopyable'", ()) + "a '@sensitive' type cannot conform to 'BitwiseCopyable'", ()) ERROR(non_bitwise_copyable_type_cxx_nontrivial,none, "non-trivial C++ type cannot conform to 'BitwiseCopyable'", ()) ERROR(non_bitwise_copyable_c_type_nontrivial,none, @@ -8071,8 +8134,8 @@ ERROR(noimplicitcopy_attr_valid_only_on_local_let_params, ERROR(noimplicitcopy_attr_not_allowed_on_moveonlytype,none, "'@_noImplicitCopy' has no effect when applied to a noncopyable type", ()) ERROR(noncopyable_types_cannot_be_resilient, none, - "noncopyable %kind0 must be @frozen in library evolution mode; " - "non-@frozen public and @usableFromInline noncopyable types are not " + "noncopyable %kind0 must be '@frozen' in library evolution mode; " + "non-'@frozen' public and '@usableFromInline' noncopyable types are not " "supported", (const ValueDecl *)) ERROR(noncopyable_cannot_have_read_set_accessor,none, @@ -8089,7 +8152,7 @@ ERROR(init_accessor_can_refer_only_to_properties,none, (DescriptiveDeclKind, DeclNameRef)) ERROR(storage_restrictions_attribute_not_on_init_accessor,none, - "@storageRestrictions attribute could only be used with init accessors", + "'@storageRestrictions' could only be used with init accessors", ()) ERROR(init_accessor_property_both_init_and_accessed,none, "property %0 cannot be both initialized and accessed", @@ -8132,6 +8195,9 @@ ERROR(pack_iteration_where_clause_not_supported, none, // MARK: Lifetime Dependence Syntax //------------------------------------------------------------------------------ +WARNING(use_lifetime_underscored, PointsToFirstBadToken, + "Unsupported use of @lifetime, use @_lifetime to specify lifetime dependencies", ()) + ERROR(lifetime_dependence_invalid_param_name, none, "invalid parameter name specified %0", (Identifier)) ERROR(lifetime_dependence_invalid_param_index, none, @@ -8166,42 +8232,46 @@ ERROR(lifetime_dependence_immortal_alone, none, "cannot specify any other dependence source along with immortal", ()) ERROR(lifetime_dependence_invalid_inherit_escapable_type, none, "cannot copy the lifetime of an Escapable type, use " - "'@lifetime(borrow %0)' instead", + "'@_lifetime(%0%1)' instead", + (StringRef, StringRef)) +ERROR(lifetime_dependence_parsed_borrow_with_ownership, none, + "invalid use of %0 dependence with %1 ownership", + (StringRef, StringRef)) +NOTE(lifetime_dependence_parsed_borrow_with_ownership_fix, none, + "use '@_lifetime(%0%1)' instead", + (StringRef, StringRef)) +ERROR(lifetime_dependence_cannot_use_default_escapable_consuming, none, + "invalid lifetime dependence on an Escapable value with %0 ownership", (StringRef)) -ERROR(lifetime_dependence_cannot_use_parsed_borrow_consuming, none, - "invalid use of borrow dependence with consuming ownership", - ()) ERROR(lifetime_dependence_cannot_use_parsed_borrow_inout, none, - "invalid use of borrow dependence on the same inout parameter", + "invalid use of inout dependence on the same inout parameter", ()) ERROR(lifetime_dependence_duplicate_target, none, "invalid duplicate target lifetime dependencies on function", ()) ERROR(lifetime_parameter_requires_inout, none, - "lifetime-dependent parameter must be 'inout'", (Identifier)) + "lifetime-dependent parameter '%0' must be 'inout'", (StringRef)) //------------------------------------------------------------------------------ // MARK: Lifetime Dependence Requirements //------------------------------------------------------------------------------ ERROR(lifetime_dependence_feature_required_return, none, - "%0 with a ~Escapable result requires " - "'-enable-experimental-feature LifetimeDependence'", (StringRef)) + "%0 cannot return a ~Escapable result", (StringRef)) ERROR(lifetime_dependence_feature_required_mutating, none, - "%0 with ~Escapable 'self' requires " - "'-enable-experimental-feature LifetimeDependence'", (StringRef)) + "%0 cannot have a ~Escapable 'self'", (StringRef)) ERROR(lifetime_dependence_feature_required_inout, none, - "%0 with a ~Escapable 'inout' parameter requires " - "'-enable-experimental-feature LifetimeDependence'", - // arg list is interchangable with lifetime_dependence_cannot_infer_inout - (StringRef, Identifier)) + "%0 cannot have a ~Escapable 'inout' parameter '%1' in addition to other ~Escapable parameters", + // this arg list must be compatible with + // lifetime_dependence_cannot_infer_inout + (StringRef, StringRef)) ERROR(lifetime_dependence_cannot_infer_return, none, - "%0 with a ~Escapable result requires '@lifetime(...)'", (StringRef)) + "%0 with a ~Escapable result requires '@_lifetime(...)'", (StringRef)) ERROR(lifetime_dependence_cannot_infer_mutating, none, - "%0 with a ~Escapable 'self' requires '@lifetime(self: ...)'", (StringRef)) + "%0 with a ~Escapable 'self' requires '@_lifetime(self: ...)'", (StringRef)) ERROR(lifetime_dependence_cannot_infer_inout, none, - "%0 with a ~Escapable 'inout' parameter requires '@lifetime(%1: ...)'", - (StringRef, Identifier)) + "%0 with a ~Escapable 'inout' parameter requires '@_lifetime(%1: ...)'", + (StringRef, StringRef)) //------------------------------------------------------------------------------ // MARK: Lifetime Dependence Inference - refinements to the requirements above @@ -8211,19 +8281,25 @@ ERROR(lifetime_dependence_cannot_infer_return_no_param, none, "%0 with a ~Escapable result needs a parameter to depend on", (StringRef)) NOTE(lifetime_dependence_cannot_infer_return_immortal, none, - "'@lifetime(immortal)' can be used to indicate that values produced by " + "'@_lifetime(immortal)' can be used to indicate that values produced by " "this initializer have no lifetime dependencies", ()) ERROR(lifetime_dependence_cannot_infer_bitwisecopyable, none, "cannot infer lifetime dependence on %0 because '%1' is BitwiseCopyable, " - "specify '@lifetime(borrow self)'", + "specify '@_lifetime(borrow self)'", (StringRef, StringRef)) ERROR(lifetime_dependence_cannot_infer_kind, none, "cannot infer the lifetime dependence scope on %0 with a ~Escapable " - "parameter, specify '@lifetime(borrow %1)' or '@lifetime(copy %1)'", + "parameter, specify '@_lifetime(borrow %1)' or '@_lifetime(copy %1)'", (StringRef, StringRef)) ERROR(lifetime_dependence_cannot_infer_scope_ownership, none, "cannot borrow the lifetime of '%0', which has consuming ownership on %1", (StringRef, StringRef)) +ERROR(lifetime_dependence_cannot_infer_implicit_init, none, + "cannot infer implicit initialization lifetime. Add an initializer with " + "'@_lifetime(...)' for each parameter the result depends on", ()) +NOTE(lifetime_dependence_cannot_infer_inout_suggest, none, + "use '@_lifetime(%0: copy %0) to forward the inout dependency", + (StringRef)) //------------------------------------------------------------------------------ // MARK: Lifetime Dependence Experimental Inference @@ -8266,6 +8342,15 @@ NOTE(note_reference_to_unsafe_decl,none, NOTE(note_reference_to_unsafe_typed_decl,none, "%select{reference|call}0 to %kind1 involves unsafe type %2", (bool, const ValueDecl *, Type)) +NOTE(note_unsafe_call_decl_argument_named,none, + "argument %1 in call to %kindbase0 has unsafe type %2", + (const ValueDecl *, Identifier, Type)) +NOTE(note_unsafe_call_decl_argument_indexed,none, + "argument #%1 in call to %kindbase0 has unsafe type %2", + (const ValueDecl *, unsigned, Type)) +NOTE(note_unsafe_call_argument_indexed,none, + "argument #%0 in call has unsafe type %1", + (unsigned, Type)) NOTE(note_reference_to_unsafe_through_typealias,none, "reference to %kind0 whose underlying type involves unsafe type %1", (const ValueDecl *, Type)) @@ -8278,9 +8363,10 @@ NOTE(note_reference_to_nonisolated_unsafe,none, NOTE(note_reference_unowned_unsafe,none, "reference to unowned(unsafe) %kind0 is unsafe", (const ValueDecl *)) NOTE(note_reference_exclusivity_unchecked,none, - "reference to @exclusivity(unchecked) %kind0 is unsafe", (const ValueDecl *)) + "reference to '@exclusivity(unchecked)' %kind0 is unsafe", + (const ValueDecl *)) NOTE(note_use_of_unsafe_conformance_is_unsafe,none, - "@unsafe conformance of %0 to %kind1 involves unsafe code", + "'@unsafe' conformance of %0 to %kind1 involves unsafe code", (Type, const ValueDecl *)) NOTE(note_unsafe_storage,none, "%kindbase1 involves unsafe type %2", (bool, const ValueDecl *, Type)) @@ -8298,7 +8384,7 @@ NOTE(decl_storage_mark_safe,none, "a safe interface", ()) ERROR(safe_and_unsafe_attr,none, - "%kindbase0 cannot be both @safe and @unsafe", (const Decl *)) + "%kindbase0 cannot be both '@safe' and '@unsafe'", (const Decl *)) GROUPED_WARNING(unsafe_superclass,StrictMemorySafety,none, "%kindbase0 has superclass involving unsafe type %1", @@ -8319,18 +8405,19 @@ GROUPED_WARNING(override_safe_with_unsafe,StrictMemorySafety,none, "override of safe %0 with unsafe %0", (DescriptiveDeclKind)) GROUPED_WARNING(preconcurrency_import_unsafe,StrictMemorySafety,none, - "@preconcurrency import is not memory-safe because it can silently " - "introduce data races", ()) + "'@preconcurrency' import is not memory-safe because it can silently " + "introduce data races; add '@unsafe' to indicate that this is unsafe", ()) GROUPED_WARNING(unsafe_without_unsafe,StrictMemorySafety,none, "expression uses unsafe constructs but is not marked with 'unsafe'", ()) GROUPED_WARNING(for_unsafe_without_unsafe,StrictMemorySafety,none, "for-in loop uses unsafe constructs but is not marked with 'unsafe'", ()) -GROUPED_WARNING(no_unsafe_in_unsafe,StrictMemorySafety,none, +WARNING(no_unsafe_in_unsafe,none, "no unsafe operations occur within 'unsafe' expression", ()) -GROUPED_WARNING(no_unsafe_in_unsafe_for,StrictMemorySafety,none, +WARNING(no_unsafe_in_unsafe_for,none, "no unsafe operations occur within 'unsafe' for-in loop", ()) NOTE(make_subclass_unsafe,none, - "make class %0 @unsafe to allow unsafe overrides of safe superclass methods", + "make class %0 '@unsafe' to allow unsafe overrides of safe superclass " + "methods", (DeclName)) //===----------------------------------------------------------------------===// @@ -8390,14 +8477,10 @@ ERROR(attr_abi_mismatched_async,none, "cannot give %0 the ABI of %select{a non-async|an async}1 %kindonly0", (Decl *, /*abiIsAsync=*/bool)) -ERROR(attr_abi_mismatched_pbd_size,none, - "cannot give pattern binding the ABI of a binding with " - "%select{more|fewer}0 patterns", - (/*abiHasExtra=*/bool)) - -ERROR(attr_abi_mismatched_var,none, - "no match for %select{%kind0 in the ABI|ABI %kind0}1", - (Decl *, /*isABI=*/bool)) +ERROR(attr_abi_multiple_vars,none, + "'abi' attribute can only be applied to a single %0; declare each " + "%0 separately", + (DescriptiveDeclKind)) ERROR(attr_abi_incompatible_with_silgen_name,none, "cannot use '@_silgen_name' and '@abi' on the same %0 because they serve " @@ -8413,9 +8496,6 @@ ERROR(attr_abi_extra_attr,none, ERROR(attr_abi_forbidden_attr,none, "unused '%0' %select{attribute|modifier}1 in '@abi'", (StringRef, bool)) -REMARK(abi_attr_inferred_attribute,none, - "inferred '%0' in '@abi' to match %select{attribute|modifier}1 on API", - (StringRef, bool)) ERROR(attr_abi_mismatched_attr,none, "'%0' %select{attribute|modifier}1 in '@abi' should match '%2'", @@ -8455,6 +8535,13 @@ ERROR(attr_abi_no_default_arguments,none, "affect the parameter's ABI", (Decl *)) +ERROR(attr_abi_no_macros,none, + "%kind0 cannot be expanded in '@abi' attribute", + (Decl *)) +ERROR(attr_abi_no_lazy,none, + "'lazy' is not compatible with '@abi' attribute", + ()) + // These macros insert 'final', 'non-final', or nothing depending on both the // current decl and its counterpart, such that 'non-final' is used if the // counterpart would be described as 'final' or 'static'. They must be kept in @@ -8483,10 +8570,6 @@ ERROR(attr_abi_failable_mismatch,none, //===----------------------------------------------------------------------===// // MARK: Isolated conformances //===----------------------------------------------------------------------===// -GROUPED_ERROR(isolated_conformance_experimental_feature,IsolatedConformances, - none, - "isolated conformances require experimental feature " - " 'IsolatedConformances'", ()) NOTE(note_isolate_conformance_to_global_actor,none, "isolate this conformance to the %select{global actor %0|main actor}1 " "with '@%2'", (Type, bool, StringRef)) @@ -8505,45 +8588,99 @@ GROUPED_ERROR(isolated_conformance_with_sendable_simple,IsolatedConformances, GROUPED_ERROR(isolated_conformance_wrong_domain,IsolatedConformances,none, "%0 conformance of %1 to %2 cannot be used in %3 context", (ActorIsolation, Type, DeclName, ActorIsolation)) +GROUPED_WARNING(isolated_conformance_will_become_nonisolated,IsolatedConformances,none, + "conformance of %0 to %1 should be marked 'nonisolated' to retain its behavior with upcoming feature 'InferIsolatedConformances'", + (const ValueDecl *, const ValueDecl *)) +GROUPED_ERROR(isolated_conformance_to_sendable_metatype,IsolatedConformances,none, + "cannot form %0 conformance of %1 to SendableMetatype-inheriting %kind2", + (ActorIsolation, Type, const ValueDecl *)) //===----------------------------------------------------------------------===// -// MARK: @execution Attribute +// MARK: @_inheritActorContext //===----------------------------------------------------------------------===// +ERROR(inherit_actor_context_only_on_func_types,none, + "%0 only applies to parameters with function types (got: %1)", + (DeclAttribute, Type)) -ERROR(attr_execution_only_on_async,none, - "cannot use '@execution' on non-async %kind0", - (ValueDecl *)) +ERROR(inherit_actor_context_only_on_sending_or_Sendable_params,none, + "%0 only applies to 'sending' parameters or parameters with " + "'@Sendable' function types", + (DeclAttribute)) -ERROR(attr_execution_only_on_async_closure,none, - "cannot use '@execution' on non-async closure", - ()) +ERROR(inherit_actor_context_only_on_async_or_isolation_erased_params,none, + "%0 only applies to '@isolated(any)' parameters or parameters with " + "asynchronous function types", + (DeclAttribute)) -ERROR(attr_execution_type_attr_only_on_async,none, - "cannot use '@execution' on non-async function type", - ()) +//===----------------------------------------------------------------------===// +// MARK: @concurrent and nonisolated(nonsending) attributes +//===----------------------------------------------------------------------===// -ERROR(attr_execution_incompatible_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "an isolated parameter: %1", - (ValueDecl *, ValueDecl *)) +ERROR(execution_behavior_only_on_async,none, + "cannot use %0 on non-async %kind1", + (DeclAttribute, ValueDecl *)) -ERROR(attr_execution_incompatible_dynamically_isolated_parameter,none, - "cannot use '@execution' on %kind0 because it has " - "a dynamically isolated parameter: %1", - (ValueDecl *, ValueDecl *)) +ERROR(cannot_specify_execution_behavior_for_decl,none, + "%0 is only applicable to asynchronous functions, " + "initializers, subscripts and computed properties", + (DeclAttribute)) -ERROR(attr_execution_type_attr_incompatible_with_global_isolation,none, - "cannot use '@execution' because function type is " - "isolated to a global actor %0", - (Type)) +ERROR(execution_behavior_only_on_async_closure,none, + "cannot use %0 on non-async closure", + (DeclAttribute)) -ERROR(attr_execution_type_attr_incompatible_with_isolated_param,none, - "cannot use '@execution' together with an isolated parameter", - ()) +ERROR(execution_behavior_type_attr_only_on_async,none, + "cannot use '@%0' on non-async function type", + (StringRef)) -ERROR(attr_execution_type_attr_incompatible_with_isolated_any,none, - "cannot use '@execution' together with @isolated(any)", - ()) +ERROR(nonisolated_nonsending_only_on_function_types, none, + "%0 may only be used on function types", + (TypeRepr *)) + +ERROR(nonisolated_nonsending_only_on_async,none, + "cannot use %0 on non-async function type", + (TypeRepr *)) + +ERROR(cannot_use_nonisolated_nonsending_together_with_concurrent,none, + "cannot use %0 together with '@concurrent'", + (TypeRepr *)) + +ERROR(execution_behavior_incompatible_isolated_parameter,none, + "cannot use %0 on %kind1 because it has " + "an isolated parameter: %2", + (DeclAttribute, ValueDecl *, ValueDecl *)) + +ERROR(execution_behavior_attr_incompatible_with_global_isolation,none, + "cannot use %0 because function type is isolated to a global actor %1", + (DeclAttribute, Type)) + +ERROR(execution_behavior_attr_incompatible_with_isolated_param,none, + "cannot use %0 together with an isolated parameter", + (DeclAttribute)) + +ERROR(execution_behavior_type_attr_incompatible_with_global_isolation,none, + "cannot use '@%0' because function type is isolated to a global actor %1", + (StringRef, Type)) + +ERROR(nonisolated_nonsending_incompatible_with_global_isolation,none, + "cannot use %0 because function type is isolated to a global actor %1", + (TypeRepr *, Type)) + +ERROR(execution_behavior_type_attr_incompatible_with_isolated_param,none, + "cannot use '@%0' together with an isolated parameter", + (StringRef)) + +ERROR(nonisolated_nonsending_incompatible_with_isolated_param,none, + "cannot use %0 together with an isolated parameter", + (TypeRepr *)) + +ERROR(execution_behavior_type_attr_incompatible_with_isolated_any,none, + "cannot use '@%0' together with '@isolated(any)'", + (StringRef)) + +ERROR(nonisolated_nonsending_incompatible_with_isolated_any,none, + "cannot use %0 together with '@isolated(any)'", + (TypeRepr *)) ERROR(invalid_function_conversion_with_non_sendable,none, "cannot convert %0 to %1 because crossing of an isolation boundary " @@ -8553,41 +8690,35 @@ NOTE(type_does_not_conform_to_Sendable,none, "type %0 does not conform to 'Sendable' protocol", (Type)) GROUPED_WARNING( - attr_execution_nonisolated_behavior_will_change_decl, AsyncCallerExecution, + attr_execution_nonisolated_behavior_will_change_decl, NonisolatedNonsendingByDefault, none, "feature '%0' will cause nonisolated async %kindbase1 to run on the " - "caller's actor; use %2 to preserve behavior", - (StringRef, const AbstractFunctionDecl *, DeclAttribute)) + "caller's actor; use '@concurrent' to preserve behavior", + (StringRef, const AbstractFunctionDecl *)) GROUPED_WARNING( attr_execution_nonisolated_behavior_will_change_closure, - AsyncCallerExecution, none, + NonisolatedNonsendingByDefault, none, "feature '%0' will cause nonisolated async closure to run on the caller's " - "actor; use %1 to preserve behavior", - (StringRef, DeclAttribute)) + "actor; use '@concurrent' to preserve behavior", + (StringRef)) GROUPED_WARNING( attr_execution_nonisolated_behavior_will_change_typerepr, - AsyncCallerExecution, none, + NonisolatedNonsendingByDefault, none, "feature '%0' will cause nonisolated async function type to be treated as " - "specified to run on the caller's actor; use %1 to preserve " + "specified to run on the caller's actor; use '@concurrent' to preserve " "behavior", - (StringRef, DeclAttribute)) + (StringRef)) //===----------------------------------------------------------------------===// -// MARK: SwiftSettings +// MARK: `using` declaration //===----------------------------------------------------------------------===// +ERROR(invalid_redecl_of_file_isolation,none, + "invalid redeclaration of file-level default actor isolation", ()) +NOTE(invalid_redecl_of_file_isolation_prev,none, + "default isolation was previously declared here", ()) -ERROR(swift_settings_invalid_setting, none, - "Unrecognized setting passed to #SwiftSettings", ()) - -ERROR(swift_settings_must_be_top_level, none, - "#SwiftSettings can only be invoked as a top level declaration", ()) - -ERROR(swift_settings_duplicate_setting, none, - "duplicate setting passed to #SwiftSettings", ()) -NOTE(swift_settings_duplicate_setting_original_loc, none, - "setting originally passed here", ()) #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index f3f56f0f85ae2..aeedf3ba2b297 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -276,9 +276,7 @@ class Evaluator { typename std::enable_if::type* = nullptr> void cacheNonEmptyOutput(const Request &request, typename Request::OutputType &&output) { - bool inserted = cache.insert(request, std::move(output)); - assert(inserted && "Request result was already cached"); - (void) inserted; + (void)cache.insert(request, std::move(output)); } /// Consults the request evaluator's cache for a split-cached request. diff --git a/include/swift/AST/ExistentialLayout.h b/include/swift/AST/ExistentialLayout.h index 706e6341379df..7e4fa5e75189c 100644 --- a/include/swift/AST/ExistentialLayout.h +++ b/include/swift/AST/ExistentialLayout.h @@ -105,6 +105,9 @@ struct ExistentialLayout { /// calling this on a temporary is likely to be incorrect. ArrayRef getProtocols() const && = delete; + /// Determine whether this refers to any non-marker protocols. + bool containsNonMarkerProtocols() const; + ArrayRef getParameterizedProtocols() const & { return parameterized; } diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 7515022f3dc91..fa7fc3664b083 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -267,7 +267,7 @@ class alignas(8) Expr : public ASTAllocated { Kind : 2 ); - SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1+1+1+1+1+1+1+1, /// True if closure parameters were synthesized from anonymous closure /// variables. HasAnonymousClosureVars : 1, @@ -276,9 +276,11 @@ class alignas(8) Expr : public ASTAllocated { /// on each member reference. ImplicitSelfCapture : 1, - /// True if this @Sendable async closure parameter should implicitly - /// inherit the actor context from where it was formed. + /// True if this closure parameter should implicitly inherit the actor + /// context from where it was formed. InheritActorContext : 1, + /// The kind for inheritance - none or always at the moment. + InheritActorContextKind : 1, /// True if this closure's actor isolation behavior was determined by an /// \c \@preconcurrency declaration. @@ -295,7 +297,12 @@ class alignas(8) Expr : public ASTAllocated { /// isolation checks when it either specifies or inherits isolation /// and was passed as an argument to a function that is not fully /// concurrency checked. - RequiresDynamicIsolationChecking : 1 + RequiresDynamicIsolationChecking : 1, + + /// Whether this closure was type-checked as an argument to a macro. This + /// is only populated after type-checking, and only exists for diagnostic + /// logic. Do not add more uses of this. + IsMacroArgument : 1 ); SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16, @@ -1449,23 +1456,25 @@ class TypeExpr : public Expr { }; class TypeValueExpr : public Expr { - GenericTypeParamDecl *paramDecl; - DeclNameLoc loc; + TypeRepr *repr; Type paramType; - /// Create a \c TypeValueExpr from a given generic value param decl. - TypeValueExpr(DeclNameLoc loc, GenericTypeParamDecl *paramDecl) : - Expr(ExprKind::TypeValue, /*implicit*/ false), paramDecl(paramDecl), - loc(loc), paramType(nullptr) {} + /// Create a \c TypeValueExpr from a given type representation. + TypeValueExpr(TypeRepr *repr) : + Expr(ExprKind::TypeValue, /*implicit*/ false), repr(repr), + paramType(nullptr) {} public: - /// Create a \c TypeValueExpr for a given \c GenericTypeParamDecl. + /// Create a \c TypeValueExpr for a given \c TypeDecl. /// /// The given location must be valid. - static TypeValueExpr *createForDecl(DeclNameLoc Loc, GenericTypeParamDecl *D); + static TypeValueExpr *createForDecl(DeclNameLoc loc, TypeDecl *d, + DeclContext *dc); + + GenericTypeParamDecl *getParamDecl() const; - GenericTypeParamDecl *getParamDecl() const { - return paramDecl; + TypeRepr *getRepr() const { + return repr; } /// Retrieves the corresponding parameter type of the value referenced by this @@ -1480,9 +1489,7 @@ class TypeValueExpr : public Expr { this->paramType = paramType; } - SourceRange getSourceRange() const { - return loc.getSourceRange(); - } + SourceRange getSourceRange() const; static bool classof(const Expr *E) { return E->getKind() == ExprKind::TypeValue; @@ -4313,9 +4320,11 @@ class ClosureExpr : public AbstractClosureExpr { Bits.ClosureExpr.HasAnonymousClosureVars = false; Bits.ClosureExpr.ImplicitSelfCapture = false; Bits.ClosureExpr.InheritActorContext = false; + Bits.ClosureExpr.InheritActorContextKind = 0; Bits.ClosureExpr.IsPassedToSendingParameter = false; Bits.ClosureExpr.NoGlobalActorAttribute = false; Bits.ClosureExpr.RequiresDynamicIsolationChecking = false; + Bits.ClosureExpr.IsMacroArgument = false; } SourceRange getSourceRange() const; @@ -4360,8 +4369,29 @@ class ClosureExpr : public AbstractClosureExpr { return Bits.ClosureExpr.InheritActorContext; } - void setInheritsActorContext(bool value = true) { + /// Whether this closure should _always_ implicitly inherit the actor context + /// regardless of whether the isolation parameter is captured or not. + bool alwaysInheritsActorContext() const { + if (!inheritsActorContext()) + return false; + return getInheritActorIsolationModifier() == + InheritActorContextModifier::Always; + } + + void setInheritsActorContext(bool value = true, + InheritActorContextModifier modifier = + InheritActorContextModifier::None) { Bits.ClosureExpr.InheritActorContext = value; + Bits.ClosureExpr.InheritActorContextKind = uint8_t(modifier); + assert((static_cast( + Bits.ClosureExpr.InheritActorContextKind) == modifier) && + "not enough bits for modifier"); + } + + InheritActorContextModifier getInheritActorIsolationModifier() const { + assert(inheritsActorContext()); + return static_cast( + Bits.ClosureExpr.InheritActorContextKind); } /// Whether the closure's concurrency behavior was determined by an @@ -4394,6 +4424,17 @@ class ClosureExpr : public AbstractClosureExpr { Bits.ClosureExpr.RequiresDynamicIsolationChecking = value; } + /// Whether this closure was type-checked as an argument to a macro. This + /// is only populated after type-checking, and only exists for diagnostic + /// logic. Do not add more uses of this. + bool isMacroArgument() const { + return Bits.ClosureExpr.IsMacroArgument; + } + + void setIsMacroArgument(bool value = true) { + Bits.ClosureExpr.IsMacroArgument = value; + } + /// Determine whether this closure expression has an /// explicitly-specified result type. bool hasExplicitResultType() const { return ArrowLoc.isValid(); } diff --git a/include/swift/AST/ExtInfo.h b/include/swift/AST/ExtInfo.h index 3662a99c61aef..bb38eb1a6dc78 100644 --- a/include/swift/AST/ExtInfo.h +++ b/include/swift/AST/ExtInfo.h @@ -740,12 +740,19 @@ class ASTExtInfoBuilder { globalActor, thrownError, lifetimeDependencies); } + /// \p lifetimeDependencies should be arena allocated and not a temporary + /// Function types are allocated on the are arena and their ExtInfo should be + /// valid throughout their lifetime. [[nodiscard]] ASTExtInfoBuilder withLifetimeDependencies( llvm::ArrayRef lifetimeDependencies) const { return ASTExtInfoBuilder(bits, clangTypeInfo, globalActor, thrownError, lifetimeDependencies); } + [[nodiscard]] ASTExtInfoBuilder withLifetimeDependencies( + SmallVectorImpl lifetimeDependencies) const = + delete; + [[nodiscard]] ASTExtInfoBuilder withIsolation(FunctionTypeIsolation isolation) const { return ASTExtInfoBuilder( @@ -920,11 +927,18 @@ class ASTExtInfo { .build(); } + /// \p lifetimeDependencies should be arena allocated and not a temporary + /// Function types are allocated on the are arena and their ExtInfo should be + /// valid throughout their lifetime. [[nodiscard]] ASTExtInfo withLifetimeDependencies( ArrayRef lifetimeDependencies) const { return builder.withLifetimeDependencies(lifetimeDependencies).build(); } + [[nodiscard]] ASTExtInfo withLifetimeDependencies( + SmallVectorImpl lifetimeDependencies) const = + delete; + void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); } bool isEqualTo(ASTExtInfo other, bool useClangTypes) const { @@ -1227,11 +1241,19 @@ class SILExtInfoBuilder { return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical(), lifetimeDependencies); } + + /// \p lifetimeDependencies should be arena allocated and not a temporary + /// Function types are allocated on the are arena and their ExtInfo should be + /// valid throughout their lifetime. [[nodiscard]] SILExtInfoBuilder withLifetimeDependencies( ArrayRef lifetimeDependenceInfo) const { return SILExtInfoBuilder(bits, clangTypeInfo, lifetimeDependenceInfo); } + [[nodiscard]] ASTExtInfoBuilder withLifetimeDependencies( + SmallVectorImpl lifetimeDependencies) const = + delete; + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(bits); ID.AddPointer(clangTypeInfo.getType()); @@ -1368,11 +1390,17 @@ class SILExtInfo { return builder.withUnimplementable(isUnimplementable).build(); } + /// \p lifetimeDependencies should be arena allocated and not a temporary + /// Function types are allocated on the are arena and their ExtInfo should be + /// valid throughout their lifetime. SILExtInfo withLifetimeDependencies( ArrayRef lifetimeDependencies) const { return builder.withLifetimeDependencies(lifetimeDependencies); } + SILExtInfo withLifetimeDependencies(SmallVectorImpl + lifetimeDependencies) const = delete; + void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); } bool isEqualTo(SILExtInfo other, bool useClangTypes) const { diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h index cca6904965974..8e8dbfb86b513 100644 --- a/include/swift/AST/GenericSignature.h +++ b/include/swift/AST/GenericSignature.h @@ -376,6 +376,19 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final /// the given protocol. bool requiresProtocol(Type type, ProtocolDecl *proto) const; + /// Determine whether a conformance requirement of the given type to the + /// given protocol prohibits the use of an isolated conformance. + /// + /// The use of an isolated conformance to satisfy a requirement T: P is + /// prohibited when T is a type parameter and T, or some type that can be + /// used to reach T, also conforms to Sendable or SendableMetatype. In that + /// case, the conforming type and the protocol (Sendable or SendableMetatype) + /// is returned. + /// + /// If there is no such requirement, returns std::nullopt. + std::optional> + prohibitsIsolatedConformance(Type type) const; + /// Determine whether the given dependent type is equal to a concrete type. bool isConcreteType(Type type) const; @@ -604,6 +617,23 @@ using GenericSignatureErrors = OptionSet; using GenericSignatureWithError = llvm::PointerIntPair; +/// Build a generic signature from the given requirements, which are not +/// required to be minimal or canonical, and may contain unresolved +/// DependentMemberTypes. The generic signature is returned with the +/// error flags (if any) that were raised while building the signature. +/// +/// \param baseSignature if non-null, the new parameters and requirements +///// are added on; existing requirements of the base signature might become +///// redundant. Otherwise if null, build a new signature from scratch. +/// \param allowInverses if true, default requirements to Copyable/Escapable are +/// expanded for generic parameters. +GenericSignatureWithError buildGenericSignatureWithError( + ASTContext &ctx, + GenericSignature baseSignature, + SmallVector addedParameters, + SmallVector addedRequirements, + bool allowInverses); + } // end namespace swift namespace llvm { diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 21e868a03c52e..d05d7c96e51d8 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -647,7 +647,7 @@ class IRGenOptions { DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false), ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false), UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false), - EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(false), + EmitAsyncFramePushPopMetadata(true), EmitTypeMallocForCoroFrame(true), AsyncFramePointerAll(false), UseProfilingMarkerThunks(false), UseCoroCCX8664(false), UseCoroCCArm64(false), MergeableTraps(false), diff --git a/include/swift/AST/Identifier.h b/include/swift/AST/Identifier.h index 036685873da73..ee6a4c0a8b8d8 100644 --- a/include/swift/AST/Identifier.h +++ b/include/swift/AST/Identifier.h @@ -230,7 +230,7 @@ class Identifier { private: bool isOperatorSlow() const; }; - + class DeclName; class DeclNameRef; class ObjCSelector; @@ -362,7 +362,7 @@ class DeclBaseName { } bool hasDollarPrefix() const { - return getIdentifier().hasDollarPrefix(); + return !isSpecial() && getIdentifier().hasDollarPrefix(); } /// A representation of the name to be displayed to users. May be ambiguous @@ -663,8 +663,12 @@ class DeclName { /// /// \param skipEmptyArgumentNames When true, don't print the argument labels /// if they are all empty. + /// + /// \param escapeIfNeeded When true, escape identifiers with backticks + /// when required. llvm::raw_ostream &print(llvm::raw_ostream &os, - bool skipEmptyArgumentNames = false) const; + bool skipEmptyArgumentNames = false, + bool escapeIfNeeded = false) const; /// Print a "pretty" representation of this declaration name to the given /// stream. diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 73e3b44485598..8be2729b9376a 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -127,6 +127,7 @@ IDENTIFIER(main) IDENTIFIER_WITH_NAME(MainEntryPoint, "$main") IDENTIFIER(message) IDENTIFIER(next) +IDENTIFIER(nonsending) IDENTIFIER_(nsErrorDomain) IDENTIFIER(objectAtIndexedSubscript) IDENTIFIER(objectForKeyedSubscript) @@ -324,6 +325,7 @@ IDENTIFIER(SerializationRequirement) IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf") // Attribute options +IDENTIFIER(always) IDENTIFIER_(_always) IDENTIFIER_(assumed) IDENTIFIER(checked) diff --git a/include/swift/AST/KnownStdlibTypes.def b/include/swift/AST/KnownStdlibTypes.def index fda6ed7b37439..425c846e26854 100644 --- a/include/swift/AST/KnownStdlibTypes.def +++ b/include/swift/AST/KnownStdlibTypes.def @@ -101,6 +101,6 @@ KNOWN_STDLIB_TYPE_DECL(Result, NominalTypeDecl, 2) KNOWN_STDLIB_TYPE_DECL(InlineArray, NominalTypeDecl, 2) -KNOWN_STDLIB_TYPE_DECL(SwiftSetting, NominalTypeDecl, 0) +KNOWN_STDLIB_TYPE_DECL(MutableSpan, NominalTypeDecl, 1) #undef KNOWN_STDLIB_TYPE_DECL diff --git a/include/swift/AST/LifetimeDependence.h b/include/swift/AST/LifetimeDependence.h index 0d8cd14029bbb..f802b0982ada0 100644 --- a/include/swift/AST/LifetimeDependence.h +++ b/include/swift/AST/LifetimeDependence.h @@ -38,8 +38,9 @@ class SILResultInfo; enum class ParsedLifetimeDependenceKind : uint8_t { Default = 0, - Scope, - Inherit // Only used with deserialized decls + Borrow, + Inherit, // Only used with deserialized decls + Inout }; enum class LifetimeDependenceKind : uint8_t { Inherit = 0, Scope }; @@ -182,6 +183,7 @@ class LifetimeEntry final ArrayRef sources, std::optional targetDescriptor = std::nullopt); + std::string getString() const; SourceLoc getLoc() const { return startLoc; } SourceLoc getStartLoc() const { return startLoc; } SourceLoc getEndLoc() const { return endLoc; } @@ -193,35 +195,6 @@ class LifetimeEntry final std::optional getTargetDescriptor() const { return targetDescriptor; } - - std::string getString() const { - std::string result = "@lifetime("; - if (targetDescriptor.has_value()) { - result += targetDescriptor->getString(); - result += ": "; - } - - bool firstElem = true; - for (auto source : getSources()) { - if (!firstElem) { - result += ", "; - } - switch (source.getParsedLifetimeDependenceKind()) { - case ParsedLifetimeDependenceKind::Scope: - result += "borrow "; - break; - case ParsedLifetimeDependenceKind::Inherit: - result += "copy "; - break; - default: - break; - } - result += source.getString(); - firstElem = false; - } - result += ")"; - return result; - } }; class LifetimeDependenceInfo { @@ -258,6 +231,25 @@ class LifetimeDependenceInfo { || !conditionallyAddressableParamIndices || conditionallyAddressableParamIndices->isDisjointWith( addressableParamIndices))); + + if (CONDITIONAL_ASSERT_enabled()) { + // Ensure inherit/scope/addressable param indices are of the same length + // or 0. + unsigned paramIndicesLength = 0; + if (inheritLifetimeParamIndices) { + paramIndicesLength = inheritLifetimeParamIndices->getCapacity(); + } + if (scopeLifetimeParamIndices) { + assert(paramIndicesLength == 0 || + paramIndicesLength == scopeLifetimeParamIndices->getCapacity()); + paramIndicesLength = scopeLifetimeParamIndices->getCapacity(); + } + if (addressableParamIndices) { + assert(paramIndicesLength == 0 || + paramIndicesLength == addressableParamIndices->getCapacity()); + paramIndicesLength = addressableParamIndices->getCapacity(); + } + } } operator bool() const { return !empty(); } @@ -281,6 +273,19 @@ class LifetimeDependenceInfo { return addressableParamIndicesAndImmortal.getPointer() != nullptr; } + unsigned getParamIndicesLength() const { + if (hasInheritLifetimeParamIndices()) { + return getInheritIndices()->getCapacity(); + } + if (hasScopeLifetimeParamIndices()) { + return getScopeIndices()->getCapacity(); + } + if (hasAddressableParamIndices()) { + return getAddressableIndices()->getCapacity(); + } + return 0; + } + IndexSubset *getInheritIndices() const { return inheritLifetimeParamIndices; } IndexSubset *getScopeIndices() const { return scopeLifetimeParamIndices; } @@ -316,11 +321,6 @@ class LifetimeDependenceInfo { && scopeLifetimeParamIndices->contains(index); } - bool checkAddressable(int index) const { - return hasAddressableParamIndices() - && getAddressableIndices()->contains(index); - } - std::string getString() const; void Profile(llvm::FoldingSetNodeID &ID) const; void getConcatenatedData(SmallVectorImpl &concatenatedData) const; @@ -328,8 +328,7 @@ class LifetimeDependenceInfo { /// Builds LifetimeDependenceInfo from a swift decl, either from the explicit /// lifetime dependence specifiers or by inference based on types and /// ownership modifiers. - static std::optional> - get(AbstractFunctionDecl *decl); + static std::optional> get(ValueDecl *decl); /// Builds LifetimeDependenceInfo from SIL static std::optional> @@ -366,6 +365,9 @@ filterEscapableLifetimeDependencies(GenericSignature sig, SmallVectorImpl &outputs, llvm::function_ref getSubstTargetType); +StringRef +getNameForParsedLifetimeDependenceKind(ParsedLifetimeDependenceKind kind); + } // namespace swift #endif diff --git a/include/swift/AST/MacroDefinition.h b/include/swift/AST/MacroDefinition.h index 17937a9bba82d..7c7538948c43f 100644 --- a/include/swift/AST/MacroDefinition.h +++ b/include/swift/AST/MacroDefinition.h @@ -77,9 +77,6 @@ enum class BuiltinMacroKind : uint8_t { ExternalMacro, /// #isolation, which produces the isolation of the current context IsolationMacro, - /// #SwiftSettings, which allows for the user to set a compiler setting at - /// the file level - SwiftSettingsMacro, }; /// A single replacement diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index bf1a462f308a8..f079dc4a2ea9c 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -434,11 +434,6 @@ class ModuleDecl /// \c nullptr if the source location isn't in this module. SourceFile *getSourceFileContainingLocation(SourceLoc loc); - // Retrieve the buffer ID and source location of the outermost location that - // caused the generation of the buffer containing \p loc. \p loc and its - // buffer if it isn't in a generated buffer or has no original location. - std::pair getOriginalLocation(SourceLoc loc) const; - /// Creates a map from \c #filePath strings to corresponding \c #fileID /// strings, diagnosing any conflicts. /// @@ -1158,6 +1153,9 @@ class ModuleDecl /// \returns true if this module is the "swift" standard library module. bool isStdlibModule() const; + /// \returns true if this module is the "Cxx" module. + bool isCxxModule() const; + /// \returns true if this module is the "_Concurrency" standard library module. bool isConcurrencyModule() const; diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 391b2acc0b4a0..4846c4bcca735 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -22,6 +22,7 @@ #include "swift/AST/LinkLibrary.h" #include "swift/Basic/CXXStdlibKind.h" #include "swift/Basic/LLVM.h" +#include "swift/Serialization/Validation.h" #include "clang/CAS/CASOptions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" @@ -55,6 +56,7 @@ class Identifier; class CompilerInstance; class IRGenOptions; class CompilerInvocation; +class DiagnosticEngine; /// Which kind of module dependencies we are looking for. enum class ModuleDependencyKind : int8_t { @@ -154,25 +156,35 @@ struct ScannerImportStatementInfo { uint32_t columnNumber; }; - ScannerImportStatementInfo(std::string importIdentifier, bool isExported) - : importLocations(), importIdentifier(importIdentifier), - isExported(isExported) {} + ScannerImportStatementInfo(std::string importIdentifier, bool isExported, + AccessLevel accessLevel) + : importIdentifier(importIdentifier), importLocations(), + isExported(isExported), accessLevel(accessLevel) {} ScannerImportStatementInfo(std::string importIdentifier, bool isExported, + AccessLevel accessLevel, ImportDiagnosticLocationInfo location) - : importLocations({location}), importIdentifier(importIdentifier), - isExported(isExported) {} + : importIdentifier(importIdentifier), importLocations({location}), + isExported(isExported), accessLevel(accessLevel) {} + + ScannerImportStatementInfo(std::string importIdentifier, bool isExported, + AccessLevel accessLevel, + SmallVector locations) + : importIdentifier(importIdentifier), importLocations(locations), + isExported(isExported), accessLevel(accessLevel) {} void addImportLocation(ImportDiagnosticLocationInfo location) { importLocations.push_back(location); } - /// Buffer, line & column number of the import statement - SmallVector importLocations; /// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar' std::string importIdentifier; + /// Buffer, line & column number of the import statement + SmallVector importLocations; /// Is this an @_exported import bool isExported; + /// Access level of this dependency + AccessLevel accessLevel; }; /// Base class for the variant storage of ModuleDependencyInfo. @@ -400,15 +412,18 @@ class SwiftBinaryModuleDependencyStorage StringRef sourceInfoPath, ArrayRef moduleImports, ArrayRef optionalModuleImports, - ArrayRef linkLibraries, StringRef headerImport, - StringRef definingModuleInterface, bool isFramework, bool isStatic, - StringRef moduleCacheKey, StringRef userModuleVersion) + ArrayRef linkLibraries, + ArrayRef serializedSearchPaths, + StringRef headerImport, StringRef definingModuleInterface, + bool isFramework, bool isStatic, StringRef moduleCacheKey, + StringRef userModuleVersion) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary, moduleImports, optionalModuleImports, linkLibraries, moduleCacheKey), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath), headerImport(headerImport), definingModuleInterfacePath(definingModuleInterface), + serializedSearchPaths(serializedSearchPaths), isFramework(isFramework), isStatic(isStatic), userModuleVersion(userModuleVersion) {} @@ -435,6 +450,9 @@ class SwiftBinaryModuleDependencyStorage /// Source files on which the header inputs depend. std::vector headerSourceFiles; + /// Search paths this module was built with which got serialized + std::vector serializedSearchPaths; + /// (Clang) modules on which the header inputs depend. std::vector headerModuleDependencies; @@ -607,15 +625,17 @@ class ModuleDependencyInfo { StringRef sourceInfoPath, ArrayRef moduleImports, ArrayRef optionalModuleImports, - ArrayRef linkLibraries, StringRef headerImport, - StringRef definingModuleInterface, bool isFramework, - bool isStatic, StringRef moduleCacheKey, StringRef userModuleVer) { + ArrayRef linkLibraries, + ArrayRef serializedSearchPaths, + StringRef headerImport, StringRef definingModuleInterface, + bool isFramework, bool isStatic, StringRef moduleCacheKey, + StringRef userModuleVer) { return ModuleDependencyInfo( std::make_unique( compiledModulePath, moduleDocPath, sourceInfoPath, moduleImports, - optionalModuleImports, linkLibraries, headerImport, - definingModuleInterface,isFramework, isStatic, moduleCacheKey, - userModuleVer)); + optionalModuleImports, linkLibraries, serializedSearchPaths, + headerImport, definingModuleInterface,isFramework, isStatic, + moduleCacheKey, userModuleVer)); } /// Describe the main Swift module. @@ -689,7 +709,7 @@ class ModuleDependencyInfo { storage->importedSwiftModules.assign(dependencyIDs.begin(), dependencyIDs.end()); } - const ArrayRef getImportedSwiftDependencies() const { + ArrayRef getImportedSwiftDependencies() const { return storage->importedSwiftModules; } @@ -698,7 +718,7 @@ class ModuleDependencyInfo { storage->importedClangModules.assign(dependencyIDs.begin(), dependencyIDs.end()); } - const ArrayRef getImportedClangDependencies() const { + ArrayRef getImportedClangDependencies() const { return storage->importedClangModules; } @@ -732,7 +752,7 @@ class ModuleDependencyInfo { } } } - const ArrayRef getHeaderClangDependencies() const { + ArrayRef getHeaderClangDependencies() const { switch (getKind()) { case swift::ModuleDependencyKind::SwiftInterface: { auto swiftInterfaceStorage = @@ -760,7 +780,7 @@ class ModuleDependencyInfo { storage->swiftOverlayDependencies.assign(dependencyIDs.begin(), dependencyIDs.end()); } - const ArrayRef getSwiftOverlayDependencies() const { + ArrayRef getSwiftOverlayDependencies() const { return storage->swiftOverlayDependencies; } @@ -770,11 +790,11 @@ class ModuleDependencyInfo { storage->crossImportOverlayModules.assign(dependencyIDs.begin(), dependencyIDs.end()); } - const ArrayRef getCrossImportOverlayDependencies() const { + ArrayRef getCrossImportOverlayDependencies() const { return storage->crossImportOverlayModules; } - const ArrayRef getLinkLibraries() const { + ArrayRef getLinkLibraries() const { return storage->linkLibraries; } @@ -783,15 +803,10 @@ class ModuleDependencyInfo { storage->linkLibraries.assign(linkLibraries.begin(), linkLibraries.end()); } - const ArrayRef getAuxiliaryFiles() const { + ArrayRef getAuxiliaryFiles() const { return storage->auxiliaryFiles; } - void - setAuxiliaryFiles(const ArrayRef auxiliaryFiles) { - storage->auxiliaryFiles.assign(auxiliaryFiles.begin(), auxiliaryFiles.end()); - } - bool isStaticLibrary() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->isStatic; @@ -800,7 +815,7 @@ class ModuleDependencyInfo { return false; } - const ArrayRef getHeaderInputSourceFiles() const { + ArrayRef getHeaderInputSourceFiles() const { if (auto *detail = getAsSwiftInterfaceModule()) return detail->textualModuleDetails.bridgingSourceFiles; if (auto *detail = getAsSwiftSourceModule()) @@ -810,7 +825,7 @@ class ModuleDependencyInfo { return {}; } - std::vector getCommandline() const { + ArrayRef getCommandline() const { if (auto *detail = getAsClangModule()) return detail->buildCommandLine; if (auto *detail = getAsSwiftInterfaceModule()) @@ -833,7 +848,7 @@ class ModuleDependencyInfo { llvm_unreachable("Unexpected type"); } - std::vector getBridgingHeaderCommandline() const { + ArrayRef getBridgingHeaderCommandline() const { if (auto *detail = getAsSwiftSourceModule()) return detail->bridgingHeaderBuildCommandLine; return {}; @@ -932,6 +947,7 @@ class ModuleDependencyInfo { /// Add a dependency on the given module, if it was not already in the set. void addOptionalModuleImport(StringRef module, bool isExported, + AccessLevel accessLevel, llvm::StringSet<> *alreadyAddedModules = nullptr); /// Add all of the module imports in the given source @@ -942,12 +958,14 @@ class ModuleDependencyInfo { /// Add a dependency on the given module, if it was not already in the set. void addModuleImport(ImportPath::Module module, bool isExported, + AccessLevel accessLevel, llvm::StringSet<> *alreadyAddedModules = nullptr, const SourceManager *sourceManager = nullptr, SourceLoc sourceLocation = SourceLoc()); /// Add a dependency on the given module, if it was not already in the set. void addModuleImport(StringRef module, bool isExported, + AccessLevel accessLevel, llvm::StringSet<> *alreadyAddedModules = nullptr, const SourceManager *sourceManager = nullptr, SourceLoc sourceLocation = SourceLoc()); @@ -1004,7 +1022,7 @@ using ModuleDependenciesKindMap = /// Track swift dependency class SwiftDependencyTracker { public: - SwiftDependencyTracker(llvm::cas::CachingOnDiskFileSystem &FS, + SwiftDependencyTracker(std::shared_ptr CAS, llvm::PrefixMapper *Mapper, const CompilerInvocation &CI); @@ -1013,7 +1031,8 @@ class SwiftDependencyTracker { llvm::Expected createTreeFromDependencies(); private: - llvm::IntrusiveRefCntPtr FS; + llvm::IntrusiveRefCntPtr FS; + std::shared_ptr CAS; llvm::PrefixMapper *Mapper; struct FileEntry { @@ -1039,10 +1058,7 @@ class SwiftDependencyScanningService { ClangScanningService; /// CachingOnDiskFileSystem for dependency tracking. - llvm::IntrusiveRefCntPtr CacheFS; - - /// If use clang include tree. - bool UseClangIncludeTree = false; + llvm::IntrusiveRefCntPtr CacheFS; /// CAS Instance. std::shared_ptr CAS; @@ -1080,8 +1096,8 @@ class SwiftDependencyScanningService { return *SharedFilesystemCache; } - llvm::cas::CachingOnDiskFileSystem &getSharedCachingFS() const { - assert(CacheFS && "Expect CachingOnDiskFileSystem"); + llvm::vfs::FileSystem &getSharedCachingFS() const { + assert(CacheFS && "Expect a CASFileSystem"); return *CacheFS; } @@ -1092,22 +1108,14 @@ class SwiftDependencyScanningService { std::optional createSwiftDependencyTracker(const CompilerInvocation &CI) { - if (!CacheFS) + if (!CAS) return std::nullopt; - return SwiftDependencyTracker(*CacheFS, Mapper.get(), CI); + return SwiftDependencyTracker(CAS, Mapper.get(), CI); } - llvm::IntrusiveRefCntPtr getClangScanningFS() const { - if (UseClangIncludeTree) - return llvm::cas::createCASProvidingFileSystem( - CAS, llvm::vfs::createPhysicalFileSystem()); - - if (CacheFS) - return CacheFS->createProxyFS(); - - return llvm::vfs::createPhysicalFileSystem(); - } + llvm::IntrusiveRefCntPtr + getClangScanningFS(ASTContext &ctx) const; bool hasPathMapping() const { return Mapper && !Mapper->getMappings().empty(); @@ -1259,7 +1267,8 @@ class ModuleDependenciesCache { ModuleDependencyInfo dependencies); /// Record dependencies for the given module collection. - void recordDependencies(ModuleDependencyVector moduleDependencies); + void recordDependencies(ModuleDependencyVector moduleDependencies, + DiagnosticEngine &diags); /// Update stored dependencies for the given module. void updateDependency(ModuleDependencyID moduleID, diff --git a/include/swift/AST/ModuleLoader.h b/include/swift/AST/ModuleLoader.h index 3cde841b0b65f..10dc109a0647c 100644 --- a/include/swift/AST/ModuleLoader.h +++ b/include/swift/AST/ModuleLoader.h @@ -374,7 +374,7 @@ class ModuleLoader { getModuleDependencies(Identifier moduleName, StringRef moduleOutputPath, StringRef sdkModuleOutputPath, const llvm::DenseSet &alreadySeenClangModules, - clang::tooling::dependencies::DependencyScanningTool &clangScanningTool, + const std::vector &swiftModuleClangCC1CommandLineArgs, InterfaceSubContextDelegate &delegate, llvm::PrefixMapper *mapper = nullptr, bool isTestableImport = false) = 0; diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index d678f9a7c3254..262f41f7c5bf1 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -604,6 +604,11 @@ void forEachPotentialAttachedMacro( /// Describes an inherited nominal entry. struct InheritedNominalEntry : Located { + /// The `TypeRepr` of the inheritance clause entry from which this nominal was + /// sourced, if any. For example, if this is a conformance to `Y` declared as + /// `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`. + TypeRepr *inheritedTypeRepr; + ConformanceAttributes attributes; /// Whether this inherited entry was suppressed via "~". @@ -612,10 +617,10 @@ struct InheritedNominalEntry : Located { InheritedNominalEntry() { } InheritedNominalEntry(NominalTypeDecl *item, SourceLoc loc, - ConformanceAttributes attributes, - bool isSuppressed) - : Located(item, loc), attributes(attributes), - isSuppressed(isSuppressed) {} + TypeRepr *inheritedTypeRepr, + ConformanceAttributes attributes, bool isSuppressed) + : Located(item, loc), inheritedTypeRepr(inheritedTypeRepr), + attributes(attributes), isSuppressed(isSuppressed) {} }; /// Retrieve the set of nominal type declarations that are directly diff --git a/include/swift/AST/NameLookupRequests.h b/include/swift/AST/NameLookupRequests.h index 36fe7b6974dbe..26e901e7a1a08 100644 --- a/include/swift/AST/NameLookupRequests.h +++ b/include/swift/AST/NameLookupRequests.h @@ -267,7 +267,7 @@ class HasMissingDesignatedInitializersRequest : /// Request the nominal declaration extended by a given extension declaration. class ExtendedNominalRequest : public SimpleRequest< - ExtendedNominalRequest, NominalTypeDecl *(ExtensionDecl *), + ExtendedNominalRequest, NominalTypeDecl *(ExtensionDecl *, bool), RequestFlags::SeparatelyCached | RequestFlags::DependencySink> { public: using SimpleRequest::SimpleRequest; @@ -276,8 +276,8 @@ class ExtendedNominalRequest friend SimpleRequest; // Evaluation. - NominalTypeDecl * - evaluate(Evaluator &evaluator, ExtensionDecl *ext) const; + NominalTypeDecl * evaluate(Evaluator &evaluator, ExtensionDecl *ext, + bool excludeMacroExpansions) const; public: // Separate caching. diff --git a/include/swift/AST/PlatformKind.h b/include/swift/AST/PlatformKind.h index a8a869a36777a..34323bae9ba36 100644 --- a/include/swift/AST/PlatformKind.h +++ b/include/swift/AST/PlatformKind.h @@ -21,6 +21,7 @@ #include "swift/Config.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/TargetParser/Triple.h" #include namespace swift { @@ -91,6 +92,10 @@ PlatformKind targetVariantPlatform(const LangOptions &LangOpts); /// an explicit attribute for the child. bool inheritsAvailabilityFromPlatform(PlatformKind Child, PlatformKind Parent); +/// Returns the LLVM triple OS type for the given platform, if there is one. +std::optional +tripleOSTypeForPlatform(PlatformKind platform); + llvm::VersionTuple canonicalizePlatformVersion( PlatformKind platform, const llvm::VersionTuple &version); diff --git a/include/swift/AST/PluginLoader.h b/include/swift/AST/PluginLoader.h index fdcd73f13ba97..576d88e5b36b1 100644 --- a/include/swift/AST/PluginLoader.h +++ b/include/swift/AST/PluginLoader.h @@ -52,10 +52,17 @@ class PluginLoader { /// Get or lazily create and populate 'PluginMap'. llvm::DenseMap &getPluginMap(); + /// Resolved plugin path remappings. + std::vector PathRemap; + public: PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker, + std::optional> Remap = std::nullopt, bool disableSandbox = false) - : Ctx(Ctx), DepTracker(DepTracker), disableSandbox(disableSandbox) {} + : Ctx(Ctx), DepTracker(DepTracker), disableSandbox(disableSandbox) { + if (Remap) + PathRemap = std::move(*Remap); + } void setRegistry(PluginRegistry *newValue); PluginRegistry *getRegistry(); diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index 8c2773f282e71..2e550c1e098f9 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -234,6 +234,12 @@ struct PrintOptions { /// \see FileUnit::getExportedModuleName bool UseExportedModuleNames = false; + /// If true, printed module names will use the "public" (for documentation) + /// name, which may be different from the regular name. + /// + /// \see FileUnit::getPublicModuleName + bool UsePublicModuleNames = false; + /// Use the original module name to qualify a symbol. bool UseOriginallyDefinedInModuleNames = false; @@ -349,6 +355,9 @@ struct PrintOptions { /// as public bool SuppressIsolatedDeinit = false; + /// Suppress @_lifetime attribute and emit @lifetime instead. + bool SuppressLifetimes = false; + /// Whether to print the \c{/*not inherited*/} comment on factory initializers. bool PrintFactoryInitializerComment = true; @@ -397,9 +406,6 @@ struct PrintOptions { /// Suppress modify/read accessors. bool SuppressCoroutineAccessors = false; - /// Suppress the @execution attribute - bool SuppressExecutionAttribute = false; - /// List of attribute kinds that should not be printed. std::vector ExcludeAttrList = { DeclAttrKind::Transparent, DeclAttrKind::Effects, @@ -591,7 +597,7 @@ struct PrintOptions { bool AlwaysDesugarArraySliceTypes = false; /// Whether to always desugar inline array types from - /// `[ x ]` to `InlineArray` + /// `[ of ]` to `InlineArray` bool AlwaysDesugarInlineArrayTypes = false; /// Whether to always desugar dictionary types @@ -707,6 +713,7 @@ struct PrintOptions { result.MapCrossImportOverlaysToDeclaringModule = true; result.PrintCurrentMembersOnly = false; result.SuppressExpandedMacros = true; + result.UsePublicModuleNames = true; return result; } diff --git a/include/swift/AST/ProtocolConformance.h b/include/swift/AST/ProtocolConformance.h index a3981486bc1a9..ae08bfb277b09 100644 --- a/include/swift/AST/ProtocolConformance.h +++ b/include/swift/AST/ProtocolConformance.h @@ -131,6 +131,9 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance /// conformance definition. Type ConformingType; + friend class ConformanceIsolationRequest; + friend class RawConformanceIsolationRequest; + protected: // clang-format off // @@ -139,9 +142,16 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance union { uint64_t OpaqueBits; SWIFT_INLINE_BITFIELD_BASE(ProtocolConformance, + 1+1+ bitmax(NumProtocolConformanceKindBits, 8), /// The kind of protocol conformance. - Kind : bitmax(NumProtocolConformanceKindBits, 8) + Kind : bitmax(NumProtocolConformanceKindBits, 8), + + /// Whether the "raw" conformance isolation is "inferred", which applies to most conformances. + IsRawConformanceInferred : 1, + + /// Whether the computed actor isolation is nonisolated. + IsComputedNonisolated : 1 ); SWIFT_INLINE_BITFIELD_EMPTY(RootProtocolConformance, ProtocolConformance); @@ -161,9 +171,6 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance /// this conformance. IsPreconcurrencyEffectful : 1, - /// Whether the computed actor isolation is nonisolated. - IsComputedNonisolated : 1, - /// Whether there is an explicit global actor specified for this /// conformance. HasExplicitGlobalActor : 1, @@ -198,6 +205,24 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance ProtocolConformance(ProtocolConformanceKind kind, Type conformingType) : ConformingType(conformingType) { Bits.ProtocolConformance.Kind = unsigned(kind); + Bits.ProtocolConformance.IsRawConformanceInferred = false; + Bits.ProtocolConformance.IsComputedNonisolated = false; + } + + bool isRawConformanceInferred() const { + return Bits.ProtocolConformance.IsRawConformanceInferred; + } + + void setRawConformanceInferred(bool value = true) { + Bits.ProtocolConformance.IsRawConformanceInferred = value; + } + + bool isComputedNonisolated() const { + return Bits.ProtocolConformance.IsComputedNonisolated; + } + + void setComputedNonnisolated(bool value = true) { + Bits.ProtocolConformance.IsComputedNonisolated = value; } public: @@ -246,6 +271,14 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance /// Otherwise a new conformance will be created. ProtocolConformance *getCanonicalConformance(); + /// Determine the "raw" actor isolation of this conformance, before applying any inference rules. + /// + /// Most clients should use `getIsolation()`, unless they are part of isolation inference + /// themselves (e.g., conformance checking). + /// + /// - Returns std::nullopt if the isolation will be inferred. + std::optional getRawIsolation() const; + /// Determine the actor isolation of this conformance. ActorIsolation getIsolation() const; @@ -544,6 +577,7 @@ class NormalProtocolConformance : public RootProtocolConformance, friend class ValueWitnessRequest; friend class TypeWitnessRequest; friend class ConformanceIsolationRequest; + friend class RawConformanceIsolationRequest; /// The protocol being conformed to. ProtocolDecl *Protocol; @@ -552,10 +586,17 @@ class NormalProtocolConformance : public RootProtocolConformance, SourceLoc Loc; /// The location of the protocol name within the conformance. + /// + /// - Important: This is not a valid insertion location for an attribute. + /// Use `applyConformanceAttribute` instead. SourceLoc ProtocolNameLoc; - /// The location of the `@preconcurrency` attribute, if any. - SourceLoc PreconcurrencyLoc; + /// The `TypeRepr` of the inheritance clause entry that declares this + /// conformance, if any. For example, if this is a conformance to `Y` + /// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`. + /// + /// - Important: The value can be valid only for an explicit conformance. + TypeRepr *inheritedTypeRepr; /// The declaration context containing the ExtensionDecl or /// NominalTypeDecl that declared the conformance. @@ -591,30 +632,26 @@ class NormalProtocolConformance : public RootProtocolConformance, // Record the explicitly-specified global actor isolation. void setExplicitGlobalActorIsolation(TypeExpr *typeExpr); - bool isComputedNonisolated() const { - return Bits.NormalProtocolConformance.IsComputedNonisolated; - } - - void setComputedNonnisolated(bool value = true) { - Bits.NormalProtocolConformance.IsComputedNonisolated = value; - } + /// Return the `TypeRepr` of the inheritance clause entry that declares this + /// conformance, if any. For example, if this is a conformance to `Y` + /// declared as `struct S: X, Y & Z {}`, this is the `TypeRepr` for `Y & Z`. + /// + /// - Important: The value can be valid only for an explicit conformance. + TypeRepr *getInheritedTypeRepr() const { return inheritedTypeRepr; } public: NormalProtocolConformance(Type conformingType, ProtocolDecl *protocol, - SourceLoc loc, DeclContext *dc, - ProtocolConformanceState state, - ProtocolConformanceOptions options, - SourceLoc preconcurrencyLoc) + SourceLoc loc, TypeRepr *inheritedTypeRepr, + DeclContext *dc, ProtocolConformanceState state, + ProtocolConformanceOptions options) : RootProtocolConformance(ProtocolConformanceKind::Normal, conformingType), Protocol(protocol), Loc(extractNearestSourceLoc(dc)), - ProtocolNameLoc(loc), PreconcurrencyLoc(preconcurrencyLoc), + ProtocolNameLoc(loc), inheritedTypeRepr(inheritedTypeRepr), Context(dc) { assert(!conformingType->hasArchetype() && "ProtocolConformances should store interface types"); - assert((preconcurrencyLoc.isInvalid() || - options.contains(ProtocolConformanceFlags::Preconcurrency)) && - "Cannot have a @preconcurrency location without isPreconcurrency"); + setState(state); Bits.NormalProtocolConformance.IsInvalid = false; Bits.NormalProtocolConformance.IsPreconcurrencyEffectful = false; @@ -622,9 +659,11 @@ class NormalProtocolConformance : public RootProtocolConformance, Bits.NormalProtocolConformance.HasComputedAssociatedConformances = false; Bits.NormalProtocolConformance.SourceKind = unsigned(ConformanceEntryKind::Explicit); - Bits.NormalProtocolConformance.IsComputedNonisolated = false; Bits.NormalProtocolConformance.HasExplicitGlobalActor = false; setExplicitGlobalActorIsolation(options.getGlobalActorIsolationType()); + + assert((!getPreconcurrencyLoc() || isPreconcurrency()) && + "Cannot have a @preconcurrency location without isPreconcurrency"); } /// Get the protocol being conformed to. @@ -634,6 +673,9 @@ class NormalProtocolConformance : public RootProtocolConformance, SourceLoc getLoc() const { return Loc; } /// Retrieve the name of the protocol location. + /// + /// - Important: This is not a valid insertion location for an attribute. + /// Use `applyConformanceAttribute` instead. SourceLoc getProtocolNameLoc() const { return ProtocolNameLoc; } /// Get the declaration context that contains the conforming extension or @@ -704,7 +746,9 @@ class NormalProtocolConformance : public RootProtocolConformance, /// Retrieve the location of `@preconcurrency`, if there is one and it is /// known. - SourceLoc getPreconcurrencyLoc() const { return PreconcurrencyLoc; } + /// + /// - Important: The value can be valid only for an explicit conformance. + SourceLoc getPreconcurrencyLoc() const; /// Query whether this conformance was explicitly declared to be safe or /// unsafe. @@ -714,6 +758,9 @@ class NormalProtocolConformance : public RootProtocolConformance, return ExplicitSafety::Unspecified; } + /// Whether this conformance has explicitly-specified global actor isolation. + bool hasExplicitGlobalActorIsolation() const; + /// Determine whether we've lazily computed the associated conformance array /// already. bool hasComputedAssociatedConformances() const { @@ -825,6 +872,15 @@ class NormalProtocolConformance : public RootProtocolConformance, /// Triggers a request that resolves all of the conformance's value witnesses. void resolveValueWitnesses() const; + /// If the necessary source location information is found, attaches a fix-it + /// to the given diagnostic for applying the given attribute to the + /// conformance. + /// + /// \param attrStr A conformance attribute as a string, e.g. "@unsafe" or + /// "nonisolated". + void applyConformanceAttribute(InFlightDiagnostic &diag, + std::string attrStr) const; + /// Determine whether the witness for the given type requirement /// is the default definition. bool usesDefaultDefinition(AssociatedTypeDecl *requirement) const { diff --git a/include/swift/AST/RuntimeVersions.def b/include/swift/AST/RuntimeVersions.def index 6a5c8918f8160..d04192382f47a 100644 --- a/include/swift/AST/RuntimeVersions.def +++ b/include/swift/AST/RuntimeVersions.def @@ -152,7 +152,10 @@ RUNTIME_VERSION( RUNTIME_VERSION( (6, 1), - FUTURE + PLATFORM(macOS, (15, 4, 0)) + PLATFORM(iOS, (18, 4, 0)) + PLATFORM(watchOS, (11, 4, 0)) + PLATFORM(visionOS,(2, 4, 0)) ) RUNTIME_VERSION( diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 2c18a09d21823..4b75884d90175 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -338,6 +338,10 @@ class SILOptions { // Whether to allow merging traps and cond_fails. bool MergeableTraps = false; + /// Whether the @yield_once_2 convention is used by accessors added with the + /// CoroutineAccessors feature (i.e. read2/modify2). + bool CoroutineAccessorsUseYieldOnce2 = false; + SILOptions() {} /// Return a hash code of any components from these options that should diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index ff697f5ef49b4..7cde0bc4c1521 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -35,7 +35,7 @@ namespace swift { enum class ModuleSearchPathKind { Import, Framework, - DarwinImplicitFramework, + ImplicitFramework, RuntimeLibrary, }; @@ -323,6 +323,10 @@ class SearchPathOptions { friend bool operator!=(const SearchPath &LHS, const SearchPath &RHS) { return !(LHS == RHS); } + friend llvm::hash_code + hash_value(const SearchPath &searchPath) { + return llvm::hash_combine(searchPath.Path, searchPath.IsSystem); + } }; private: @@ -352,12 +356,8 @@ class SearchPathOptions { /// When on Darwin the framework paths that are implicitly imported. /// $SDKROOT/System/Library/Frameworks/ and $SDKROOT/Library/Frameworks/. /// - /// On non-Darwin platforms these are populated, but ignored. - /// - /// Computed when the SDK path is set and cached so we can reference the - /// Darwin implicit framework search paths as \c StringRef from - /// \c ModuleSearchPath. - std::vector DarwinImplicitFrameworkSearchPaths; + /// Must be modified through setter to keep \c Lookup in sync. + std::vector ImplicitFrameworkSearchPaths; /// Compiler plugin library search paths. std::vector CompilerPluginLibraryPaths; @@ -397,21 +397,6 @@ class SearchPathOptions { void setSDKPath(std::string NewSDKPath) { SDKPath = NewSDKPath; - - // Compute Darwin implicit framework search paths. - SmallString<128> systemFrameworksScratch(NewSDKPath); - llvm::sys::path::append(systemFrameworksScratch, "System", "Library", - "Frameworks"); - SmallString<128> systemSubFrameworksScratch(NewSDKPath); - llvm::sys::path::append(systemSubFrameworksScratch, "System", "Library", - "SubFrameworks"); - SmallString<128> frameworksScratch(NewSDKPath); - llvm::sys::path::append(frameworksScratch, "Library", "Frameworks"); - DarwinImplicitFrameworkSearchPaths = {systemFrameworksScratch.str().str(), - systemSubFrameworksScratch.str().str(), - frameworksScratch.str().str()}; - - Lookup.searchPathsDidChange(); } /// Retrieves the corresponding parent platform path for the SDK, or @@ -466,8 +451,14 @@ class SearchPathOptions { /// The extra implicit framework search paths on Apple platforms: /// $SDKROOT/System/Library/Frameworks/ and $SDKROOT/Library/Frameworks/. - ArrayRef getDarwinImplicitFrameworkSearchPaths() const { - return DarwinImplicitFrameworkSearchPaths; + ArrayRef getImplicitFrameworkSearchPaths() const { + return ImplicitFrameworkSearchPaths; + } + + void setImplicitFrameworkSearchPaths( + std::vector NewImplicitFrameworkSearchPaths) { + ImplicitFrameworkSearchPaths = NewImplicitFrameworkSearchPaths; + Lookup.searchPathsDidChange(); } ArrayRef getRuntimeLibraryImportPaths() const { @@ -501,14 +492,17 @@ class SearchPathOptions { /// Path to in-process plugin server shared library. std::string InProcessPluginServerPath; - /// Don't look in for compiler-provided modules. - bool SkipRuntimeLibraryImportPaths = false; + /// Don't automatically add any import paths. + bool SkipAllImplicitImportPaths = false; - /// Don't include SDK paths in the RuntimeLibraryImportPaths - bool ExcludeSDKPathsFromRuntimeLibraryImportPaths = false; + /// Don't automatically add any import paths from the SDK. + bool SkipSDKImportPaths = false; /// Scanner Prefix Mapper. - std::vector ScannerPrefixMapper; + std::vector> ScannerPrefixMapper; + + /// Verify resolved plugin is not changed. + bool ResolvedPluginVerification = false; /// When set, don't validate module system dependencies. /// @@ -596,35 +590,24 @@ class SearchPathOptions { makeOverlayFileSystem( llvm::IntrusiveRefCntPtr BaseFS) const; -private: - static StringRef pathStringFromSearchPath(const SearchPath &next) { - return next.Path; - }; - public: /// Return a hash code of any components from these options that should /// contribute to a Swift Bridging PCH hash. llvm::hash_code getPCHHashComponents() const { using llvm::hash_combine; using llvm::hash_combine_range; - - using SearchPathView = - ArrayRefView; - SearchPathView importPathsOnly{ImportSearchPaths}; - SearchPathView frameworkPathsOnly{FrameworkSearchPaths}; - return hash_combine(SDKPath, - // FIXME: Should we include the system-ness of - // search paths too? - hash_combine_range(importPathsOnly.begin(), importPathsOnly.end()), + hash_combine_range(ImportSearchPaths.begin(), ImportSearchPaths.end()), hash_combine_range(VFSOverlayFiles.begin(), VFSOverlayFiles.end()), - hash_combine_range(frameworkPathsOnly.begin(), - frameworkPathsOnly.end()), + hash_combine_range(FrameworkSearchPaths.begin(), + FrameworkSearchPaths.end()), hash_combine_range(LibrarySearchPaths.begin(), LibrarySearchPaths.end()), RuntimeResourcePath, hash_combine_range(RuntimeLibraryImportPaths.begin(), RuntimeLibraryImportPaths.end()), + hash_combine_range(ImplicitFrameworkSearchPaths.begin(), + ImplicitFrameworkSearchPaths.end()), DisableModulesValidateSystemDependencies, ScannerModuleValidation, ModuleLoadMode); diff --git a/include/swift/AST/SemanticAttrs.def b/include/swift/AST/SemanticAttrs.def index f2b93fb575ffe..ffe2717cb304c 100644 --- a/include/swift/AST/SemanticAttrs.def +++ b/include/swift/AST/SemanticAttrs.def @@ -165,5 +165,7 @@ SEMANTICS_ATTR(USE_FRAME_POINTER, "use_frame_pointer") SEMANTICS_ATTR(FIXED_STORAGE_CHECK_INDEX, "fixed_storage.check_index") SEMANTICS_ATTR(FIXED_STORAGE_GET_COUNT, "fixed_storage.get_count") +SEMANTICS_ATTR(NO_SIL_VERIFICATION, "sil.verify_none") + #undef SEMANTICS_ATTR diff --git a/include/swift/AST/SourceFile.h b/include/swift/AST/SourceFile.h index b154007d7e864..3e8b1d77b863b 100644 --- a/include/swift/AST/SourceFile.h +++ b/include/swift/AST/SourceFile.h @@ -31,6 +31,7 @@ class AvailabilityScope; class PersistentParserState; struct SourceFileExtras; class Token; +enum class DefaultIsolation : uint8_t; /// Kind of import affecting how a decl can be reexported. /// @@ -53,15 +54,6 @@ enum class RestrictedImportKind { /// Import that limits the access level of imported entities. using ImportAccessLevel = std::optional>; -/// Language options only for use with a specific SourceFile. -/// -/// Vended by SourceFile::getLanguageOptions(). -struct SourceFileLangOptions { - /// If unset, no value was provided. If a Type, that type is the type of the - /// isolation. If set to an empty type, nil was specified explicitly. - std::optional defaultIsolation; -}; - /// A file containing Swift source code. /// /// This is a .swift or .sil file (or a virtual file, such as the contents of @@ -571,9 +563,6 @@ class SourceFile final : public FileUnit { ObjCSelector selector, SmallVectorImpl &results) const override; - /// File level language options. - SourceFileLangOptions getLanguageOptions() const; - protected: virtual void lookupOperatorDirect(Identifier name, OperatorFixity fixity, @@ -701,6 +690,11 @@ class SourceFile final : public FileUnit { DelayedParserState = std::move(state); } + /// Retrieve default action isolation to be used for this source file. + /// It's determine based on on top-level `using <>` declaration + /// found in the file. + std::optional getDefaultIsolation() const; + SWIFT_DEBUG_DUMP; void dump(raw_ostream &os, diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index 0682f73e5bcb1..799e824fde7c8 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -504,8 +504,7 @@ class alignas(8) PoundAvailableInfo final : ArrayRef queries, SourceLoc RParenLoc, bool isUnavailability) : PoundLoc(PoundLoc), LParenLoc(LParenLoc), RParenLoc(RParenLoc), - NumQueries(queries.size()), AvailableRange(VersionRange::empty()), - VariantAvailableRange(VersionRange::empty()), Flags() { + NumQueries(queries.size()), Flags() { Flags.isInvalid = false; Flags.isUnavailability = isUnavailability; std::uninitialized_copy(queries.begin(), queries.end(), diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index 961d87d87bcd7..c46d7ffd18235 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -340,7 +340,6 @@ struct OuterSubstitutions { SubstitutionMap subs; unsigned depth; - bool isUnsubstitutedTypeParameter(Type type) const; Type operator()(SubstitutableType *type) const; ProtocolConformanceRef operator()(CanType dependentType, Type conformingReplacementType, diff --git a/include/swift/AST/TypeAttr.def b/include/swift/AST/TypeAttr.def index 811e85a08d865..4defd43cf1cdf 100644 --- a/include/swift/AST/TypeAttr.def +++ b/include/swift/AST/TypeAttr.def @@ -67,7 +67,7 @@ TYPE_ATTR(_opaqueReturnTypeOf, OpaqueReturnTypeOf) TYPE_ATTR(isolated, Isolated) SIMPLE_TYPE_ATTR(nonisolated, Nonisolated) SIMPLE_TYPE_ATTR(_addressable, Addressable) -TYPE_ATTR(execution, Execution) +SIMPLE_TYPE_ATTR(concurrent, Concurrent) // SIL-specific attributes SIMPLE_SIL_TYPE_ATTR(async, Async) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 112790754f961..8fa4dfd751459 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -475,6 +475,28 @@ class ConformanceHasEffectRequest : bool isCached() const { return true; } }; +class RawConformanceIsolationRequest : + public SimpleRequest(ProtocolConformance *), + RequestFlags::SeparatelyCached | + RequestFlags::SplitCached> { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + // Evaluation. + std::optional + evaluate(Evaluator &evaluator, ProtocolConformance *conformance) const; + +public: + // Separate caching. + bool isCached() const { return true; } + std::optional> getCachedResult() const; + void cacheResult(std::optional result) const; +}; + class ConformanceIsolationRequest : public SimpleRequest>( - AbstractFunctionDecl *), + std::optional>(ValueDecl *), RequestFlags::SeparatelyCached | RequestFlags::SplitCached> { public: using SimpleRequest::SimpleRequest; @@ -5083,7 +5104,7 @@ class LifetimeDependenceInfoRequest friend SimpleRequest; std::optional> - evaluate(Evaluator &evaluator, AbstractFunctionDecl *AFD) const; + evaluate(Evaluator &evaluator, ValueDecl *AFD) const; public: // Separate caching. @@ -5134,6 +5155,26 @@ class ParamCaptureInfoRequest : void cacheResult(CaptureInfo value) const; }; +class PatternBindingCaptureInfoRequest + : public SimpleRequest { +public: + using SimpleRequest::SimpleRequest; + +private: + friend SimpleRequest; + + CaptureInfo evaluate(Evaluator &evaluator, PatternBindingDecl *PBD, + unsigned idx) const; + +public: + // Separate caching. + bool isCached() const { return true; } + std::optional getCachedResult() const; + void cacheResult(CaptureInfo info) const; +}; + class SuppressesConformanceRequest : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -5228,7 +5269,7 @@ class GenericTypeParamDeclGetValueTypeRequest private: friend SimpleRequest; - Type evaluate(Evaluator &evaluator, GenericTypeParamDecl *decl) const; + Type evaluate(Evaluator &evaluator, const GenericTypeParamDecl *decl) const; public: bool isCached() const { return true; } @@ -5293,24 +5334,21 @@ class SemanticAvailabilitySpecRequest void cacheResult(std::optional value) const; }; -class SourceFileLangOptionsRequest - : public SimpleRequest(const SourceFile *), RequestFlags::Cached> { - public: using SimpleRequest::SimpleRequest; private: friend SimpleRequest; - SourceFileLangOptions evaluate(Evaluator &evaluator, - SourceFile *sourceFile) const; + std::optional evaluate(Evaluator &evaluator, + const SourceFile *file) const; public: bool isCached() const { return true; } - std::optional getCachedResult() const; - void cacheResult(SourceFileLangOptions value) const; }; #define SWIFT_TYPEID_ZONE TypeChecker diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 5173cc5d3a196..a5812410ee000 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -406,6 +406,10 @@ SWIFT_REQUEST(TypeChecker, PolymorphicEffectRequirementsRequest, SWIFT_REQUEST(TypeChecker, ConformanceHasEffectRequest, bool(EffectKind, ProtocolConformanceRef), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, RawConformanceIsolationRequest, + std::optional(ProtocolConformance *), + SeparatelyCached | SplitCached, + NoLocationInfo) SWIFT_REQUEST(TypeChecker, ConformanceIsolationRequest, ActorIsolation(ProtocolConformance *), SeparatelyCached | SplitCached, @@ -608,12 +612,15 @@ SWIFT_REQUEST(TypeChecker, CaptureInfoRequest, SWIFT_REQUEST(TypeChecker, ParamCaptureInfoRequest, CaptureInfo(ParamDecl *), SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, PatternBindingCaptureInfoRequest, + CaptureInfo(PatternBindingDecl *, unsigned), + SeparatelyCached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, CustomDerivativesRequest, CustomDerivativesResult(SourceFile *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, GenericTypeParamDeclGetValueTypeRequest, - Type(GenericTypeParamDecl *), Cached, NoLocationInfo) + Type(const GenericTypeParamDecl *), Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, SemanticAvailableAttrRequest, std::optional @@ -624,5 +631,6 @@ SWIFT_REQUEST(TypeChecker, SemanticAvailabilitySpecRequest, (const AvailabilitySpec *, const DeclContext *), SeparatelyCached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, SourceFileLangOptionsRequest, - SourceFileLangOptions (SourceFile *), Cached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, DefaultIsolationInSourceFileRequest, + std::optional(const SourceFile *), + Cached, NoLocationInfo) diff --git a/include/swift/AST/TypeMemberVisitor.h b/include/swift/AST/TypeMemberVisitor.h index 7ad863f980968..479a84510d49d 100644 --- a/include/swift/AST/TypeMemberVisitor.h +++ b/include/swift/AST/TypeMemberVisitor.h @@ -41,6 +41,7 @@ class TypeMemberVisitor : public DeclVisitor { BAD_MEMBER(Operator) BAD_MEMBER(PrecedenceGroup) BAD_MEMBER(Macro) + BAD_MEMBER(Using) RetTy visitMacroExpansionDecl(MacroExpansionDecl *D) { // Expansion already visited as auxiliary decls. diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index 5ae2e5c658401..b910f88e33e5f 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -207,7 +207,7 @@ TYPE(PackExpansion, Type) TYPE(PackElement, Type) UNCHECKED_TYPE(TypeVariable, Type) UNCHECKED_TYPE(ErrorUnion, Type) -ALWAYS_CANONICAL_TYPE(Integer, Type) +TYPE(Integer, Type) ABSTRACT_SUGARED_TYPE(Sugar, Type) SUGARED_TYPE(TypeAlias, SugarType) SUGARED_TYPE(Locatable, SugarType) diff --git a/include/swift/AST/TypeRepr.h b/include/swift/AST/TypeRepr.h index 749cf72190223..771819d29ace8 100644 --- a/include/swift/AST/TypeRepr.h +++ b/include/swift/AST/TypeRepr.h @@ -641,7 +641,7 @@ class ArrayTypeRepr : public TypeRepr { friend class TypeRepr; }; -/// An InlineArray type e.g `[2 x Foo]`, sugar for `InlineArray<2, Foo>`. +/// An InlineArray type e.g `[2 of Foo]`, sugar for `InlineArray<2, Foo>`. class InlineArrayTypeRepr : public TypeRepr { TypeRepr *Count; TypeRepr *Element; @@ -1249,6 +1249,35 @@ class SendingTypeRepr : public SpecifierTypeRepr { static bool classof(const SendingTypeRepr *T) { return true; } }; +/// A 'nonisolated(nonsending)' function type. +/// \code +/// x : nonisolated(nonsending) () async -> Int +/// \endcode +class CallerIsolatedTypeRepr : public TypeRepr { + TypeRepr *Base; + SourceLoc Loc; + +public: + CallerIsolatedTypeRepr(TypeRepr *Base, SourceLoc Loc) + : TypeRepr(TypeReprKind::CallerIsolated), Base(Base), Loc(Loc) { + assert(Base); + } + + TypeRepr *getBase() const { return Base; } + + static bool classof(const TypeRepr *T) { + return T->getKind() == TypeReprKind::CallerIsolated; + } + static bool classof(const CallerIsolatedTypeRepr *T) { return true; } + +private: + SourceLoc getStartLocImpl() const { return Loc; } + SourceLoc getEndLocImpl() const { return Base->getEndLoc(); } + SourceLoc getLocImpl() const { return Base->getLoc(); } + void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const; + friend class TypeRepr; +}; + /// A TypeRepr for a known, fixed type. /// /// Fixed type representations should be used sparingly, in places @@ -1680,6 +1709,7 @@ inline bool TypeRepr::isSimple() const { case TypeReprKind::ConstValue: case TypeReprKind::LifetimeDependent: case TypeReprKind::Integer: + case TypeReprKind::CallerIsolated: return true; } llvm_unreachable("bad TypeRepr kind"); diff --git a/include/swift/AST/TypeReprNodes.def b/include/swift/AST/TypeReprNodes.def index a1f7e51ded313..6a98b8f4dd3e6 100644 --- a/include/swift/AST/TypeReprNodes.def +++ b/include/swift/AST/TypeReprNodes.def @@ -77,6 +77,7 @@ TYPEREPR(Fixed, TypeRepr) TYPEREPR(SILBox, TypeRepr) TYPEREPR(Self, TypeRepr) TYPEREPR(LifetimeDependent, TypeRepr) +TYPEREPR(CallerIsolated, TypeRepr) TYPEREPR(Integer, TypeRepr) LAST_TYPEREPR(Integer) diff --git a/include/swift/AST/TypeTransform.h b/include/swift/AST/TypeTransform.h index 8348506c836a8..fe437f9e642d8 100644 --- a/include/swift/AST/TypeTransform.h +++ b/include/swift/AST/TypeTransform.h @@ -358,7 +358,8 @@ case TypeKind::Id: } }); if (didRemoveLifetimeDependencies) { - extInfo = extInfo.withLifetimeDependencies(substDependenceInfos); + extInfo = extInfo.withLifetimeDependencies( + ctx.AllocateCopy(substDependenceInfos)); } } @@ -939,7 +940,8 @@ case TypeKind::Id: }); if (didRemoveLifetimeDependencies) { - extInfo = extInfo->withLifetimeDependencies(substDependenceInfos); + extInfo = extInfo->withLifetimeDependencies( + ctx.AllocateCopy(substDependenceInfos)); } } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index bc53a44510809..9f72d3839d748 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -318,6 +318,11 @@ class RecursiveTypeProperties { Bits &= ~HasDependentMember; } + /// Remove the IsUnsafe property from this set. + void removeIsUnsafe() { + Bits &= ~IsUnsafe; + } + /// Test for a particular property in this set. bool operator&(Property prop) const { return Bits & prop; @@ -695,6 +700,14 @@ class alignas(1 << TypeAlignInBits) TypeBase /// Returns true if this contextual type is (Escapable && !isNoEscape). bool mayEscape() { return !isNoEscape() && isEscapable(); } + /// Returns true if this contextual type satisfies a conformance to + /// BitwiseCopyable. + bool isBitwiseCopyable(); + + /// Returns true if this type satisfies a conformance to BitwiseCopyable in + /// the given generic signature. + bool isBitwiseCopyable(GenericSignature sig); + /// Are values of this type essentially just class references, /// possibly with some sort of additional information? /// @@ -715,6 +728,12 @@ class alignas(1 << TypeAlignInBits) TypeBase return getRecursiveProperties().hasTypeVariable(); } + // Convenience for checking whether the given type either has a type + // variable or placeholder. + bool hasTypeVariableOrPlaceholder() const { + return hasTypeVariable() || hasPlaceholder(); + } + /// Determine where this type is a type variable or a dependent /// member root in a type variable. bool isTypeVariableOrMember(); @@ -1049,6 +1068,9 @@ class alignas(1 << TypeAlignInBits) TypeBase bool is##NAME(); #include "swift/AST/KnownStdlibTypes.def" + /// Check if this type is from the Builtin module. + bool isBuiltinType(); + /// Check if this type is equal to Builtin.IntN. bool isBuiltinIntegerType(unsigned bitWidth); @@ -4037,6 +4059,7 @@ struct ParameterListInfo { SmallBitVector propertyWrappers; SmallBitVector implicitSelfCapture; SmallBitVector inheritActorContext; + SmallBitVector alwaysInheritActorContext; SmallBitVector variadicGenerics; SmallBitVector sendingParameters; @@ -4063,7 +4086,8 @@ struct ParameterListInfo { /// Whether the given parameter is a closure that should inherit the /// actor context from the context in which it was created. - bool inheritsActorContext(unsigned paramIdx) const; + std::pair + inheritsActorContext(unsigned paramIdx) const; bool isVariadicGenericParameter(unsigned paramIdx) const; @@ -5022,6 +5046,8 @@ enum class SILCoroutineKind : uint8_t { class SILFunctionConventions; +Type substOpaqueTypesWithUnderlyingTypes(Type type, + TypeExpansionContext context); CanType substOpaqueTypesWithUnderlyingTypes(CanType type, TypeExpansionContext context); @@ -5188,12 +5214,12 @@ class SILFunctionType final /// Given an existing ExtInfo, and a set of interface parameters and results /// destined for a new SILFunctionType, return a new ExtInfo with only the /// lifetime dependencies relevant after substitution. - static ExtInfo - getSubstLifetimeDependencies(GenericSignature genericSig, - ExtInfo origExtInfo, - ArrayRef params, - ArrayRef yields, - ArrayRef results); + static ExtInfo getSubstLifetimeDependencies(GenericSignature genericSig, + ExtInfo origExtInfo, + ASTContext &context, + ArrayRef params, + ArrayRef yields, + ArrayRef results); /// Return a structurally-identical function type with a slightly tweaked /// ExtInfo. @@ -5450,6 +5476,10 @@ class SILFunctionType final return getParameters().back(); } + unsigned getSelfParameterIndex() const { + return NumParameters - 1; + } + /// Return SILParameterInfo for the isolated parameter in this SILFunctionType /// if one exists. Returns None otherwise. std::optional maybeGetIsolatedParameter() const { @@ -5647,6 +5677,24 @@ class SILFunctionType final return getLifetimeDependenceFor(getNumParameters()); } + /// Return true of the specified parameter is addressable based on its type + /// lowering in 'caller's context. This includes @_addressableForDependencies + /// parameter types. + /// + /// Defined in SILType.cpp. + bool isAddressable(unsigned paramIdx, SILFunction *caller); + + /// Return true of the specified parameter is addressable based on its type + /// lowering. This includes @_addressableForDependencies parameter types. + /// + /// 'genericEnv' may be null. + /// + /// Defined in SILType.cpp. + bool isAddressable(unsigned paramIdx, SILModule &module, + GenericEnvironment *genericEnv, + Lowering::TypeConverter &typeConverter, + TypeExpansionContext expansion); + /// Returns true if the function type stores a Clang type that cannot /// be derived from its Swift type. Returns false otherwise, including if /// the function type is not @convention(c) or @convention(block). @@ -6255,7 +6303,7 @@ class ArraySliceType : public UnarySyntaxSugarType { } }; -/// An InlineArray type e.g `[2 x Foo]`, sugar for `InlineArray<2, Foo>`. +/// An InlineArray type e.g `[2 of Foo]`, sugar for `InlineArray<2, Foo>`. class InlineArrayType : public SyntaxSugarType { Type Count; Type Elt; @@ -7908,10 +7956,27 @@ class IntegerType final : public TypeBase, public llvm::FoldingSetNode { friend class ASTContext; StringRef Value; + // Integers may not be canonical, but don't have any structural type + // components from which to get the ASTContext, so we need to store a + // reference to it ourselves. + const ASTContext &Context; + + static const ASTContext * + getCanonicalIntegerLiteralContext(StringRef value, const ASTContext &ctx) { + for (char c : value) { + // A canonical integer literal consists only of ASCII decimal digits. + if (c < '0' || c > '9') { + return nullptr; + } + } + return &ctx; + } IntegerType(StringRef value, bool isNegative, const ASTContext &ctx) : - TypeBase(TypeKind::Integer, &ctx, RecursiveTypeProperties()), - Value(value) { + TypeBase(TypeKind::Integer, getCanonicalIntegerLiteralContext(value, ctx), + RecursiveTypeProperties()), + Value(value), + Context(ctx) { Bits.IntegerType.IsNegative = isNegative; } @@ -7941,6 +8006,8 @@ class IntegerType final : public TypeBase, public llvm::FoldingSetNode { static bool classof(const TypeBase *T) { return T->getKind() == TypeKind::Integer; } + + const ASTContext &getASTContext() { return Context; } }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(IntegerType, Type) @@ -8095,6 +8162,10 @@ inline GenericTypeDecl *TypeBase::getAnyGeneric() { return getCanonicalType().getAnyGeneric(); } +inline bool TypeBase::isBuiltinType() { + return isa(getCanonicalType()); +} + inline bool TypeBase::isBuiltinIntegerType(unsigned n) { if (auto intTy = dyn_cast(getCanonicalType())) return intTy->getWidth().isFixedWidth() diff --git a/include/swift/AST/UnsafeUse.h b/include/swift/AST/UnsafeUse.h index 70f8f2ecc2aec..ba6958ea44874 100644 --- a/include/swift/AST/UnsafeUse.h +++ b/include/swift/AST/UnsafeUse.h @@ -53,6 +53,8 @@ class UnsafeUse { ReferenceToUnsafeThroughTypealias, /// A call to an unsafe declaration. CallToUnsafe, + /// An unsafe argument in a call. + CallArgument, /// A @preconcurrency import. PreconcurrencyImport, /// A use of withoutActuallyEscaping that lacks enforcement that the @@ -91,6 +93,15 @@ class UnsafeUse { MakeTemporarilyEscapableExpr *temporarilyEscaping; + struct { + Expr *call; + const Decl *calleeDecl; + TypeBase *paramType; + const void *argumentName; + unsigned argumentIndex; + Expr *argument; + } callArgument; + const ImportDecl *importDecl; } storage; @@ -201,6 +212,19 @@ class UnsafeUse { decl, type, location); } + static UnsafeUse forCallArgument( + Expr *call, const Decl *calleeDecl, Type paramType, + Identifier argumentName, unsigned argumentIndex, Expr *argument) { + UnsafeUse result(CallArgument); + result.storage.callArgument.call = call; + result.storage.callArgument.calleeDecl = calleeDecl; + result.storage.callArgument.paramType = paramType.getPointer(); + result.storage.callArgument.argumentName = argumentName.getAsOpaquePointer(); + result.storage.callArgument.argumentIndex = argumentIndex; + result.storage.callArgument.argument = argument; + return result; + } + static UnsafeUse forTemporarilyEscaping(MakeTemporarilyEscapableExpr *expr) { UnsafeUse result(TemporarilyEscaping); result.storage.temporarilyEscaping = expr; @@ -242,6 +266,9 @@ class UnsafeUse { return SourceLoc( llvm::SMLoc::getFromPointer((const char *)storage.entity.location)); + case CallArgument: + return storage.callArgument.call->getLoc(); + case TemporarilyEscaping: return storage.temporarilyEscaping->getLoc(); @@ -257,6 +284,7 @@ class UnsafeUse { case Witness: case TemporarilyEscaping: case PreconcurrencyImport: + case CallArgument: // Cannot replace location. return; @@ -298,6 +326,9 @@ class UnsafeUse { case CallToUnsafe: return storage.entity.decl; + case CallArgument: + return storage.callArgument.calleeDecl; + case UnsafeConformance: case TemporarilyEscaping: return nullptr; @@ -330,6 +361,7 @@ class UnsafeUse { case ReferenceToUnsafeThroughTypealias: case ReferenceToUnsafeStorage: case CallToUnsafe: + case CallArgument: case UnsafeConformance: case PreconcurrencyImport: case TemporarilyEscaping: @@ -360,6 +392,9 @@ class UnsafeUse { case CallToUnsafe: return storage.entity.type; + case CallArgument: + return storage.callArgument.paramType; + case TemporarilyEscaping: return storage.temporarilyEscaping->getOpaqueValue()->getType(); } @@ -386,11 +421,24 @@ class UnsafeUse { case ReferenceToUnsafeStorage: case ReferenceToUnsafeThroughTypealias: case CallToUnsafe: + case CallArgument: case TemporarilyEscaping: case PreconcurrencyImport: return ProtocolConformanceRef::forInvalid(); } } + + /// Get information about the call argument. + /// + /// Produces the argument name, argument index, and argument expression for + /// a unsafe use describing a call argument. + std::tuple getCallArgument() const { + assert(getKind() == CallArgument); + return std::make_tuple( + Identifier::getFromOpaquePointer(storage.callArgument.argumentName), + storage.callArgument.argumentIndex, + storage.callArgument.argument); + } }; } // end namespace swift diff --git a/include/swift/Basic/BasicBridgingImpl.h b/include/swift/Basic/BasicBridgingImpl.h index 35efe357fa253..0ab0a56da33af 100644 --- a/include/swift/Basic/BasicBridgingImpl.h +++ b/include/swift/Basic/BasicBridgingImpl.h @@ -146,7 +146,11 @@ swift_ASTGen_bridgedSwiftClosureCall_1(const void *_Nonnull closure, const void *_Nullable arg1); void BridgedSwiftClosure::operator()(const void *_Nullable arg1) { +#if SWIFT_BUILD_SWIFT_SYNTAX swift_ASTGen_bridgedSwiftClosureCall_1(closure, arg1); +#else + llvm_unreachable("Must not be used in C++-only build"); +#endif } SWIFT_END_NULLABILITY_ANNOTATIONS diff --git a/include/swift/Basic/CASOptions.h b/include/swift/Basic/CASOptions.h index fb63938e1f3fb..567c34671fc49 100644 --- a/include/swift/Basic/CASOptions.h +++ b/include/swift/Basic/CASOptions.h @@ -34,17 +34,17 @@ class CASOptions final { /// Skip replaying outputs from cache. bool CacheSkipReplay = false; + /// Import modules from CAS. + bool ImportModuleFromCAS = false; + /// CASOptions clang::CASOptions CASOpts; - /// CASFS Root. - std::vector CASFSRootIDs; - /// Clang Include Trees. - std::vector ClangIncludeTrees; + std::string ClangIncludeTree; /// Clang Include Tree FileList. - std::vector ClangIncludeTreeFileList; + std::string ClangIncludeTreeFileList; /// CacheKey for input file. std::string InputFileKey; @@ -62,9 +62,8 @@ class CASOptions final { /// Check to see if a CASFileSystem is required. bool requireCASFS() const { return EnableCaching && - (!CASFSRootIDs.empty() || !ClangIncludeTrees.empty() || - !ClangIncludeTreeFileList.empty() || !InputFileKey.empty() || - !BridgingHeaderPCHCacheKey.empty()); + (!ClangIncludeTree.empty() || !ClangIncludeTreeFileList.empty() || + !InputFileKey.empty() || !BridgingHeaderPCHCacheKey.empty()); } /// Return a hash code of any components from these options that should diff --git a/include/swift/Basic/Casting.h b/include/swift/Basic/Casting.h new file mode 100644 index 0000000000000..85ffe8f0ae6ac --- /dev/null +++ b/include/swift/Basic/Casting.h @@ -0,0 +1,59 @@ +//===--- Casting.h - Helpers for casting ------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_BASIC_CASTING_H +#define SWIFT_BASIC_CASTING_H + +#include + +namespace swift { + +/// Cast between two function types. Use in place of std::bit_cast, which +/// doesn't work on ARM64e with address-discriminated signed function types. +/// +/// Address-discriminated ptrauth attributes can only be applied to values with +/// a defined storage location, such as struct fields, since their value is +/// inherently tied to their address. They can't be applied to function +/// paremeters. When passing such a value to a templated function, the ptrauth +/// attribute disappears from the inferred type. +/// +/// bit_cast takes the source by reference, which means that the ptrauth +/// attribute remains on the inferred type, and the value is not trivially +/// copyable. +/// +/// function_cast instead takes the source by value, avoiding that issue and +/// ensuring that passed-in function pointers are always trivially copyable. +template +Destination function_cast(Source source) { + static_assert(sizeof(Destination) == sizeof(Source), + "Source and destination must be the same size"); + static_assert(std::is_trivially_copyable_v, + "The source type must be trivially constructible"); + static_assert(std::is_trivially_copyable_v, + "The destination type must be trivially constructible"); + +#if __has_feature(ptrauth_calls) + // Use reinterpret_cast here so we perform any necessary auth-and-sign. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-mismatch" + return reinterpret_cast(source); +#pragma clang diagnostic pop +#else + Destination destination; + memcpy(&destination, &source, sizeof(source)); + return destination; +#endif +} + +} + +#endif diff --git a/include/swift/Basic/Feature.h b/include/swift/Basic/Feature.h index d0727bd239efe..b05080bbf3a86 100644 --- a/include/swift/Basic/Feature.h +++ b/include/swift/Basic/Feature.h @@ -10,8 +10,10 @@ // //===----------------------------------------------------------------------===// -#ifndef SWIFT_BASIC_FEATURES_H -#define SWIFT_BASIC_FEATURES_H +#ifndef SWIFT_BASIC_FEATURE_H +#define SWIFT_BASIC_FEATURE_H + +#include "swift/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include @@ -21,53 +23,72 @@ namespace swift { class LangOptions; /// Enumeration describing all of the named features. -enum class Feature : uint16_t { +struct Feature { + enum class InnerKind : uint16_t { #define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName, #include "swift/Basic/Features.def" -}; + }; + + InnerKind kind; -constexpr unsigned numFeatures() { - enum Features { + constexpr Feature(InnerKind kind) : kind(kind) {} + constexpr Feature(unsigned inputKind) : kind(InnerKind(inputKind)) {} + + constexpr operator InnerKind() const { return kind; } + constexpr explicit operator unsigned() const { return unsigned(kind); } + constexpr explicit operator size_t() const { return size_t(kind); } + + static constexpr unsigned getNumFeatures() { + enum Features { #define LANGUAGE_FEATURE(FeatureName, SENumber, Description) FeatureName, #include "swift/Basic/Features.def" - NumFeatures - }; - return NumFeatures; -} + NumFeatures + }; + return NumFeatures; + } -/// Check whether the given feature is available in production compilers. -bool isFeatureAvailableInProduction(Feature feature); +#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \ + static const Feature FeatureName; +#include "swift/Basic/Features.def" -/// Determine the in-source name of the given feature. -llvm::StringRef getFeatureName(Feature feature); + /// Check whether the given feature is available in production compilers. + bool isAvailableInProduction() const; -/// Determine whether the first feature is more recent (and thus implies -/// the existence of) the second feature. Only meaningful for suppressible -/// features. -inline bool featureImpliesFeature(Feature feature, Feature implied) { - // Suppressible features are expected to be listed in order of - // addition in Features.def. - return (unsigned) feature < (unsigned) implied; -} + /// Determine the in-source name of the given feature. + llvm::StringRef getName() const; -/// Get the feature corresponding to this "future" feature, if there is one. -std::optional getUpcomingFeature(llvm::StringRef name); + /// Determine whether the given feature supports migration mode. + bool isMigratable() const; -/// Get the feature corresponding to this "experimental" feature, if there is -/// one. -std::optional getExperimentalFeature(llvm::StringRef name); + /// Determine whether this feature should be included in the + /// module interface + bool includeInModuleInterface() const; -/// Get the major language version in which this feature was introduced, or -/// \c None if it does not have such a version. -std::optional getFeatureLanguageVersion(Feature feature); + /// Determine whether the first feature is more recent (and thus implies + /// the existence of) the second feature. Only meaningful for suppressible + /// features. + constexpr bool featureImpliesFeature(Feature implied) const { + // Suppressible features are expected to be listed in order of + // addition in Features.def. + return (unsigned)kind < (unsigned)implied.kind; + } -/// Determine whether the given feature supports adoption mode. -bool isFeatureAdoptable(Feature feature); + /// Get the feature corresponding to this "future" feature, if there is one. + static std::optional getUpcomingFeature(StringRef name); -/// Determine whether this feature should be included in the -/// module interface -bool includeInModuleInterface(Feature feature); + /// Get the feature corresponding to this "experimental" feature, if there is + /// one. + static std::optional getExperimentalFeature(StringRef name); + /// Get the major language version in which this feature was introduced, or + /// \c None if it does not have such a version. + std::optional getLanguageVersion() const; +}; + +#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \ + constexpr inline Feature Feature::FeatureName = \ + Feature::InnerKind::FeatureName; +#include "swift/Basic/Features.def" } #endif // SWIFT_BASIC_FEATURES_H diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 2f889e2fefc7b..c6b3de80207eb 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -121,40 +121,45 @@ LANGUAGE_FEATURE(FeatureName, SENumber, Description) #endif -// An upcoming feature that supports adoption mode. +// An upcoming feature that supports migration mode. // // If the feature is source-breaking and provides for a -// mechanical code migration, it should implement adoption mode. +// mechanical code migration, it should implement migration mode. // -// Adoption mode is a feature-oriented code migration mechanism: a mode +// Migration mode is a feature-oriented code migration mechanism: a mode // of operation that should produce compiler warnings with attached // fix-its that can be applied to preserve the behavior of the code once // the upcoming feature is enacted. // These warnings must belong to a diagnostic group named after the -// feature. Adoption mode itself *and* the fix-its it produces must be +// feature. Migration mode itself *and* the fix-its it produces must be // source and binary compatible with how the code is compiled when the // feature is disabled. -#ifndef ADOPTABLE_UPCOMING_FEATURE +#ifndef MIGRATABLE_UPCOMING_FEATURE #if defined(UPCOMING_FEATURE) - #define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \ + #define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \ UPCOMING_FEATURE(FeatureName, SENumber, Version) #else - #define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \ + #define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \ LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName) #endif #endif -// See `ADOPTABLE_UPCOMING_FEATURE`. -#ifndef ADOPTABLE_EXPERIMENTAL_FEATURE +// See `MIGRATABLE_UPCOMING_FEATURE`. +#ifndef MIGRATABLE_EXPERIMENTAL_FEATURE #if defined(EXPERIMENTAL_FEATURE) - #define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \ + #define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \ EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) #else - #define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \ + #define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \ LANGUAGE_FEATURE(FeatureName, 0, #FeatureName) #endif #endif +#ifndef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE + #define MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, Name) \ + OPTIONAL_LANGUAGE_FEATURE(FeatureName, SENumber, #Name) +#endif + #ifndef UPCOMING_FEATURE #define UPCOMING_FEATURE(FeatureName, SENumber, Version) \ LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName) @@ -254,6 +259,14 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute") LANGUAGE_FEATURE(ValueGenerics, 452, "Value generics feature (integer generics)") LANGUAGE_FEATURE(RawIdentifiers, 451, "Raw identifiers") LANGUAGE_FEATURE(SendableCompletionHandlers, 463, "Objective-C completion handler parameters are imported as @Sendable") +LANGUAGE_FEATURE(IsolatedConformances, 470, "Global-actor isolated conformances") +LANGUAGE_FEATURE(AsyncExecutionBehaviorAttributes, 0, "@concurrent and nonisolated(nonsending)") +LANGUAGE_FEATURE(GeneralizedIsSameMetaTypeBuiltin, 465, "Builtin.is_same_metatype with support for noncopyable/nonescapable types") +LANGUAGE_FEATURE(ValueGenericsNameLookup, 452, "Value generics appearing as static members for namelookup") +SUPPRESSIBLE_LANGUAGE_FEATURE(ABIAttributeSE0479, 479, "@abi attribute on functions, initializers, properties, and subscripts") +LANGUAGE_FEATURE(BuiltinSelect, 0, "Builtin.select") +LANGUAGE_FEATURE(AlwaysInheritActorContext, 472, "@_inheritActorContext(always)") +LANGUAGE_FEATURE(NonescapableAccessorOnTrivial, 0, "Support UnsafeMutablePointer.mutableSpan") // Swift 6 UPCOMING_FEATURE(ConciseMagicFile, 274, 6) @@ -273,15 +286,17 @@ UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6) UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6) // Swift 7 -ADOPTABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7) +MIGRATABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7) UPCOMING_FEATURE(InternalImportsByDefault, 409, 7) -UPCOMING_FEATURE(MemberImportVisibility, 444, 7) +MIGRATABLE_UPCOMING_FEATURE(MemberImportVisibility, 444, 7) +MIGRATABLE_UPCOMING_FEATURE(InferIsolatedConformances, 470, 7) +MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7) // Optional language features / modes /// Diagnose uses of language constructs and APIs that can violate memory /// safety. -OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety") +MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE(StrictMemorySafety, 458, "Strict memory safety") // Experimental features @@ -416,6 +431,10 @@ EXPERIMENTAL_FEATURE(StructLetDestructuring, true) /// Enable returning non-escapable types from functions. EXPERIMENTAL_FEATURE(LifetimeDependence, true) +/// Enable inout lifetime dependence - @lifetime(&arg) +EXPERIMENTAL_FEATURE(InoutLifetimeDependence, true) +EXPERIMENTAL_FEATURE(LifetimeDependenceMutableAccessors, true) + /// Enable the `@_staticExclusiveOnly` attribute. EXPERIMENTAL_FEATURE(StaticExclusiveOnly, true) @@ -454,7 +473,7 @@ EXPERIMENTAL_FEATURE(TrailingComma, false) // Import bounds safety and lifetime attributes from interop headers to // generate Swift wrappers with safe pointer types. -EXPERIMENTAL_FEATURE(SafeInteropWrappers, false) +EXPERIMENTAL_FEATURE(SafeInteropWrappers, true) /// Ignore resilience errors due to C++ types. EXPERIMENTAL_FEATURE(AssumeResilientCxxTypes, true) @@ -464,7 +483,7 @@ EXPERIMENTAL_FEATURE(ImportNonPublicCxxMembers, true) /// Synthesize static factory methods for C++ foreign reference types and import /// them as Swift initializers. -EXPERIMENTAL_FEATURE(CXXForeignReferenceTypeInitializers, true) +EXPERIMENTAL_FEATURE(SuppressCXXForeignReferenceTypeInitializers, true) // Isolated deinit SUPPRESSIBLE_LANGUAGE_FEATURE(IsolatedDeinit, 371, "isolated deinit") @@ -478,38 +497,18 @@ EXPERIMENTAL_FEATURE(CoroutineAccessorsUnwindOnCallerError, false) EXPERIMENTAL_FEATURE(AddressableParameters, true) SUPPRESSIBLE_EXPERIMENTAL_FEATURE(AddressableTypes, true) -/// Allow the @abi attribute. -SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ABIAttribute, true) - -/// Allow the @execution attribute. This is also connected to -/// AsyncCallerExecution feature. -SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExecutionAttribute, false) - -/// Functions with nonisolated isolation inherit their isolation from the -/// calling context. -ADOPTABLE_EXPERIMENTAL_FEATURE(AsyncCallerExecution, false) - /// Allow custom availability domains to be defined and referenced. -SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CustomAvailability, true) +EXPERIMENTAL_FEATURE(CustomAvailability, true) /// Allow public enumerations to be extensible by default /// regardless of whether the module they are declared in /// is resilient or not. EXPERIMENTAL_FEATURE(ExtensibleEnums, true) -/// Allow isolated conformances. -EXPERIMENTAL_FEATURE(IsolatedConformances, true) - -/// Infer conformance isolation on global-actor-conforming types. -EXPERIMENTAL_FEATURE(InferIsolatedConformances, true) - -/// Allow SwiftSettings -EXPERIMENTAL_FEATURE(SwiftSettings, false) - /// Syntax sugar features for concurrency. EXPERIMENTAL_FEATURE(ConcurrencySyntaxSugar, true) -/// Enable syntax sugar type '[3 x Int]' for Inline Array +/// Enable syntax sugar type '[3 of Int]' for Inline Array EXPERIMENTAL_FEATURE(InlineArrayTypeSugar, false) /// Allow declaration of compile-time values @@ -521,11 +520,26 @@ EXPERIMENTAL_FEATURE(ClosureBodyMacro, true) /// Allow declarations of Swift runtime symbols using @_silgen_name. EXPERIMENTAL_FEATURE(AllowRuntimeSymbolDeclarations, true) +/// Optimize copies of ObjectiveC blocks. +EXPERIMENTAL_FEATURE(CopyBlockOptimization, true) + +/// Allow use of `using` declaration that control default isolation +/// in a file scope. +EXPERIMENTAL_FEATURE(DefaultIsolationPerFile, false) + +/// Enable @_lifetime attribute +SUPPRESSIBLE_EXPERIMENTAL_FEATURE(Lifetimes, true) + +/// Disable @MainActor inference when the primary definition of a type conforms +/// to SendableMetatype (or Sendable). +EXPERIMENTAL_FEATURE(SendableProhibitsMainActorInference, true) + #undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE #undef EXPERIMENTAL_FEATURE #undef UPCOMING_FEATURE -#undef ADOPTABLE_UPCOMING_FEATURE -#undef ADOPTABLE_EXPERIMENTAL_FEATURE +#undef MIGRATABLE_UPCOMING_FEATURE +#undef MIGRATABLE_EXPERIMENTAL_FEATURE +#undef MIGRATABLE_OPTIONAL_LANGUAGE_FEATURE #undef BASELINE_LANGUAGE_FEATURE #undef OPTIONAL_LANGUAGE_FEATURE #undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE diff --git a/include/swift/Basic/FileTypes.def b/include/swift/Basic/FileTypes.def index ae18991130eca..4ca4c87520b20 100644 --- a/include/swift/Basic/FileTypes.def +++ b/include/swift/Basic/FileTypes.def @@ -78,8 +78,8 @@ TYPE("fine-module-trace", FineModuleTrace, "", "") // Complete dependency information for the given Swift files as JSON. TYPE("json-dependencies", JSONDependencies, "dependencies.json", "") -// Complete feature information for the given Swift compiler. -TYPE("json-features", JSONFeatures, "features.json", "") +// Complete supported argument information for the given Swift compiler. +TYPE("json-arguments", JSONArguments, "arguments.json", "") // Gathered compile-time-known value information for the given Swift input file as JSON. TYPE("const-values", ConstValues, "swiftconstvalues", "") diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 01e0162a9a546..a288bbcb0b625 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -45,6 +45,7 @@ namespace swift { struct DiagnosticBehavior; class DiagnosticEngine; + class FrontendOptions; /// Kind of implicit platform conditions. enum class PlatformConditionKind { @@ -269,9 +270,6 @@ namespace swift { /// Emit a remark on early exit in explicit interface build bool EnableSkipExplicitInterfaceModuleBuildRemarks = false; - /// Emit a remark when \c \@abi infers an attribute or modifier. - bool EnableABIInferenceRemarks = false; - /// /// Support for alternate usage modes /// @@ -342,7 +340,8 @@ namespace swift { std::optional FormalCxxInteropMode; void setCxxInteropFromArgs(llvm::opt::ArgList &Args, - swift::DiagnosticEngine &Diags); + swift::DiagnosticEngine &Diags, + const FrontendOptions &FrontendOpts); /// The C++ standard library used for the current build. This can differ /// from the default C++ stdlib on a particular platform when `-Xcc @@ -409,10 +408,6 @@ namespace swift { /// Specifies how strict concurrency checking will be. StrictConcurrency StrictConcurrencyLevel = StrictConcurrency::Minimal; - /// Specifies the name of the executor factory to use to create the - /// default executors for Swift Concurrency. - std::optional ExecutorFactory; - /// Enable experimental concurrency model. bool EnableExperimentalConcurrency = false; @@ -837,7 +832,7 @@ namespace swift { /// A wrapper around the feature state enumeration. struct FeatureState { - enum class Kind : uint8_t { Off, EnabledForAdoption, Enabled }; + enum class Kind : uint8_t { Off, EnabledForMigration, Enabled }; private: Feature feature; @@ -850,9 +845,9 @@ namespace swift { /// Returns whether the feature is enabled. bool isEnabled() const; - /// Returns whether the feature is enabled in adoption mode. Should only + /// Returns whether the feature is enabled in migration mode. Should only /// be called if the feature is known to support this mode. - bool isEnabledForAdoption() const; + bool isEnabledForMigration() const; operator Kind() const { return state; } }; @@ -879,15 +874,21 @@ namespace swift { FeatureState getFeatureState(Feature feature) const; /// Returns whether the given feature is enabled. - bool hasFeature(Feature feature) const; + /// + /// If allowMigration is set, also returns true when the feature has been + /// enabled for migration. + bool hasFeature(Feature feature, bool allowMigration = false) const; /// Returns whether a feature with the given name is enabled. Returns /// `false` if a feature by this name is not known. bool hasFeature(llvm::StringRef featureName) const; - /// Enables the given feature (enables in adoption mode if `forAdoption` is - /// `true`). - void enableFeature(Feature feature, bool forAdoption = false); + /// Returns whether the given feature is enabled for migration. + bool isMigratingToFeature(Feature feature) const; + + /// Enables the given feature (enables in migration mode if `forMigration` + /// is `true`). + void enableFeature(Feature feature, bool forMigration = false); /// Disables the given feature. void disableFeature(Feature feature); @@ -1101,12 +1102,6 @@ namespace swift { /// built and provided to the compiler invocation. bool DisableImplicitClangModules = false; - /// Enable ClangIncludeTree for explicit module builds scanning. - bool UseClangIncludeTree = false; - - /// Using ClangIncludeTreeRoot for compilation. - bool HasClangIncludeTreeRoot = false; - /// Whether the dependency scanner should construct all swift-frontend /// invocations directly from clang cc1 args. bool ClangImporterDirectCC1Scan = false; diff --git a/include/swift/Basic/PrettyStackTrace.h b/include/swift/Basic/PrettyStackTrace.h index a105d6a23b0ff..90bc97a5fd71e 100644 --- a/include/swift/Basic/PrettyStackTrace.h +++ b/include/swift/Basic/PrettyStackTrace.h @@ -50,6 +50,17 @@ class PrettyStackTraceSwiftVersion : public llvm::PrettyStackTraceEntry { void print(llvm::raw_ostream &OS) const override; }; +/// Aborts the program, printing a given message to a PrettyStackTrace frame +/// before exiting. +[[noreturn]] +void abortWithPrettyStackTraceMessage( + llvm::function_ref message); + +/// Aborts the program, printing a given message to a PrettyStackTrace frame +/// before exiting. +[[noreturn]] +void abortWithPrettyStackTraceMessage(llvm::StringRef message); + } // end namespace swift #endif // SWIFT_BASIC_PRETTYSTACKTRACE_H diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h index a42801d0d7400..4d53652a949e7 100644 --- a/include/swift/Basic/RelativePointer.h +++ b/include/swift/Basic/RelativePointer.h @@ -132,7 +132,10 @@ #ifndef SWIFT_BASIC_RELATIVEPOINTER_H #define SWIFT_BASIC_RELATIVEPOINTER_H +#include #include +#include +#include namespace swift { diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 60cbb2b093d21..99b8886e62fa8 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -13,6 +13,7 @@ #ifndef SWIFT_BASIC_SOURCEMANAGER_H #define SWIFT_BASIC_SOURCEMANAGER_H +#include "swift/AST/ClangNode.h" #include "swift/Basic/FileSystem.h" #include "swift/Basic/SourceLoc.h" #include "clang/Basic/FileManager.h" @@ -22,6 +23,7 @@ #include "llvm/Support/SourceMgr.h" #include #include +#include #include namespace swift { @@ -122,6 +124,10 @@ class GeneratedSourceInfo { /// Contains the ancestors of this source buffer, starting with the root source /// buffer and ending at this source buffer. mutable llvm::ArrayRef ancestors = llvm::ArrayRef(); + + /// Clang node where this buffer comes from. This should be set when this is + /// an 'AttributeFromClang'. + ClangNode clangNode = ClangNode(); }; /// This class manages and owns source buffers. diff --git a/stdlib/public/core/SwiftSettings.swift b/include/swift/Basic/SupportedFeatures.h similarity index 50% rename from stdlib/public/core/SwiftSettings.swift rename to include/swift/Basic/SupportedFeatures.h index 5db14ec144a0a..e078792b4dbc6 100644 --- a/stdlib/public/core/SwiftSettings.swift +++ b/include/swift/Basic/SupportedFeatures.h @@ -1,4 +1,4 @@ -//===--- SwiftSettings.swift ----------------------------------------------===// +//===--- SupportedFeatures.h - Supported Features Output --------*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -9,19 +9,20 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +// +// This file provides a high-level API for supported features info +// +//===----------------------------------------------------------------------===// -#if $Macros +#ifndef SWIFT_SUPPORTEDFEATURES_H +#define SWIFT_SUPPORTEDFEATURES_H -@available(SwiftStdlib 9999, *) -public struct SwiftSetting { - public init() { - fatalError("A SwiftSetting should never actually be constructed") - } -} +#include "swift/Basic/LLVM.h" -@available(SwiftStdlib 9999, *) -@freestanding(declaration) -public macro SwiftSettings(_ settings: SwiftSetting...) = - Builtin.SwiftSettingsMacro +namespace swift { +namespace features { +void printSupportedFeatures(llvm::raw_ostream &out); +} // namespace features +} // namespace swift #endif diff --git a/include/swift/Basic/Version.h b/include/swift/Basic/Version.h index 092a4e626e518..e43ce5c7b01e5 100644 --- a/include/swift/Basic/Version.h +++ b/include/swift/Basic/Version.h @@ -131,6 +131,13 @@ class Version { /// SWIFT_VERSION_MINOR. static Version getCurrentLanguageVersion(); + /// Returns a major version to represent the next future language mode. This + /// exists to make it easier to find and update clients when a new language + /// mode is added. + static constexpr unsigned getFutureMajorLanguageVersion() { + return 7; + } + // List of backward-compatibility versions that we permit passing as // -swift-version static std::array getValidEffectiveVersions() { @@ -164,11 +171,6 @@ std::string getSwiftFullVersion(Version effectiveLanguageVersion = /// this Swift was built. StringRef getSwiftRevision(); -/// Is the running compiler built with a version tag for distribution? -/// When true, \c version::getCurrentCompilerVersion returns a valid version -/// and \c getCurrentCompilerTag returns the version tuple in string format. -bool isCurrentCompilerTagged(); - /// Retrieves the distribution tag of the running compiler, if any. StringRef getCurrentCompilerTag(); diff --git a/include/swift/Bridging/ASTGen.h b/include/swift/Bridging/ASTGen.h index afef5603a99c7..b72b9a52d4814 100644 --- a/include/swift/Bridging/ASTGen.h +++ b/include/swift/Bridging/ASTGen.h @@ -35,6 +35,14 @@ void swift_ASTGen_addQueuedDiagnostic( const BridgedCharSourceRange *_Nullable highlightRanges, ptrdiff_t numHighlightRanges, BridgedArrayRef /*BridgedFixIt*/ fixIts); +void swift_ASTGen_renderSingleDiagnostic( + void *_Nonnull state, + BridgedStringRef text, + BridgedDiagnosticSeverity severity, + BridgedStringRef categoryName, + BridgedStringRef documentationPath, + ssize_t colorize, + BridgedStringRef *_Nonnull renderedString); void swift_ASTGen_renderQueuedDiagnostics( void *_Nonnull queued, ssize_t contextSize, ssize_t colorize, BridgedStringRef *_Nonnull renderedString); diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index de1091ba12cd5..90d8cddc5c8d9 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -64,6 +64,7 @@ namespace tooling { namespace dependencies { struct ModuleDeps; struct TranslationUnitDeps; + enum class ModuleOutputKind; using ModuleDepsGraph = std::vector; } } @@ -209,8 +210,7 @@ class ClangImporter final : public ClangModuleLoader { bool ignoreClangTarget = false); std::vector - getClangDepScanningInvocationArguments(ASTContext &ctx, - std::optional sourceFileName = std::nullopt); + getClangDepScanningInvocationArguments(ASTContext &ctx); static std::unique_ptr createClangInvocation(ClangImporter *importer, @@ -428,6 +428,16 @@ class ClangImporter final : public ClangModuleLoader { bool trackParsedSymbols = false, bool implicitImport = false); + /// Bind the bridging header content to the module. + /// + /// \param adapter The module that depends on the contents of this header. + /// \param diagLoc A location to attach any diagnostics to if import fails. + /// + /// \returns true if there was an error importing the header. + /// + /// \sa importBridgingHeader + bool bindBridgingHeader(ModuleDecl *adapter, SourceLoc diagLoc); + /// Returns the module that contains imports and declarations from all loaded /// Objective-C header files. /// @@ -462,11 +472,6 @@ class ClangImporter final : public ClangModuleLoader { /// Reads the original source file name from PCH. std::string getOriginalSourceFile(StringRef PCHFilename); - /// Add clang dependency file names. - /// - /// \param files The list of file to append dependencies to. - void addClangInvovcationDependencies(std::vector &files); - /// Makes a temporary replica of the ClangImporter's CompilerInstance, reads a /// module map into the replica and emits a PCM file for one of the modules it /// declares. Delegates to clang for everything except construction of the @@ -487,54 +492,32 @@ class ClangImporter final : public ClangModuleLoader { void verifyAllModules() override; using RemapPathCallback = llvm::function_ref; - llvm::SmallVector, 1> + using LookupModuleOutputCallback = + llvm::function_ref; + + static llvm::SmallVector, 1> bridgeClangModuleDependencies( + const ASTContext &ctx, clang::tooling::dependencies::DependencyScanningTool &clangScanningTool, clang::tooling::dependencies::ModuleDepsGraph &clangDependencies, StringRef moduleOutputPath, StringRef stableModuleOutputPath, + LookupModuleOutputCallback LookupModuleOutput, RemapPathCallback remapPath = nullptr); llvm::SmallVector, 1> getModuleDependencies(Identifier moduleName, StringRef moduleOutputPath, StringRef sdkModuleOutputPath, const llvm::DenseSet &alreadySeenClangModules, - clang::tooling::dependencies::DependencyScanningTool &clangScanningTool, + const std::vector &swiftModuleClangCC1CommandLineArgs, InterfaceSubContextDelegate &delegate, llvm::PrefixMapper *mapper, bool isTestableImport = false) override; - void recordBridgingHeaderOptions( - ModuleDependencyInfo &MDI, - const clang::tooling::dependencies::TranslationUnitDeps &deps); - - void getBridgingHeaderOptions( + static void getBridgingHeaderOptions( + const ASTContext &ctx, const clang::tooling::dependencies::TranslationUnitDeps &deps, std::vector &swiftArgs); - /// Query dependency information for header dependencies - /// of a binary Swift module. - /// - /// \param moduleID the name of the Swift module whose dependency - /// information will be augmented with information about the given - /// textual header inputs. - /// - /// \param headerPath the path to the header to be scanned. - /// - /// \param clangScanningTool The clang dependency scanner. - /// - /// \param cache The module dependencies cache to update, with information - /// about new Clang modules discovered along the way. - /// - /// \returns \c true if an error occurred, \c false otherwise - bool getHeaderDependencies( - ModuleDependencyID moduleID, std::optional headerPath, - std::optional sourceBuffer, - clang::tooling::dependencies::DependencyScanningTool &clangScanningTool, - ModuleDependenciesCache &cache, - ModuleDependencyIDSetVector &headerClangModuleDependencies, - std::vector &headerFileInputs, - std::vector &bridgingHeaderCommandLine, - std::optional &includeTreeID); - clang::TargetInfo &getModuleAvailabilityTarget() const override; clang::ASTContext &getClangASTContext() const override; clang::Preprocessor &getClangPreprocessor() const override; @@ -672,6 +655,8 @@ class ClangImporter final : public ClangModuleLoader { ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext, ClangInheritanceInfo inheritance) override; + ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) override; + /// Emits diagnostics for any declarations named name /// whose direct declaration context is a TU. void diagnoseTopLevelValue(const DeclName &name) override; @@ -773,6 +758,25 @@ getPrivateFileIDAttrs(const clang::CXXRecordDecl *decl); /// /// Returns false if \a decl was not imported by ClangImporter. bool declIsCxxOnly(const Decl *decl); + +/// Is this DeclContext an `enum` that represents a C++ namespace? +bool isClangNamespace(const DeclContext *dc); + +/// For some \a templatedClass that inherits from \a base, whether they are +/// derived from the same class template. +/// +/// This kind of circular inheritance can happen when a templated class inherits +/// from a specialization of itself, e.g.: +/// +/// template class C; +/// template <> class C { /* ... */ }; +/// template class C : C { /* ... */ }; +/// +/// Checking for this kind of scenario is necessary for avoiding infinite +/// recursion during symbolic imports (importSymbolicCXXDecls), where +/// specialized class templates are instead imported as unspecialized. +bool isSymbolicCircularBase(const clang::CXXRecordDecl *templatedClass, + const clang::RecordDecl *base); } // namespace importer struct ClangInvocationFileMapping { @@ -793,10 +797,19 @@ struct ClangInvocationFileMapping { /// `suppressDiagnostic` prevents us from emitting warning messages when we /// are unable to find headers. ClangInvocationFileMapping getClangInvocationFileMapping( - ASTContext &ctx, + const ASTContext &ctx, llvm::IntrusiveRefCntPtr vfs = nullptr, bool suppressDiagnostic = false); +/// Apply the given file mapping to the specified 'fileSystem', used +/// primarily to inject modulemaps on platforms with non-modularized +/// platform libraries. +ClangInvocationFileMapping applyClangInvocationMapping( + const ASTContext &ctx, + llvm::IntrusiveRefCntPtr baseVFS, + llvm::IntrusiveRefCntPtr &fileSystem, + bool suppressDiagnostics = false); + /// Information used to compute the access level of inherited C++ members. class ClangInheritanceInfo { /// The cumulative inheritance access specifier, that is used to compute the diff --git a/include/swift/ClangImporter/ClangImporterRequests.h b/include/swift/ClangImporter/ClangImporterRequests.h index e05db6edf2378..8a3a88acae1d3 100644 --- a/include/swift/ClangImporter/ClangImporterRequests.h +++ b/include/swift/ClangImporter/ClangImporterRequests.h @@ -576,10 +576,37 @@ class ClangTypeEscapability void simple_display(llvm::raw_ostream &out, EscapabilityLookupDescriptor desc); SourceLoc extractNearestSourceLoc(EscapabilityLookupDescriptor desc); +struct CxxDeclExplicitSafetyDescriptor final { + const clang::Decl *decl; + bool isClass; + + CxxDeclExplicitSafetyDescriptor(const clang::Decl *decl, bool isClass) + : decl(decl), isClass(isClass) {} + + friend llvm::hash_code + hash_value(const CxxDeclExplicitSafetyDescriptor &desc) { + return llvm::hash_combine(desc.decl, desc.isClass); + } + + friend bool operator==(const CxxDeclExplicitSafetyDescriptor &lhs, + const CxxDeclExplicitSafetyDescriptor &rhs) { + return lhs.decl == rhs.decl && lhs.isClass == rhs.isClass; + } + + friend bool operator!=(const CxxDeclExplicitSafetyDescriptor &lhs, + const CxxDeclExplicitSafetyDescriptor &rhs) { + return !(lhs == rhs); + } +}; + +void simple_display(llvm::raw_ostream &out, + CxxDeclExplicitSafetyDescriptor desc); +SourceLoc extractNearestSourceLoc(CxxDeclExplicitSafetyDescriptor desc); + /// Determine the safety of the given Clang declaration. class ClangDeclExplicitSafety : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -592,7 +619,8 @@ class ClangDeclExplicitSafety friend SimpleRequest; // Evaluation. - ExplicitSafety evaluate(Evaluator &evaluator, SafeUseOfCxxDeclDescriptor desc) const; + ExplicitSafety evaluate(Evaluator &evaluator, + CxxDeclExplicitSafetyDescriptor desc) const; }; #define SWIFT_TYPEID_ZONE ClangImporter diff --git a/include/swift/ClangImporter/ClangImporterTypeIDZone.def b/include/swift/ClangImporter/ClangImporterTypeIDZone.def index b4ea68a4053a2..2d81f93181ac3 100644 --- a/include/swift/ClangImporter/ClangImporterTypeIDZone.def +++ b/include/swift/ClangImporter/ClangImporterTypeIDZone.def @@ -46,5 +46,5 @@ SWIFT_REQUEST(ClangImporter, ClangTypeEscapability, CxxEscapability(EscapabilityLookupDescriptor), Cached, NoLocationInfo) SWIFT_REQUEST(ClangImporter, ClangDeclExplicitSafety, - ExplicitSafety(SafeUseOfCxxDeclDescriptor), Cached, + ExplicitSafety(CxxDeclExplicitSafetyDescriptor), Cached, NoLocationInfo) diff --git a/include/swift/Demangling/Demangle.h b/include/swift/Demangling/Demangle.h index 5e1d153b77545..95e3c21662bbc 100644 --- a/include/swift/Demangling/Demangle.h +++ b/include/swift/Demangling/Demangle.h @@ -19,9 +19,11 @@ #ifndef SWIFT_DEMANGLING_DEMANGLE_H #define SWIFT_DEMANGLING_DEMANGLE_H +#include "swift/Demangling/Demangle.h" #include "swift/Demangling/Errors.h" #include "swift/Demangling/ManglingFlavor.h" #include "swift/Demangling/NamespaceMacros.h" +#include "swift/Strings.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" @@ -99,6 +101,7 @@ struct DemangleOptions { class Node; using NodePointer = Node *; +class NodePrinter; enum class FunctionSigSpecializationParamKind : unsigned { // Option Flags use bits 0-5. This give us 6 bits implying 64 entries to @@ -465,16 +468,26 @@ class Context { /// The lifetime of the returned node tree ends with the lifetime of the /// context or with a call of clear(). NodePointer demangleTypeAsNode(llvm::StringRef MangledName); - + /// Demangle the given symbol and return the readable name. /// /// \param MangledName The mangled symbol string, which start a mangling /// prefix: _T, _T0, $S, _$S. /// /// \returns The demangled string. - std::string demangleSymbolAsString( - llvm::StringRef MangledName, - const DemangleOptions &Options = DemangleOptions()); + std::string + demangleSymbolAsString(llvm::StringRef MangledName, + const DemangleOptions &Options = DemangleOptions()); + + /// Demangle the given symbol and store the result in the `printer`. + /// + /// \param MangledName The mangled symbol string, which start a mangling + /// prefix: _T, _T0, $S, _$S. + /// \param Printer The NodePrinter that will be used to demangle the symbol. + /// + /// \returns The demangled string. + void demangleSymbolAsString(llvm::StringRef MangledName, + NodePrinter &Printer); /// Demangle the given type and return the readable name. /// @@ -533,6 +546,16 @@ std::string demangleSymbolAsString(const char *mangledName, size_t mangledNameLength, const DemangleOptions &options = DemangleOptions()); +/// Standalone utility function to demangle the given symbol as string. The +/// demangled string is stored in the `printer`. +/// +/// If performance is an issue when demangling multiple symbols, +/// \param mangledName The mangled name string pointer. +/// \param mangledNameLength The length of the mangledName string. +/// \param printer The NodePrinter that will be used to demangle the symbol. +void demangleSymbolAsString(const llvm::StringRef mangledName, + NodePrinter &printer); + /// Standalone utility function to demangle the given symbol as string. /// /// If performance is an issue when demangling multiple symbols, @@ -545,7 +568,7 @@ demangleSymbolAsString(const std::string &mangledName, return demangleSymbolAsString(mangledName.data(), mangledName.size(), options); } - + /// Standalone utility function to demangle the given symbol as string. /// /// If performance is an issue when demangling multiple symbols, @@ -626,7 +649,7 @@ struct [[nodiscard]] ManglingError { InvalidImplCoroutineKind, InvalidImplFunctionAttribute, InvalidImplParameterConvention, - InvalidImplParameterSending, + InvalidImplParameterAttr, InvalidMetatypeRepresentation, MultiByteRelatedEntity, BadValueWitnessKind, @@ -725,13 +748,19 @@ ManglingErrorOr mangleNodeAsObjcCString(NodePointer node, /// \endcode /// /// \param Root A pointer to a parse tree generated by the demangler. -/// \param Options An object encapsulating options to use to perform this demangling. +/// \param Options An object encapsulating options to use to perform this +/// demangling. /// /// \returns A string representing the demangled name. -/// std::string nodeToString(NodePointer Root, const DemangleOptions &Options = DemangleOptions()); +/// Transform the node structure to a string, which is stored in the `Printer`. +/// +/// \param Root A pointer to a parse tree generated by the demangler. +/// \param Printer A NodePrinter used to pretty print the demangled Node. +void nodeToString(NodePointer Root, NodePrinter &Printer); + /// Transforms a mangled key path accessor thunk helper /// into the identfier/subscript that would be used to invoke it in swift code. std::string keyPathSourceString(const char *MangledName, @@ -777,11 +806,14 @@ class DemanglerPrinter { llvm::StringRef getStringRef() const { return Stream; } + size_t getStreamLength() { return Stream.length(); } + /// Shrinks the buffer. void resetSize(size_t toPos) { assert(toPos <= Stream.size()); Stream.resize(toPos); } + private: std::string Stream; }; @@ -818,6 +850,159 @@ std::string mangledNameForTypeMetadataAccessor( llvm::StringRef moduleName, llvm::StringRef typeName, Node::Kind typeKind, Mangle::ManglingFlavor Flavor = Mangle::ManglingFlavor::Default); +/// Base class for printing a Swift demangled node tree. +/// +/// NodePrinter is used to convert demangled Swift symbol nodes into +/// human-readable string representations. It handles formatting, indentation, +/// and Swift-specific syntax. +/// +/// The virtual methods in this class are meant to be overriden to allow +/// external consumers (e.g lldb) to track the ranges of components of the +/// demangled name. +class NodePrinter { +protected: + DemanglerPrinter Printer; + DemangleOptions Options; + bool SpecializationPrefixPrinted = false; + bool isValid = true; + +public: + NodePrinter(DemangleOptions options) : Options(options) {} + + virtual ~NodePrinter() = default; + + void printRoot(NodePointer root) { + isValid = true; + print(root, 0); + } + + std::string takeString() { + if (isValid) + return std::move(Printer).str(); + return ""; + } + +protected: + static const unsigned MaxDepth = 768; + + size_t getStreamLength() { return Printer.getStreamLength(); } + + /// Called when the node tree in valid. + /// + /// The demangler already catches most error cases and mostly produces valid + /// node trees. But some cases are difficult to catch in the demangler and + /// instead the NodePrinter bails. + void setInvalid() { isValid = false; } + + void printChildren(Node::iterator begin, Node::iterator end, unsigned depth, + const char *sep = nullptr); + + void printChildren(NodePointer Node, unsigned depth, + const char *sep = nullptr); + + NodePointer getFirstChildOfKind(NodePointer Node, Node::Kind kind); + + void printBoundGenericNoSugar(NodePointer Node, unsigned depth); + + void printOptionalIndex(NodePointer node); + + static bool isSwiftModule(NodePointer node) { + return (node->getKind() == Node::Kind::Module && + node->getText() == STDLIB_NAME); + } + + static bool isIdentifier(NodePointer node, StringRef desired) { + return (node->getKind() == Node::Kind::Identifier && + node->getText() == desired); + } + + bool printContext(NodePointer Context); + + enum class SugarType { + None, + Optional, + ImplicitlyUnwrappedOptional, + Array, + Dictionary + }; + + enum class TypePrinting { NoType, WithColon, FunctionStyle }; + + /// Determine whether this is a "simple" type, from the type-simple + /// production. + bool isSimpleType(NodePointer Node); + + void printWithParens(NodePointer type, unsigned depth); + + SugarType findSugar(NodePointer Node); + + void printBoundGeneric(NodePointer Node, unsigned depth); + + NodePointer getChildIf(NodePointer Node, Node::Kind Kind); + + virtual void printFunctionParameters(NodePointer LabelList, + NodePointer ParameterType, + unsigned depth, bool showTypes); + + void printFunctionType(NodePointer LabelList, NodePointer node, + unsigned depth); + + void printImplFunctionType(NodePointer fn, unsigned depth); + + void printGenericSignature(NodePointer Node, unsigned depth); + + void printFunctionSigSpecializationParams(NodePointer Node, unsigned depth); + + void printSpecializationPrefix(NodePointer node, StringRef Description, + unsigned depth, + StringRef ParamPrefix = StringRef()); + + /// The main big print function. + NodePointer print(NodePointer Node, unsigned depth, + bool asPrefixContext = false); + + NodePointer printAbstractStorage(NodePointer Node, unsigned depth, + bool asPrefixContent, StringRef ExtraName); + + /// Utility function to print entities. + /// + /// \param Entity The entity node to print + /// \param depth The depth in the print() call tree. + /// \param asPrefixContext Should the entity printed as a context which as a + /// prefix to another entity, e.g. the Abc in Abc.def() + /// \param TypePr How should the type of the entity be printed, if at all. + /// E.g. with a colon for properties or as a function type. + /// \param hasName Does the entity has a name, e.g. a function in contrast to + /// an initializer. + /// \param ExtraName An extra name added to the entity name (if any). + /// \param ExtraIndex An extra index added to the entity name (if any), + /// e.g. closure #1 + /// \param OverwriteName If non-empty, print this name instead of the one + /// provided by the node. Gets printed even if hasName is false. + /// \return If a non-null node is returned it's a context which must be + /// printed in postfix-form after the entity: " in ". + NodePointer printEntity(NodePointer Entity, unsigned depth, + bool asPrefixContext, TypePrinting TypePr, + bool hasName, StringRef ExtraName = "", + int ExtraIndex = -1, StringRef OverwriteName = ""); + + virtual void printFunctionName(bool hasName, llvm::StringRef &OverwriteName, + llvm::StringRef &ExtraName, bool MultiWordName, + int &ExtraIndex, + swift::Demangle::NodePointer Entity, + unsigned int depth); + + /// Print the type of an entity. + /// + /// \param Entity The entity. + /// \param type The type of the entity. + /// \param genericFunctionTypeList If not null, the generic argument types + /// which is printed in the generic signature. + /// \param depth The depth in the print() call tree. + void printEntityType(NodePointer Entity, NodePointer type, + NodePointer genericFunctionTypeList, unsigned depth); +}; + SWIFT_END_INLINE_NAMESPACE } // end namespace Demangle } // end namespace swift diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index df41580cf465c..7d99dc6e94d62 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -75,6 +75,7 @@ NODE(DependentPseudogenericSignature) NODE(DependentProtocolConformanceRoot) NODE(DependentProtocolConformanceInherited) NODE(DependentProtocolConformanceAssociated) +NODE(DependentProtocolConformanceOpaque) CONTEXT_NODE(Destructor) CONTEXT_NODE(DidSet) NODE(Directness) @@ -137,6 +138,8 @@ NODE(ImplErasedIsolation) NODE(ImplSendingResult) NODE(ImplParameterResultDifferentiability) NODE(ImplParameterSending) +NODE(ImplParameterIsolated) +NODE(ImplParameterImplicitLeading) NODE(ImplFunctionAttribute) NODE(ImplFunctionConvention) NODE(ImplFunctionConventionName) @@ -399,6 +402,7 @@ NODE(AsyncRemoved) // Added in Swift 5.TBD NODE(ObjectiveCProtocolSymbolicReference) +NODE(OutlinedInitializeWithTakeNoValueWitness) NODE(OutlinedInitializeWithCopyNoValueWitness) NODE(OutlinedAssignWithTakeNoValueWitness) NODE(OutlinedAssignWithCopyNoValueWitness) diff --git a/include/swift/Demangling/Demangler.h b/include/swift/Demangling/Demangler.h index f634e5a86181b..8a4a6f2722086 100644 --- a/include/swift/Demangling/Demangler.h +++ b/include/swift/Demangling/Demangler.h @@ -570,6 +570,8 @@ class Demangler : public NodeFactory { NodePointer demangleImplParamConvention(Node::Kind ConvKind); NodePointer demangleImplResultConvention(Node::Kind ConvKind); NodePointer demangleImplParameterSending(); + NodePointer demangleImplParameterIsolated(); + NodePointer demangleImplParameterImplicitLeading(); NodePointer demangleImplParameterResultDifferentiability(); NodePointer demangleImplFunctionType(); NodePointer demangleClangType(); @@ -596,6 +598,7 @@ class Demangler : public NodeFactory { NodePointer demangleDependentProtocolConformanceInherited(); NodePointer popDependentAssociatedConformance(); NodePointer demangleDependentProtocolConformanceAssociated(); + NodePointer demangleDependentProtocolConformanceOpaque(); NodePointer demangleThunkOrSpecialization(); NodePointer demangleGenericSpecialization(Node::Kind SpecKind, NodePointer droppedArguments); diff --git a/include/swift/Demangling/TypeDecoder.h b/include/swift/Demangling/TypeDecoder.h index 724f6d01d019f..2cd6a0350dbed 100644 --- a/include/swift/Demangling/TypeDecoder.h +++ b/include/swift/Demangling/TypeDecoder.h @@ -118,6 +118,8 @@ enum class ImplParameterConvention { enum class ImplParameterInfoFlags : uint8_t { NotDifferentiable = 0x1, Sending = 0x2, + Isolated = 0x4, + ImplicitLeading = 0x8 }; using ImplParameterInfoOptions = OptionSet; @@ -192,6 +194,22 @@ class ImplFunctionParam { return result; } + static OptionsType getIsolated() { + OptionsType result; + + result |= ImplParameterInfoFlags::Isolated; + + return result; + } + + static OptionsType getImplicitLeading() { + OptionsType result; + + result |= ImplParameterInfoFlags::ImplicitLeading; + + return result; + } + ImplFunctionParam(BuiltType type, ImplParameterConvention convention, OptionsType options) : Type(type), Convention(convention), Options(options) {} @@ -1143,11 +1161,11 @@ class TypeDecoder { return MAKE_NODE_TYPE_ERROR0(child, "failed to decode function yields"); } else if (child->getKind() == NodeKind::ImplResult) { - if (decodeImplFunctionParam(child, depth + 1, results)) + if (decodeImplFunctionResult(child, depth + 1, results)) return MAKE_NODE_TYPE_ERROR0(child, "failed to decode function results"); } else if (child->getKind() == NodeKind::ImplErrorResult) { - if (decodeImplFunctionPart(child, depth + 1, errorResults)) + if (decodeImplFunctionResult(child, depth + 1, errorResults)) return MAKE_NODE_TYPE_ERROR0(child, "failed to decode function part"); } else { @@ -1638,40 +1656,70 @@ class TypeDecoder { } template - bool decodeImplFunctionPart(Demangle::NodePointer node, unsigned depth, - llvm::SmallVectorImpl &results) { + bool decodeImplFunctionParam(Demangle::NodePointer node, unsigned depth, + llvm::SmallVectorImpl &results) { if (depth > TypeDecoder::MaxDepth) return true; - if (node->getNumChildren() != 2) + // Children: `convention, attrs, type` + // attrs: `differentiability?, sending?, isolated?, implicit_leading?` + if (node->getNumChildren() < 2) return true; - - if (node->getChild(0)->getKind() != Node::Kind::ImplConvention || - node->getChild(1)->getKind() != Node::Kind::Type) + + auto *conventionNode = node->getChild(0); + auto *typeNode = node->getLastChild(); + if (conventionNode->getKind() != Node::Kind::ImplConvention || + typeNode->getKind() != Node::Kind::Type) return true; - StringRef conventionString = node->getChild(0)->getText(); - std::optional convention = - T::getConventionFromString(conventionString); + StringRef conventionString = conventionNode->getText(); + auto convention = T::getConventionFromString(conventionString); if (!convention) return true; - auto type = decodeMangledType(node->getChild(1), depth + 1); - if (type.isError()) + auto result = decodeMangledType(typeNode, depth + 1); + if (result.isError()) return true; - results.emplace_back(type.getType(), *convention); + typename T::OptionsType options; + for (unsigned i = 1; i < node->getNumChildren() - 1; ++i) { + auto child = node->getChild(i); + switch (child->getKind()) { + case Node::Kind::ImplParameterResultDifferentiability: { + auto optDiffOptions = + T::getDifferentiabilityFromString(child->getText()); + if (!optDiffOptions) + return true; + options |= *optDiffOptions; + break; + } + case Node::Kind::ImplParameterSending: + options |= T::getSending(); + break; + case Node::Kind::ImplParameterIsolated: + options |= T::getIsolated(); + break; + case Node::Kind::ImplParameterImplicitLeading: + options |= T::getImplicitLeading(); + break; + default: + return true; + } + } + + results.emplace_back(result.getType(), *convention, options); + return false; } template - bool decodeImplFunctionParam(Demangle::NodePointer node, unsigned depth, - llvm::SmallVectorImpl &results) { + bool decodeImplFunctionResult(Demangle::NodePointer node, unsigned depth, + llvm::SmallVectorImpl &results) { if (depth > TypeDecoder::MaxDepth) return true; - // Children: `convention, differentiability?, sending?, type` - if (node->getNumChildren() != 2 && node->getNumChildren() != 3 && - node->getNumChildren() != 4) + // Children: `convention, attrs, type` + // attrs: `differentiability?, sending?, isolated?, implicit_leading?` + if (node->getNumChildren() < 2) return true; auto *conventionNode = node->getChild(0); @@ -1689,23 +1737,24 @@ class TypeDecoder { return true; typename T::OptionsType options; - if (node->getNumChildren() == 3 || node->getNumChildren() == 4) { - auto diffKindNode = node->getChild(1); - if (diffKindNode->getKind() != - Node::Kind::ImplParameterResultDifferentiability) - return true; - auto optDiffOptions = - T::getDifferentiabilityFromString(diffKindNode->getText()); - if (!optDiffOptions) - return true; - options |= *optDiffOptions; - } - - if (node->getNumChildren() == 4) { - auto sendingKindNode = node->getChild(2); - if (sendingKindNode->getKind() != Node::Kind::ImplParameterSending) + for (unsigned i = 1; i < node->getNumChildren() - 1; ++i) { + auto child = node->getChild(i); + switch (child->getKind()) { + case Node::Kind::ImplParameterResultDifferentiability: { + auto optDiffOptions = + T::getDifferentiabilityFromString(child->getText()); + if (!optDiffOptions) + return true; + options |= *optDiffOptions; + break; + } + case Node::Kind::ImplParameterSending: + options |= T::getSending(); + break; + break; + default: return true; - options |= T::getSending(); + } } results.emplace_back(result.getType(), *convention, options); diff --git a/include/swift/DependencyScan/DependencyScanImpl.h b/include/swift/DependencyScan/DependencyScanImpl.h index c5507ea7c731d..ec70611550fcc 100644 --- a/include/swift/DependencyScan/DependencyScanImpl.h +++ b/include/swift/DependencyScan/DependencyScanImpl.h @@ -63,6 +63,9 @@ struct swiftscan_dependency_info_s { /// The list of link libraries for this module. swiftscan_link_library_set_t *link_libraries; + /// The list of source import infos. + swiftscan_import_info_set_t *imports; + /// Specific details of a particular kind of module. swiftscan_module_details_t details; }; @@ -74,10 +77,16 @@ struct swiftscan_link_library_info_s { bool forceLoad; }; +struct swiftscan_import_info_s { + swiftscan_string_ref_t import_identifier; + swiftscan_source_location_set_t *source_locations; + swiftscan_access_level_t access_level; +}; + struct swiftscan_macro_dependency_s { - swiftscan_string_ref_t moduleName; - swiftscan_string_ref_t libraryPath; - swiftscan_string_ref_t executablePath; + swiftscan_string_ref_t module_name; + swiftscan_string_ref_t library_path; + swiftscan_string_ref_t executable_path; }; /// Swift modules to be built from a module interface, may have a bridging @@ -102,6 +111,9 @@ typedef struct { /// Clang module dependencies swiftscan_string_set_t *swift_overlay_module_dependencies; + /// Directly-imported in source module dependencies + swiftscan_string_set_t *source_import_module_dependencies; + /// Options to the compile command required to build this module interface swiftscan_string_set_t *command_line; diff --git a/include/swift/DependencyScan/DependencyScanningTool.h b/include/swift/DependencyScan/DependencyScanningTool.h index 7129b1503c781..8aa380c83fc0e 100644 --- a/include/swift/DependencyScan/DependencyScanningTool.h +++ b/include/swift/DependencyScan/DependencyScanningTool.h @@ -40,6 +40,7 @@ class DependencyScanDiagnosticCollector : public DiagnosticConsumer { std::optional ImportLocation; }; std::vector Diagnostics; + llvm::sys::SmartMutex ScanningDiagnosticConsumerStateLock; void handleDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override; @@ -55,19 +56,6 @@ class DependencyScanDiagnosticCollector : public DiagnosticConsumer { } }; -/// Locking variant of the above diagnostic collector that guards accesses to -/// its state with a lock. -class LockingDependencyScanDiagnosticCollector - : public DependencyScanDiagnosticCollector { -private: - void addDiagnostic(SourceManager &SM, const DiagnosticInfo &Info) override; - llvm::sys::SmartMutex ScanningDiagnosticConsumerStateLock; - -public: - friend DependencyScanningTool; - LockingDependencyScanDiagnosticCollector() {} -}; - /// Given a set of arguments to a print-target-info frontend tool query, produce the /// JSON target info. llvm::ErrorOr getTargetInfo(ArrayRef Command, @@ -97,11 +85,6 @@ class DependencyScanningTool { llvm::ErrorOr getImports(ArrayRef Command, StringRef WorkingDirectory); - /// Query diagnostics consumed so far. - std::vector getDiagnostics(); - /// Discared the collection of diagnostics encountered so far. - void resetDiagnostics(); - /// Using the specified invocation command, instantiate a CompilerInstance /// that will be used for this scan. llvm::ErrorOr @@ -116,9 +99,6 @@ class DependencyScanningTool { /// Shared state mutual-exclusivity lock llvm::sys::SmartMutex DependencyScanningToolStateLock; - - /// A shared consumer that accumulates encountered diagnostics. - LockingDependencyScanDiagnosticCollector CDC; llvm::BumpPtrAllocator Alloc; llvm::StringSaver Saver; }; diff --git a/include/swift/DependencyScan/ModuleDependencyScanner.h b/include/swift/DependencyScan/ModuleDependencyScanner.h index 6065ccc6d4998..58b91d6253d19 100644 --- a/include/swift/DependencyScan/ModuleDependencyScanner.h +++ b/include/swift/DependencyScan/ModuleDependencyScanner.h @@ -50,6 +50,32 @@ class ModuleDependencyScanningWorker { StringRef sdkModuleOutputPath, llvm::PrefixMapper *prefixMapper, bool isTestableImport = false); + /// Query dependency information for header dependencies + /// of a binary Swift module. + /// + /// \param moduleID the name of the Swift module whose dependency + /// information will be augmented with information about the given + /// textual header inputs. + /// + /// \param headerPath the path to the header to be scanned. + /// + /// \param clangScanningTool The clang dependency scanner. + /// + /// \param cache The module dependencies cache to update, with information + /// about new Clang modules discovered along the way. + /// + /// \returns \c true if an error occurred, \c false otherwise + bool scanHeaderDependenciesOfSwiftModule( + const ASTContext &ctx, + ModuleDependencyID moduleID, std::optional headerPath, + std::optional sourceBuffer, + ModuleDependenciesCache &cache, + ModuleDependencyIDSetVector &headerClangModuleDependencies, + std::vector &headerFileInputs, + std::vector &bridgingHeaderCommandLine, + std::optional &includeTreeID); + + /// Store cache entry for include tree. llvm::Error createCacheKeyForEmbeddedHeader(std::string embeddedHeaderIncludeTree, @@ -65,7 +91,17 @@ class ModuleDependencyScanningWorker { clang::tooling::dependencies::DependencyScanningTool clangScanningTool; // Swift and Clang module loaders acting as scanners. std::unique_ptr swiftScannerModuleLoader; - std::unique_ptr clangScannerModuleLoader; + + // Base command line invocation for clang scanner queries (both module and header) + std::vector clangScanningBaseCommandLineArgs; + // Command line invocation for clang by-name module lookups + std::vector clangScanningModuleCommandLineArgs; + // Clang-specific (-Xcc) command-line flags to include on + // Swift module compilation commands + std::vector swiftModuleClangCC1CommandLineArgs; + // Working directory for clang module lookup queries + std::string clangScanningWorkingDirectoryPath; + // CAS instance. std::shared_ptr CAS; std::shared_ptr ActionCache; @@ -92,19 +128,6 @@ class ModuleDependencyScanner { performDependencyScan(ModuleDependencyID rootModuleID, ModuleDependenciesCache &cache); - /// Query the module dependency info for the Clang module with the given name. - /// Explicit by-name lookups are useful for batch mode scanning. - std::optional - getNamedClangModuleDependencyInfo(StringRef moduleName, - ModuleDependenciesCache &cache, - ModuleDependencyIDSetVector &discoveredClangModules); - - /// Query the module dependency info for the Swift module with the given name. - /// Explicit by-name lookups are useful for batch mode scanning. - std::optional - getNamedSwiftModuleDependencyInfo(StringRef moduleName, - ModuleDependenciesCache &cache); - /// How many filesystem lookups were performed by the scanner unsigned getNumLookups() { return NumLookups; } @@ -167,8 +190,26 @@ class ModuleDependencyScanner { template auto withDependencyScanningWorker(Function &&F, Args &&...ArgList); + /// Use the scanner's ASTContext to construct an `Identifier` + /// for a given module name. Identifier getModuleImportIdentifier(StringRef moduleName); + /// Diagnose scanner failure and attempt to reconstruct the dependency + /// path from the main module to the missing dependency. + void diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport, + const ModuleDependenciesCache &cache, + std::optional dependencyOf); + + /// Assuming the \c `moduleImport` failed to resolve, + /// iterate over all binary Swift module dependencies with serialized + /// search paths and attempt to diagnose if the failed-to-resolve module + /// can be found on any of them. Returns the path containing + /// the module, if one is found. + std::optional> + attemptToFindResolvingSerializedSearchPath( + const ScannerImportStatementInfo &moduleImport, + const ModuleDependenciesCache &cache, const SourceLoc &importLoc); + private: const CompilerInvocation &ScanCompilerInvocation; ASTContext &ScanASTContext; diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index fddb8bdd721dc..f48f0e4e1ec64 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -41,7 +41,7 @@ using llvm::BCVBR; const unsigned char MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE[] = {'I', 'M', 'D','C'}; const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR = 9; /// Increment this on every change. -const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 1; +const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 3; /// Various identifiers in this format will rely on having their strings mapped /// using this ID. @@ -67,6 +67,9 @@ using IsExportedImport = BCFixed<1>; using LineNumberField = BCFixed<32>; using ColumnNumberField = BCFixed<32>; +/// Access level of an import +using AccessLevelField = BCFixed<8>; + /// Arrays of various identifiers, distinguished for readability using IdentifierIDArryField = llvm::BCArray; using ModuleIDArryField = llvm::BCArray; @@ -78,9 +81,9 @@ using ModuleCacheKeyIDField = IdentifierIDField; using ImportArrayIDField = IdentifierIDField; using LinkLibrariesArrayIDField = IdentifierIDField; using MacroDependenciesArrayIDField = IdentifierIDField; +using SearchPathArrayIDField = IdentifierIDField; using FlagIDArrayIDField = IdentifierIDField; using DependencyIDArrayIDField = IdentifierIDField; -using AuxiliaryFilesArrayIDField = IdentifierIDField; using SourceLocationIDArrayIDField = IdentifierIDField; /// The ID of the top-level block containing the dependency graph @@ -102,6 +105,8 @@ enum { LINK_LIBRARY_ARRAY_NODE, MACRO_DEPENDENCY_NODE, MACRO_DEPENDENCY_ARRAY_NODE, + SEARCH_PATH_NODE, + SEARCH_PATH_ARRAY_NODE, IMPORT_STATEMENT_NODE, IMPORT_STATEMENT_ARRAY_NODE, OPTIONAL_IMPORT_STATEMENT_ARRAY_NODE, @@ -170,6 +175,17 @@ using MacroDependencyLayout = using MacroDependencyArrayLayout = BCRecordLayout; +// A record for a serialized search pathof a given dependency +// node (Swift binary module dependency only). +using SearchPathLayout = + BCRecordLayout; +using SearchPathArrayLayout = + BCRecordLayout; + // A record capturing information about a given 'import' statement // captured in a dependency node, including its source location. using ImportStatementLayout = @@ -179,7 +195,8 @@ using ImportStatementLayout = LineNumberField, // lineNumber ColumnNumberField, // columnNumber IsOptionalImport, // isOptional - IsExportedImport // isExported + IsExportedImport, // isExported + AccessLevelField // accessLevel >; using ImportStatementArrayLayout = BCRecordLayout; @@ -204,8 +221,7 @@ using ModuleInfoLayout = DependencyIDArrayIDField, // importedClangModules DependencyIDArrayIDField, // crossImportOverlayModules DependencyIDArrayIDField, // swiftOverlayDependencies - ModuleCacheKeyIDField, // moduleCacheKey - AuxiliaryFilesArrayIDField // auxiliaryFiles + ModuleCacheKeyIDField // moduleCacheKey >; using SwiftInterfaceModuleDetailsLayout = @@ -250,6 +266,7 @@ using SwiftBinaryModuleDetailsLayout = FileIDField, // definingInterfacePath IdentifierIDField, // headerModuleDependencies FileIDArrayIDField, // headerSourceFiles + SearchPathArrayIDField, // serializedSearchPaths IsFrameworkField, // isFramework IsStaticField, // isStatic IdentifierIDField, // moduleCacheKey diff --git a/include/swift/Frontend/CachingUtils.h b/include/swift/Frontend/CachingUtils.h index e478c22daf56c..d676ccbcaa4e6 100644 --- a/include/swift/Frontend/CachingUtils.h +++ b/include/swift/Frontend/CachingUtils.h @@ -70,9 +70,9 @@ std::unique_ptr loadCachedCompileResultFromCacheKey( llvm::StringRef Filename = ""); llvm::Expected> -createCASFileSystem(llvm::cas::ObjectStore &CAS, ArrayRef FSRoots, - ArrayRef IncludeTreeRoots, - ArrayRef IncludeTreeFileList); +createCASFileSystem(llvm::cas::ObjectStore &CAS, + const std::string &IncludeTreeRoot, + const std::string &IncludeTreeFileList); std::vector remapPathsFromCommandLine( ArrayRef Args, diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 55d984a53db8a..029e296ab5d38 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -176,7 +176,8 @@ class CompilerInvocation { } bool requiresCAS() const { - return CASOpts.EnableCaching || IRGenOpts.UseCASBackend; + return CASOpts.EnableCaching || IRGenOpts.UseCASBackend || + CASOpts.ImportModuleFromCAS; } void setClangModuleCachePath(StringRef Path) { diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 29a3f657f8fb0..339368386cc88 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -58,7 +58,7 @@ class FrontendOptions { std::string ImplicitObjCPCHPath; /// The map of aliases and real names of imported or referenced modules. - llvm::StringMap ModuleAliasMap; + llvm::StringMap ModuleAliasMap; /// The name of the module that the frontend is building. std::string ModuleName; @@ -201,7 +201,7 @@ class FrontendOptions { ScanDependencies, ///< Scan dependencies of Swift source files PrintVersion, ///< Print version information. - PrintFeature, ///< Print supported feature of this compiler + PrintArguments, ///< Print supported arguments of this compiler }; /// Indicates the action the user requested that the frontend perform. @@ -314,6 +314,10 @@ class FrontendOptions { /// exit. bool PrintTargetInfo = false; + /// Indicates that the frontend should print the supported features and then + /// exit. + bool PrintSupportedFeatures = false; + /// See the \ref SILOptions.EmitVerboseSIL flag. bool EmitVerboseSIL = false; diff --git a/include/swift/IDE/CodeCompletionResult.h b/include/swift/IDE/CodeCompletionResult.h index 83b067aaa3eae..9e247d1552191 100644 --- a/include/swift/IDE/CodeCompletionResult.h +++ b/include/swift/IDE/CodeCompletionResult.h @@ -190,6 +190,7 @@ enum class CodeCompletionKeywordKind : uint8_t { enum class CompletionKind : uint8_t { None, Import, + Using, UnresolvedMember, DotExpr, StmtOrExpr, diff --git a/include/swift/IDE/CompletionLookup.h b/include/swift/IDE/CompletionLookup.h index 29a2f911b1913..47b00f55eb135 100644 --- a/include/swift/IDE/CompletionLookup.h +++ b/include/swift/IDE/CompletionLookup.h @@ -325,6 +325,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addImportModuleNames(); + void addUsingSpecifiers(); + SemanticContextKind getSemanticContext(const Decl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo); @@ -458,6 +460,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { void addEnumElementRef(const EnumElementDecl *EED, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, bool HasTypeContext); + void addMacroCallArguments(const MacroDecl *MD, DeclVisibilityKind Reason, + bool forTrivialTrailingClosure = false); void addMacroExpansion(const MacroDecl *MD, DeclVisibilityKind Reason); void addKeyword( diff --git a/include/swift/IDE/ModuleInterfacePrinting.h b/include/swift/IDE/ModuleInterfacePrinting.h index fc51d5e287d83..178f7758944bc 100644 --- a/include/swift/IDE/ModuleInterfacePrinting.h +++ b/include/swift/IDE/ModuleInterfacePrinting.h @@ -38,11 +38,14 @@ namespace ide { /// Flags used when traversing a module for printing. enum class ModuleTraversal : unsigned { /// Visit modules even if their contents wouldn't be visible to name lookup. - VisitHidden = 0x01, + VisitHidden = 0x01, /// Visit submodules. VisitSubmodules = 0x02, /// Skip the declarations in a Swift overlay module. - SkipOverlay = 0x04, + SkipOverlay = 0x04, + /// Visit exported modules where their public module name matches the current + /// module. + VisitMatchingExported = 0x08, }; /// Options used to describe the traversal of a module for printing. diff --git a/include/swift/IDETool/CompileInstance.h b/include/swift/IDETool/CompileInstance.h index 4d904568517d1..5e6b7b7dc4f95 100644 --- a/include/swift/IDETool/CompileInstance.h +++ b/include/swift/IDETool/CompileInstance.h @@ -33,7 +33,6 @@ namespace ide { class CompileInstance { const std::string &SwiftExecutablePath; const std::string &RuntimeResourcePath; - const std::string &DiagnosticDocumentationPath; const std::shared_ptr Plugins; struct Options { @@ -70,12 +69,10 @@ class CompileInstance { public: CompileInstance(const std::string &SwiftExecutablePath, const std::string &RuntimeResourcePath, - const std::string &DiagnosticDocumentationPath, std::shared_ptr Plugins = nullptr) : SwiftExecutablePath(SwiftExecutablePath), - RuntimeResourcePath(RuntimeResourcePath), - DiagnosticDocumentationPath(DiagnosticDocumentationPath), - Plugins(Plugins), CachedCIInvalidated(false), CachedReuseCount(0) {} + RuntimeResourcePath(RuntimeResourcePath), Plugins(Plugins), + CachedCIInvalidated(false), CachedReuseCount(0) {} /// NOTE: \p Args is only used for checking the equaity of the invocation. /// Since this function assumes that it is already normalized, exact the same diff --git a/include/swift/IDETool/CompilerInvocation.h b/include/swift/IDETool/CompilerInvocation.h index 4b15f322f9933..c98f886d2e2d5 100644 --- a/include/swift/IDETool/CompilerInvocation.h +++ b/include/swift/IDETool/CompilerInvocation.h @@ -27,8 +27,7 @@ bool initCompilerInvocation( StringRef UnresolvedPrimaryFile, llvm::IntrusiveRefCntPtr FileSystem, const std::string &swiftExecutablePath, - const std::string &runtimeResourcePath, - const std::string &diagnosticDocumentationPath, time_t sessionTimestamp, + const std::string &runtimeResourcePath, time_t sessionTimestamp, std::string &Error); bool initInvocationByClangArguments(ArrayRef ArgList, diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 78ac19c0c8817..e9673973b5163 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -132,7 +132,7 @@ class LinkEntity { /// ValueDecl*, SILFunction*, or TypeBase*, depending on Kind. void *Pointer; - /// ProtocolConformance*, depending on Kind. + /// ProtocolConformance* or SILDifferentiabilityWitness*, depending on Kind. void *SecondaryPointer; /// A hand-rolled bitfield with the following layout: @@ -772,8 +772,8 @@ class LinkEntity { void setForDifferentiabilityWitness(Kind kind, const SILDifferentiabilityWitness *witness) { - Pointer = const_cast(static_cast(witness)); - SecondaryPointer = nullptr; + Pointer = nullptr; + SecondaryPointer = const_cast(static_cast(witness)); Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)); } @@ -1043,7 +1043,7 @@ class LinkEntity { } static LinkEntity forPropertyDescriptor(AbstractStorageDecl *decl) { - assert(decl->exportsPropertyDescriptor()); + assert((bool)decl->getPropertyDescriptorGenericSignature()); LinkEntity entity; entity.setForDecl(Kind::PropertyDescriptor, decl); return entity; @@ -1684,7 +1684,7 @@ class LinkEntity { SILDifferentiabilityWitness *getSILDifferentiabilityWitness() const { assert(getKind() == Kind::DifferentiabilityWitness); - return reinterpret_cast(Pointer); + return reinterpret_cast(SecondaryPointer); } const RootProtocolConformance *getRootProtocolConformance() const { diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 40e071a8facf5..e22aa30ee6605 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -244,6 +244,9 @@ def module_can_import_version: MultiArg<["-"], "module-can-import-version", 3>, MetaVarName<" ">, HelpText<"Specify canImport module and versions">; +def module_import_from_cas: Flag<["-"], "module-import-from-cas">, + HelpText<"Import modules from CAS instead of file system">; + def disable_cross_import_overlay_search: Flag<["-"], "disable-cross-import-overlay-search">, HelpText<"Disable searching for cross import overlay file">; @@ -1175,6 +1178,12 @@ def enable_arm64_corocc : Flag<["-"], "enable-arm64-corocc">, def disable_arm64_corocc : Flag<["-"], "disable-arm64-corocc">, HelpText<"Don't use swiftcorocc for yield_once_2 routines on arm64 variants.">; +def enable_callee_allocated_coro_abi : Flag<["-"], "enable-callee-allocated-coro-abi">, + HelpText<"Override per-platform settings and use yield_once_2.">; + +def disable_callee_allocated_coro_abi : Flag<["-"], "disable-callee-allocated-coro-abi">, + HelpText<"Override per-platform settings and don't use yield_once_2.">; + def enable_cond_fail_message_annotation : Flag<["-"], "enable-cond-fail-message-annotation">, HelpText<"Enable cond_fail message annotation. Will serialize a .o.yaml file per .o file.">; @@ -1448,9 +1457,6 @@ def bridging_header_pch_key : Separate<["-"], "bridging-header-pch-key">, def no_clang_include_tree: Flag<["-"], "no-clang-include-tree">, HelpText<"Do not use clang include tree, fallback to use CAS filesystem to build clang modules">; -def cas_fs: Separate<["-"], "cas-fs">, - HelpText<"Root CASID for CAS FileSystem">, MetaVarName<"">; - def clang_include_tree_root: Separate<["-"], "clang-include-tree-root">, HelpText<"Clang Include Tree CASID">, MetaVarName<"">; def clang_include_tree_filelist: Separate<["-"], "clang-include-tree-filelist">, diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 664572632985d..f71bdccf98c07 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -468,10 +468,6 @@ def remark_module_serialization : Flag<["-"], "Rmodule-serialization">, Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, HelpText<"Emit remarks about module serialization">; -def remark_abi_inference : Flag<["-"], "Rabi-inference">, - Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, - HelpText<"Emit a remark when an '@abi' attribute adds an attribute or modifier to the ABI declaration based on its presence in the API">; - def emit_tbd : Flag<["-"], "emit-tbd">, HelpText<"Emit a TBD file">, Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput]>; @@ -998,16 +994,6 @@ def default_isolation_EQ : Joined<["-"], "default-isolation=">, Flags<[FrontendOption]>, Alias; -def executor_factory : JoinedOrSeparate<["-"], "executor-factory">, - Flags<[FrontendOption]>, - HelpText<"Specify the factory to use to create the default executors for " - "Swift Concurrency. This must be a type conforming to the " - "'ExecutorFactory' protocol.">, - MetaVarName<"">; -def executor_factory_EQ : Joined<["-"], "executor-factory=">, - Flags<[FrontendOption]>, - Alias; - def enable_experimental_feature : Separate<["-"], "enable-experimental-feature">, Flags<[FrontendOption, ModuleInterfaceOption]>, @@ -1032,6 +1018,10 @@ def strict_memory_safety : Flag<["-"], "strict-memory-safety">, Flags<[FrontendOption, ModuleInterfaceOptionIgnorable, SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>, HelpText<"Enable strict memory safety checking">; +def strict_memory_safety_migrate : Flag<["-"], "strict-memory-safety:migrate">, + Flags<[FrontendOption, ModuleInterfaceOptionIgnorable, + SwiftAPIDigesterOption, SwiftSynthesizeInterfaceOption]>, + HelpText<"Enable migration to strict memory safety checking">; def Rpass_EQ : Joined<["-"], "Rpass=">, Flags<[FrontendOption]>, @@ -1544,6 +1534,10 @@ def print_target_info : Flag<["-"], "print-target-info">, Flags<[FrontendOption]>, HelpText<"Print target information for the given target , such as x86_64-apple-macos10.9">, MetaVarName<"">; +def print_supported_features : Flag<["-"], "print-supported-features">, + Flags<[FrontendOption]>, + HelpText<"Print information about features supported by the compiler">; + def target_cpu : Separate<["-"], "target-cpu">, Flags<[FrontendOption, ModuleInterfaceOption]>, HelpText<"Generate code for a particular CPU variant">; @@ -1660,9 +1654,13 @@ def scan_dependencies : Flag<["-"], "scan-dependencies">, HelpText<"Scan dependencies of the given Swift sources">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; -def emit_supported_features : Flag<["-"], "emit-supported-features">, - HelpText<"Emit a JSON file including all supported compiler features">, ModeOpt, +def emit_supported_arguments : Flag<["-"], "emit-supported-arguments">, + HelpText<"Emit a JSON file including all supported compiler arguments">, ModeOpt, Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>; +def emit_supported_features : Flag<["-"], "emit-supported-features">, + HelpText<"This is a compatibility alias for '-emit-supported-arguments'">, ModeOpt, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild, HelpHidden]>, + Alias; def enable_incremental_imports : Flag<["-"], "enable-incremental-imports">, @@ -1774,6 +1772,16 @@ def symbol_graph_minimum_access_level: Separate<["-"], "symbol-graph-minimum-acc HelpText<"Include symbols with this access level or more when emitting a symbol graph">, MetaVarName<"">; +def symbol_graph_allow_availability_platforms: Separate<["-"], "symbol-graph-allow-availability-platforms">, + Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput, HelpHidden]>, + HelpText<"Restrict availability metadata to the given platforms, e.g. 'macOS,Swift'">, + MetaVarName<"">; + +def symbol_graph_block_availability_platforms: Separate<["-"], "symbol-graph-block-availability-platforms">, + Flags<[FrontendOption, NoInteractiveOption, SupplementaryOutput, HelpHidden]>, + HelpText<"Remove the given platforms from symbol graph availability metadata, e.g. 'macOS,Swift'">, + MetaVarName<"">; + def pretty_print: Flag<["-"], "pretty-print">, Flags<[SwiftSymbolGraphExtractOption]>, HelpText<"Pretty-print the output JSON">; @@ -1788,6 +1796,16 @@ def omit_extension_block_symbols: Flag<["-"], "omit-extension-block-symbols">, NoInteractiveOption, SupplementaryOutput, HelpHidden]>, HelpText<"Directly associate members and conformances with the extended nominal when generating symbol graphs instead of emitting 'swift.extension' symbols for extensions to external types">; +def allow_availability_platforms: Separate<["-"], "allow-availability-platforms">, + Flags<[SwiftSymbolGraphExtractOption]>, + HelpText<"Restrict availability metadata to the given platforms, e.g. 'macOS,Swift'">, + MetaVarName<"">; + +def block_availability_platforms: Separate<["-"], "block-availability-platforms">, + Flags<[SwiftSymbolGraphExtractOption]>, + HelpText<"Remove the given platforms from symbol graph availability metadata, e.g. 'macOS,Swift'">, + MetaVarName<"">; + // swift-synthesize-interface-only options def include_submodules : Flag<["-"], "include-submodules">, Flags<[NoDriverOption, SwiftSynthesizeInterfaceOption]>, @@ -2263,6 +2281,10 @@ def load_resolved_plugin: "and exectuable path can be empty if not used">, MetaVarName<"##">; +def resolved_plugin_verification : Flag<["-"], "resolved-plugin-verification">, + Flags<[FrontendOption, NoDriverOption]>, + HelpText<"verify resolved plugins">; + def in_process_plugin_server_path : Separate<["-"], "in-process-plugin-server-path">, Flags<[FrontendOption, ArgumentIsPath]>, HelpText<"Path to dynamic library plugin server">; diff --git a/include/swift/Parse/IDEInspectionCallbacks.h b/include/swift/Parse/IDEInspectionCallbacks.h index 938083795af51..45c2634cbdd8e 100644 --- a/include/swift/Parse/IDEInspectionCallbacks.h +++ b/include/swift/Parse/IDEInspectionCallbacks.h @@ -39,7 +39,8 @@ enum class ParameterizedDeclAttributeKind { Available, FreestandingMacro, AttachedMacro, - StorageRestrictions + StorageRestrictions, + InheritActorContext }; /// A bit of a hack. When completing inside the '@storageRestrictions' @@ -254,6 +255,10 @@ class CodeCompletionCallbacks { virtual void completeImportDecl(ImportPath::Builder &Path) {}; + /// Complete the 'using' decl with supported specifiers. + virtual void + completeUsingDecl() {}; + /// Complete unresolved members after dot. virtual void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) {}; diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index f834cb84ce9b6..5f2515929e9e9 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1127,8 +1127,8 @@ class Parser { ); /// Parse the @lifetime attribute. - ParserResult parseLifetimeAttribute(SourceLoc AtLoc, - SourceLoc Loc); + ParserResult + parseLifetimeAttribute(StringRef attrName, SourceLoc atLoc, SourceLoc loc); /// Common utility to parse swift @lifetime decl attribute and SIL @lifetime /// type modifier. @@ -1158,7 +1158,8 @@ class Parser { bool isParameterSpecifier() { if (Tok.is(tok::kw_inout)) return true; - if (Context.LangOpts.hasFeature(Feature::LifetimeDependence) && + if ((Context.LangOpts.hasFeature(Feature::LifetimeDependence) || + Context.LangOpts.hasFeature(Feature::Lifetimes)) && isSILLifetimeDependenceToken()) return true; if (!canHaveParameterSpecifierContextualKeyword()) return false; @@ -1169,6 +1170,8 @@ class Parser { Tok.isContextualKeyword("isolated") || Tok.isContextualKeyword("_const")) return true; + if (isCallerIsolatedSpecifier()) + return true; if (Context.LangOpts.hasFeature(Feature::SendingArgsAndResults) && Tok.isContextualKeyword("sending")) return true; @@ -1187,6 +1190,12 @@ class Parser { (peekToken().isContextualKeyword("lifetime")); } + bool isCallerIsolatedSpecifier() { + if (!Tok.isContextualKeyword("nonisolated")) + return false; + return peekToken().isFollowingLParen(); + } + bool canHaveParameterSpecifierContextualKeyword() { // The parameter specifiers like `isolated`, `consuming`, `borrowing` are // also valid identifiers and could be the name of a type. Check whether @@ -1215,6 +1224,9 @@ class Parser { ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); + ParserResult parseDeclUsing(ParseDeclOptions Flags, + DeclAttributes &Attributes); + /// Parse an inheritance clause into a vector of InheritedEntry's. /// /// \param allowClassRequirement whether to permit parsing of 'class' @@ -1421,6 +1433,7 @@ class Parser { SourceLoc IsolatedLoc; SourceLoc ConstLoc; SourceLoc SendingLoc; + SourceLoc CallerIsolatedLoc; SmallVector Attributes; LifetimeEntry *lifetimeEntry = nullptr; @@ -1723,6 +1736,10 @@ class Parser { /// Returns true if a qualified declaration name base type can be parsed. bool canParseBaseTypeForQualifiedDeclName(); + /// Returns true if `nonisolated` contextual keyword could be parsed + /// as part of the type a the current location. + bool canParseNonisolatedAsTypeModifier(); + /// Returns true if the current token is '->' or effects specifiers followed /// by '->'. /// diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h index ba1a14a64ce30..df041a2270e40 100644 --- a/include/swift/Parse/Token.h +++ b/include/swift/Parse/Token.h @@ -196,8 +196,9 @@ class Token { #define CONTEXTUAL_SIMPLE_DECL_ATTR(KW, ...) CONTEXTUAL_CASE(KW) #include "swift/AST/DeclAttr.def" #undef CONTEXTUAL_CASE - .Case("macro", true) - .Default(false); + .Case("macro", true) + .Case("using", true) + .Default(false); } bool isContextualPunctuator(StringRef ContextPunc) const { diff --git a/include/swift/Remote/CMemoryReader.h b/include/swift/Remote/CMemoryReader.h index 3805b76c7cdad..6cb8b7f277a02 100644 --- a/include/swift/Remote/CMemoryReader.h +++ b/include/swift/Remote/CMemoryReader.h @@ -69,7 +69,7 @@ class CMemoryReader final : public MemoryReader { // that we're likely failing to strip a signed pointer when reading from it. bool hasSignatureBits(RemoteAddress address) { return false; - uint64_t addressData = address.getAddressData(); + uint64_t addressData = address.getRawAddress(); return addressData != (addressData & getPtrauthMask()); } @@ -89,13 +89,12 @@ class CMemoryReader final : public MemoryReader { RemoteAddress getSymbolAddress(const std::string &name) override { auto addressData = Impl.getSymbolAddress(Impl.reader_context, name.c_str(), name.size()); - return RemoteAddress(addressData); + return RemoteAddress(addressData, RemoteAddress::DefaultAddressSpace); } uint64_t getStringLength(RemoteAddress address) { assert(!hasSignatureBits(address)); - return Impl.getStringLength(Impl.reader_context, - address.getAddressData()); + return Impl.getStringLength(Impl.reader_context, address.getRawAddress()); } bool readString(RemoteAddress address, std::string &dest) override { @@ -120,7 +119,7 @@ class CMemoryReader final : public MemoryReader { ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override { assert(!hasSignatureBits(address)); void *FreeContext; - auto Ptr = Impl.readBytes(Impl.reader_context, address.getAddressData(), + auto Ptr = Impl.readBytes(Impl.reader_context, address.getRawAddress(), size, &FreeContext); auto Free = Impl.free; @@ -134,8 +133,7 @@ class CMemoryReader final : public MemoryReader { return ReadBytesResult(Ptr, freeLambda); } }; - -} -} +} // namespace remote +} // namespace swift #endif diff --git a/include/swift/Remote/Failure.h b/include/swift/Remote/Failure.h index 908e6357c0261..916c74892928d 100644 --- a/include/swift/Remote/Failure.h +++ b/include/swift/Remote/Failure.h @@ -288,7 +288,7 @@ class Failure { case ArgStorageKind::Address: { result += '0'; result += 'x'; - uint64_t address = Args[argIndex].Address.getAddressData(); + uint64_t address = Args[argIndex].Address.getRawAddress(); unsigned max = ((address >> 32) != 0 ? 16 : 8); for (unsigned i = 0; i != max; ++i) { result += "0123456789abcdef"[(address >> (max - 1 - i) * 4) & 0xF]; diff --git a/include/swift/Remote/InProcessMemoryReader.h b/include/swift/Remote/InProcessMemoryReader.h index 9fa78a28308d6..dbe7351317a62 100644 --- a/include/swift/Remote/InProcessMemoryReader.h +++ b/include/swift/Remote/InProcessMemoryReader.h @@ -105,8 +105,8 @@ class InProcessMemoryReader final : public MemoryReader { return ReadBytesResult(address.getLocalPointer(), [](const void *) {}); } }; - -} -} + +} // namespace remote +} // namespace swift #endif diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 1008650b43990..88d58d1ee6e60 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -57,13 +57,29 @@ class MemoryReader { /// /// Returns false if the operation failed. virtual bool readString(RemoteAddress address, std::string &dest) = 0; - + + /// Attempts to read a remote address from the given address in the remote + /// process. + /// + /// Returns false if the operator failed. + template + bool readRemoteAddress(RemoteAddress address, RemoteAddress &out) { + constexpr std::size_t integerSize = sizeof(IntegerType); + static_assert((integerSize == 4 || integerSize == 8) && + "Only 32 or 64 bit architectures are supported!"); + return readRemoteAddressImpl(address, out, integerSize); + } + /// Attempts to read an integer from the given address in the remote /// process. /// /// Returns false if the operation failed. template bool readInteger(RemoteAddress address, IntegerType *dest) { + static_assert(!std::is_same(), + "RemoteAddress cannot be read in directly, use " + "readRemoteAddress instead."); + return readBytes(address, reinterpret_cast(dest), sizeof(IntegerType)); } @@ -147,7 +163,15 @@ class MemoryReader { virtual RemoteAbsolutePointer resolvePointer(RemoteAddress address, uint64_t readValue) { // Default implementation returns the read value as is. - return RemoteAbsolutePointer("", readValue); + return RemoteAbsolutePointer( + RemoteAddress(readValue, address.getAddressSpace())); + } + + /// Performs the inverse operation of \ref resolvePointer. + /// A use-case for this is to turn file addresses into in-process addresses. + virtual std::optional + resolveRemoteAddress(RemoteAddress address) const { + return std::nullopt; } virtual std::optional @@ -159,7 +183,7 @@ class MemoryReader { virtual RemoteAbsolutePointer getSymbol(RemoteAddress address) { if (auto symbol = resolvePointerAsSymbol(address)) return *symbol; - return RemoteAbsolutePointer("", address.getAddressData()); + return RemoteAbsolutePointer(address); } /// Lookup a dynamic symbol name (ie dynamic loader binding) for the given @@ -254,9 +278,43 @@ class MemoryReader { } virtual ~MemoryReader() = default; + +protected: + /// Implementation detail of remoteRemoteAddress. This exists because + /// templated functions cannot be virtual. + /// + /// Attempts to read a remote address of a given size from the given address + /// in the remote process. + /// + /// Returns false if the operator failed. + virtual bool readRemoteAddressImpl(RemoteAddress address, RemoteAddress &out, + std::size_t integerSize) { + assert((integerSize == 4 || integerSize == 8) && + "Only 32 or 64 bit architectures are supported!"); + auto Buf = std::malloc(integerSize); + if (!Buf) + return false; + + // Free Buf when this function return. + ReadBytesResult Result( + Buf, [](const void *ptr) { free(const_cast(ptr)); }); + if (!readBytes(address, reinterpret_cast(Buf), integerSize)) + return false; + + if (integerSize == 4) + out = RemoteAddress(*reinterpret_cast(Buf), + address.getAddressSpace()); + else if (integerSize == 8) + out = RemoteAddress(*reinterpret_cast(Buf), + address.getAddressSpace()); + else + return false; + + return true; + } }; -} // end namespace reflection +} // end namespace remote } // end namespace swift #endif // SWIFT_REFLECTION_READER_H diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 262368e9f4a2b..d156ff67b3cf4 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -58,19 +58,17 @@ enum class MangledNameKind { template class RemoteRef { private: - uint64_t Address; + RemoteAddress Address; const T *LocalBuffer; public: - RemoteRef() - : Address(0), LocalBuffer(nullptr) {} + RemoteRef() : Address(), LocalBuffer(nullptr) {} /*implicit*/ RemoteRef(std::nullptr_t _) : RemoteRef() {} - template - explicit RemoteRef(StoredPointer address, const T *localBuffer) - : Address((uint64_t)address), LocalBuffer(localBuffer) {} + explicit RemoteRef(RemoteAddress address, const T *localBuffer) + : Address(address), LocalBuffer(localBuffer) {} // Some versions of clang++ sometimes fail to generate the // copy constructor for this type correctly - add a workaround @@ -83,9 +81,7 @@ class RemoteRef { return *this; } - uint64_t getAddressData() const { - return Address; - } + RemoteAddress getRemoteAddress() const { return Address; } const T *getLocalBuffer() const { return LocalBuffer; @@ -113,23 +109,23 @@ class RemoteRef { template RemoteRef getField(U &field) const { auto offset = (intptr_t)&field - (intptr_t)LocalBuffer; - return RemoteRef((uint64_t)(Address + (int64_t)offset), &field); + return RemoteRef((Address + (int64_t)offset), &field); } /// Resolve the remote address of a relative offset stored at the remote address. - uint64_t resolveRelativeAddressData() const { + RemoteAddress resolveRelativeAddressData() const { int32_t offset; memcpy(&offset, LocalBuffer, sizeof(int32_t)); if (offset == 0) - return 0; + return RemoteAddress(); return Address + (int64_t)offset; } - - template - uint64_t resolveRelativeFieldData(U &field) const { + + template + RemoteAddress resolveRelativeFieldData(U &field) const { return getField(field).resolveRelativeAddressData(); } - + RemoteRef atByteOffset(int64_t Offset) const { return RemoteRef(Address + Offset, (const T *)((intptr_t)LocalBuffer + Offset)); @@ -195,10 +191,10 @@ class MetadataReader { /// amounts of data when we encounter corrupt values for sizes/counts. static const uint64_t MaxMetadataSize = 1048576; // 1MB - /// The dense map info for a std::pair. + /// The dense map info for a std::pair. struct DenseMapInfoTypeCacheKey { - using Pair = std::pair; - using StoredPointerInfo = llvm::DenseMapInfo; + using Pair = std::pair; + using StoredPointerInfo = llvm::DenseMapInfo; static inline Pair getEmptyKey() { // Since bool doesn't have an empty key implementation, we only use the @@ -223,7 +219,7 @@ class MetadataReader { /// A cache of built types, keyed by the address of the type and whether the /// request ignored articial superclasses or not. - llvm::DenseMap, BuiltType, + llvm::DenseMap, BuiltType, DenseMapInfoTypeCacheKey> TypeCache; @@ -231,7 +227,7 @@ class MetadataReader { using OwnedMetadataRef = MemoryReader::ReadBytesResult; /// A cache of read type metadata, keyed by the address of the metadata. - llvm::DenseMap MetadataCache; + llvm::DenseMap MetadataCache; using ContextDescriptorRef = RemoteRef>; @@ -313,14 +309,14 @@ class MetadataReader { /// A cache of read nominal type descriptors, keyed by the address of the /// nominal type descriptor. - llvm::DenseMap + llvm::DenseMap ContextDescriptorCache; using OwnedProtocolDescriptorRef = std::unique_ptr, delete_with_free>; /// A cache of read extended existential shape metadata, keyed by the /// address of the shape metadata. - llvm::DenseMap ShapeCache; + llvm::DenseMap ShapeCache; enum class IsaEncodingKind { /// We haven't checked yet. @@ -359,8 +355,8 @@ class MetadataReader { StoredPointer IsaIndexShift; StoredPointer IsaMagicMask; StoredPointer IsaMagicValue; - StoredPointer IndexedClassesPointer; - StoredPointer IndexedClassesCountPointer; + RemoteAddress IndexedClassesPointer; + RemoteAddress IndexedClassesCountPointer; StoredPointer LastIndexedClassesCount = 0; enum class TaggedPointerEncodingKind { @@ -389,11 +385,11 @@ class MetadataReader { StoredPointer TaggedPointerMask; StoredPointer TaggedPointerSlotShift; StoredPointer TaggedPointerSlotMask; - StoredPointer TaggedPointerClasses; + RemoteAddress TaggedPointerClasses; StoredPointer TaggedPointerExtendedMask; StoredPointer TaggedPointerExtendedSlotShift; StoredPointer TaggedPointerExtendedSlotMask; - StoredPointer TaggedPointerExtendedClasses; + RemoteAddress TaggedPointerExtendedClasses; StoredPointer TaggedPointerObfuscator; Demangle::NodeFactory Factory; @@ -411,16 +407,21 @@ class MetadataReader { StoredPointer PtrAuthMask; - StoredPointer stripSignedPointer(StoredSignedPointer P) { - return P.SignedValue & PtrAuthMask; + RemoteAddress stripSignedPointer(RemoteAddress P) { + // Only pointers in the default address space are signed. + if (P.getAddressSpace() == RemoteAddress::DefaultAddressSpace) + return P & PtrAuthMask; + return P; + } + + RemoteAddress stripSignedPointer(StoredSignedPointer P) { + return RemoteAddress(P.SignedValue & PtrAuthMask, + RemoteAddress::DefaultAddressSpace); } RemoteAbsolutePointer stripSignedPointer(const RemoteAbsolutePointer &P) { - if (P.isResolved()) { - return RemoteAbsolutePointer("", - P.getResolvedAddress().getAddressData() & PtrAuthMask); - } - return P; + auto Stripped = stripSignedPointer(P.getResolvedAddress()); + return RemoteAbsolutePointer(P.getSymbol(), P.getOffset(), Stripped); } StoredPointer queryPtrAuthMask() { @@ -433,11 +434,9 @@ class MetadataReader { } template - MetadataReader(std::shared_ptr reader, T &&... args) - : Builder(std::forward(args)...), - Reader(std::move(reader)), - PtrAuthMask(queryPtrAuthMask()) { - } + MetadataReader(std::shared_ptr reader, T &&...args) + : Builder(std::forward(args)...), Reader(std::move(reader)), + PtrAuthMask(queryPtrAuthMask()) {} MetadataReader(const MetadataReader &other) = delete; MetadataReader &operator=(const MetadataReader &other) = delete; @@ -464,7 +463,7 @@ class MetadataReader { auto offsetInMangledName = (const char *)base - mangledName.getLocalBuffer(); auto remoteAddress = - mangledName.getAddressData() + offsetInMangledName + offset; + mangledName.getRemoteAddress() + offsetInMangledName + offset; RemoteAbsolutePointer resolved; if (directness == Directness::Indirect) { @@ -474,7 +473,7 @@ class MetadataReader { return nullptr; } } else { - resolved = Reader->getSymbol(RemoteAddress(remoteAddress)); + resolved = Reader->getSymbol(remoteAddress); } switch (kind) { @@ -488,9 +487,13 @@ class MetadataReader { if (useOpaqueTypeSymbolicReferences && context.isResolved() && context.getResolved()->getKind() == ContextDescriptorKind::OpaqueType){ + // FIXME: this loses the address space. This can be fixed by adding an + // opaque field in Node that can store the address space. This + // wouldn't degrade performance as Node's address is part of an union + // which is 16 bytes longs return dem.createNode( - Node::Kind::OpaqueTypeDescriptorSymbolicReference, - context.getResolved().getAddressData()); + Node::Kind::OpaqueTypeDescriptorSymbolicReference, + context.getResolved().getRemoteAddress().getRawAddress()); } return buildContextMangling(context, dem); @@ -504,43 +507,27 @@ class MetadataReader { // The symbolic reference points at a unique extended // existential type shape. return dem.createNode( - Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference, - resolved.getResolvedAddress().getAddressData()); + Node::Kind::UniqueExtendedExistentialTypeShapeSymbolicReference, + resolved.getResolvedAddress().getRawAddress()); } case Demangle::SymbolicReferenceKind::NonUniqueExtendedExistentialTypeShape: { // The symbolic reference points at a non-unique extended // existential type shape. + // FIXME: this loses the address space. return dem.createNode( - Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference, - resolved.getResolvedAddress().getAddressData()); + Node::Kind::NonUniqueExtendedExistentialTypeShapeSymbolicReference, + resolved.getResolvedAddress().getRawAddress()); } case Demangle::SymbolicReferenceKind::ObjectiveCProtocol: { // 'resolved' points to a struct of two relative addresses. // The second entry is a relative address to the mangled protocol // without symbolic references. - // lldb might return an unresolved remote absolute pointer from its - // resolvePointerAsSymbol implementation -- workaround this. - if (!resolved.isResolved()) { - auto remoteAddr = RemoteAddress(remoteAddress); - resolved = - RemoteAbsolutePointer("", remoteAddr.getAddressData()); - } - - auto addr = - resolved.getResolvedAddress().getAddressData() + sizeof(int32_t); + auto addr = resolved.getResolvedAddress() + sizeof(int32_t); int32_t offset; - Reader->readInteger(RemoteAddress(addr), &offset); + Reader->readInteger(addr, &offset); auto addrOfTypeRef = addr + offset; - resolved = Reader->getSymbol(RemoteAddress(addrOfTypeRef)); - - // lldb might return an unresolved remote absolute pointer from its - // resolvePointerAsSymbol implementation -- workaround this. - if (!resolved.isResolved()) { - auto remoteAddr = RemoteAddress(addrOfTypeRef); - resolved = - RemoteAbsolutePointer("", remoteAddr.getAddressData()); - } + resolved = Reader->getSymbol(addrOfTypeRef); // Dig out the protocol from the protocol list. auto protocolList = readMangledName(resolved.getResolvedAddress(), @@ -594,10 +581,9 @@ class MetadataReader { /// Demangle a mangled name from a potentially temporary std::string. The /// demangler may produce pointers into the string data, so this copies the /// string into the demangler's allocation first. - Demangle::NodePointer demangle(uint64_t remoteAddress, + Demangle::NodePointer demangle(RemoteAddress remoteAddress, const std::string &mangledName, - MangledNameKind kind, - Demangler &dem) { + MangledNameKind kind, Demangler &dem) { StringRef mangledNameCopy = dem.copyString(mangledName); return demangle(RemoteRef(remoteAddress, mangledNameCopy.data()), kind, dem); @@ -625,7 +611,7 @@ class MetadataReader { /// Given a remote pointer to metadata, attempt to discover its MetadataKind. std::optional - readKindFromMetadata(StoredPointer MetadataAddress) { + readKindFromMetadata(RemoteAddress MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta) return std::nullopt; @@ -634,11 +620,10 @@ class MetadataReader { } /// Given a remote pointer to class metadata, attempt to read its superclass. - StoredPointer - readSuperClassFromClassMetadata(StoredPointer MetadataAddress) { + RemoteAddress readSuperClassFromClassMetadata(RemoteAddress MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::Class) - return StoredPointer(); + return RemoteAddress(); auto classMeta = cast(meta); return stripSignedPointer(classMeta->Superclass); @@ -647,7 +632,7 @@ class MetadataReader { /// Given a remote pointer to class metadata, attempt to discover its class /// instance size and whether fields should use the resilient layout strategy. std::optional - readInstanceStartFromClassMetadata(StoredPointer MetadataAddress) { + readInstanceStartFromClassMetadata(RemoteAddress MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::Class) return std::nullopt; @@ -656,7 +641,7 @@ class MetadataReader { // The following algorithm only works on the non-fragile Apple runtime. // Grab the RO-data pointer. This part is not ABI. - StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress); + RemoteAddress roDataPtr = readObjCRODataPtr(MetadataAddress); if (!roDataPtr) return std::nullopt; @@ -664,7 +649,7 @@ class MetadataReader { auto address = roDataPtr + sizeof(uint32_t) * 1; unsigned start; - if (!Reader->readInteger(RemoteAddress(address), &start)) + if (!Reader->readInteger(address, &start)) return std::nullopt; return start; @@ -694,19 +679,19 @@ class MetadataReader { /// witness table. Note that it's not safe to access any non-mandatory /// members of the value witness table, like extra inhabitants or enum members. std::optional> - readValueWitnessTable(StoredPointer MetadataAddress) { + readValueWitnessTable(RemoteAddress MetadataAddress) { // The value witness table pointer is at offset -1 from the metadata // pointer, that is, the pointer-sized word immediately before the // pointer's referenced address. TargetValueWitnessTable VWT; auto ValueWitnessTableAddrAddr = MetadataAddress - sizeof(StoredPointer); StoredSignedPointer SignedValueWitnessTableAddr; - if (!Reader->readInteger(RemoteAddress(ValueWitnessTableAddrAddr), + if (!Reader->readInteger(ValueWitnessTableAddrAddr, &SignedValueWitnessTableAddr)) return std::nullopt; - auto ValueWitnessTableAddr = stripSignedPointer(SignedValueWitnessTableAddr); - if (!Reader->readBytes(RemoteAddress(ValueWitnessTableAddr), - (uint8_t *)&VWT, sizeof(VWT))) + auto ValueWitnessTableAddr = + stripSignedPointer(SignedValueWitnessTableAddr); + if (!Reader->readBytes(ValueWitnessTableAddr, (uint8_t *)&VWT, sizeof(VWT))) return std::nullopt; return VWT; } @@ -718,8 +703,7 @@ class MetadataReader { std::optional readMetadataAndValueErrorExistential(RemoteAddress ExistentialAddress) { // An pointer to an error existential is always an heap object. - auto MetadataAddress = - readMetadataFromInstance(ExistentialAddress.getAddressData()); + auto MetadataAddress = readMetadataFromInstance(ExistentialAddress); if (!MetadataAddress) return std::nullopt; @@ -748,18 +732,15 @@ class MetadataReader { if (isBridged) { // NSError instances don't need to be unwrapped. - return RemoteExistential(RemoteAddress(*MetadataAddress), - ExistentialAddress, - isBridged); + return RemoteExistential(*MetadataAddress, ExistentialAddress, isBridged); } // In addition to the isa pointer and two 32-bit reference counts, if the // error existential is layout-compatible with NSError, we also need to // skip over its three word-sized fields: the error code, the domain, // and userInfo. - StoredPointer InstanceMetadataAddressAddress = - ExistentialAddress.getAddressData() + - (isObjC ? 5 : 2) * sizeof(StoredPointer); + RemoteAddress InstanceMetadataAddressAddress = + ExistentialAddress + (isObjC ? 5 : 2) * sizeof(StoredPointer); // We need to get the instance's alignment info so we can get the exact // offset of the start of its data in the class. @@ -775,7 +756,7 @@ class MetadataReader { // Now we need to skip over the instance metadata pointer and instance's // conformance pointer for Swift.Error. - StoredPointer InstanceAddress = + RemoteAddress InstanceAddress = InstanceMetadataAddressAddress + 2 * sizeof(StoredPointer); // When built with Objective-C interop, the runtime also stores a conformance @@ -788,10 +769,8 @@ class MetadataReader { auto AlignmentMask = VWT->getAlignmentMask(); InstanceAddress = (InstanceAddress + AlignmentMask) & ~AlignmentMask; - return RemoteExistential( - RemoteAddress(*InstanceMetadataAddress), - RemoteAddress(InstanceAddress), - isBridged); + return RemoteExistential(*InstanceMetadataAddress, InstanceAddress, + isBridged); } /// Given a known-opaque existential, attempt to discover the pointer to its @@ -801,10 +780,11 @@ class MetadataReader { // OpaqueExistentialContainer is the layout of an opaque existential. // `Type` is the pointer to the metadata. TargetOpaqueExistentialContainer Container; - if (!Reader->readBytes(RemoteAddress(ExistentialAddress), - (uint8_t *)&Container, sizeof(Container))) + if (!Reader->readBytes(ExistentialAddress, (uint8_t *)&Container, + sizeof(Container))) return std::nullopt; - auto MetadataAddress = static_cast(Container.Type); + auto MetadataAddress = + RemoteAddress(Container.Type, ExistentialAddress.getAddressSpace()); auto Metadata = readMetadata(MetadataAddress); if (!Metadata) return std::nullopt; @@ -816,20 +796,19 @@ class MetadataReader { // Inline representation (the value fits in the existential container). // So, the value starts at the first word of the container. if (VWT->isValueInline()) - return RemoteExistential(RemoteAddress(MetadataAddress), - ExistentialAddress); + return RemoteExistential(MetadataAddress, ExistentialAddress); // Non-inline (box'ed) representation. // The first word of the container stores the address to the box. - StoredPointer BoxAddress; - if (!Reader->readInteger(ExistentialAddress, &BoxAddress)) + RemoteAddress BoxAddress; + if (!Reader->template readRemoteAddress(ExistentialAddress, + BoxAddress)) return std::nullopt; auto AlignmentMask = VWT->getAlignmentMask(); auto Offset = (sizeof(HeapObject) + AlignmentMask) & ~AlignmentMask; auto StartOfValue = BoxAddress + Offset; - return RemoteExistential(RemoteAddress(MetadataAddress), - RemoteAddress(StartOfValue)); + return RemoteExistential(MetadataAddress, StartOfValue); } /// Given a known-opaque existential, discover if its value is inlined in @@ -839,10 +818,12 @@ class MetadataReader { // OpaqueExistentialContainer is the layout of an opaque existential. // `Type` is the pointer to the metadata. TargetOpaqueExistentialContainer Container; - if (!Reader->readBytes(RemoteAddress(ExistentialAddress), - (uint8_t *)&Container, sizeof(Container))) + if (!Reader->readBytes(ExistentialAddress, (uint8_t *)&Container, + sizeof(Container))) return std::nullopt; - auto MetadataAddress = static_cast(Container.Type); + auto MetadataAddress = + RemoteAddress(Container.Type, ExistentialAddress.getAddressSpace()); + auto Metadata = readMetadata(MetadataAddress); if (!Metadata) return std::nullopt; @@ -855,11 +836,10 @@ class MetadataReader { } /// Read a protocol from a reference to said protocol. - template + template typename Resolver::Result readProtocol( - const TargetProtocolDescriptorRef &ProtocolAddress, - Demangler &dem, - Resolver resolver) { + const RemoteTargetProtocolDescriptorRef &ProtocolAddress, + Demangler &dem, Resolver resolver) { #if SWIFT_OBJC_INTEROP if (Runtime::ObjCInterop) { // Check whether we have an Objective-C protocol. @@ -895,8 +875,7 @@ class MetadataReader { #endif // Swift-native protocol. - auto Demangled = - readDemanglingForContextDescriptor( + auto Demangled = readDemanglingForContextDescriptor( stripSignedPointer({ProtocolAddress.getSwiftProtocol()}), dem); if (!Demangled) return resolver.failure(); @@ -906,10 +885,10 @@ class MetadataReader { /// Given a remote pointer to metadata, attempt to turn it into a type. BuiltType - readTypeFromMetadata(StoredPointer MetadataAddress, + readTypeFromMetadata(RemoteAddress MetadataAddress, bool skipArtificialSubclasses = false, int recursion_limit = defaultTypeRecursionLimit) { - std::pair TypeCacheKey(MetadataAddress, + std::pair TypeCacheKey(MetadataAddress, skipArtificialSubclasses); auto Cached = TypeCache.find(TypeCacheKey); if (Cached != TypeCache.end()) @@ -952,17 +931,20 @@ class MetadataReader { for (unsigned i = 0, n = tupleMeta->NumElements; i != n; ++i) { auto &element = tupleMeta->getElement(i); - if (auto elementType = - readTypeFromMetadata(element.Type, false, recursion_limit)) + auto elementTypeAddress = + RemoteAddress(element.Type, MetadataAddress.getAddressSpace()); + if (auto elementType = readTypeFromMetadata(elementTypeAddress, false, + recursion_limit)) elementTypes.push_back(elementType); else return BuiltType(); } // Read the labels string. + auto labelAddress = + RemoteAddress(tupleMeta->Labels, MetadataAddress.getAddressSpace()); std::string labelStr; - if (tupleMeta->Labels && - !Reader->readString(RemoteAddress(tupleMeta->Labels), labelStr)) + if (labelAddress && !Reader->readString(labelAddress, labelStr)) return BuiltType(); std::vector labels; @@ -988,8 +970,10 @@ class MetadataReader { std::vector> Parameters; for (unsigned i = 0, n = Function->getNumParameters(); i != n; ++i) { - auto ParamTypeRef = readTypeFromMetadata(Function->getParameter(i), - false, recursion_limit); + auto paramAddress = RemoteAddress(Function->getParameter(i), + MetadataAddress.getAddressSpace()); + auto ParamTypeRef = + readTypeFromMetadata(paramAddress, false, recursion_limit); if (!ParamTypeRef) return BuiltType(); @@ -999,8 +983,10 @@ class MetadataReader { Parameters.push_back(std::move(Param)); } + auto resultTypeAddress = RemoteAddress(Function->ResultType, + MetadataAddress.getAddressSpace()); auto Result = - readTypeFromMetadata(Function->ResultType, false, recursion_limit); + readTypeFromMetadata(resultTypeAddress, false, recursion_limit); if (!Result) return BuiltType(); @@ -1012,8 +998,10 @@ class MetadataReader { BuiltType globalActor = BuiltType(); if (Function->hasGlobalActor()) { - globalActor = readTypeFromMetadata(Function->getGlobalActor(), false, - recursion_limit); + auto globalActorAddress = RemoteAddress( + Function->getGlobalActor(), MetadataAddress.getAddressSpace()); + globalActor = + readTypeFromMetadata(globalActorAddress, false, recursion_limit); if (!globalActor) return BuiltType(); } @@ -1035,8 +1023,10 @@ class MetadataReader { BuiltType thrownError = BuiltType(); if (Function->hasThrownError()) { - thrownError = readTypeFromMetadata(Function->getThrownError(), false, - recursion_limit); + auto thrownErrorAddress = RemoteAddress( + Function->getThrownError(), MetadataAddress.getAddressSpace()); + thrownError = + readTypeFromMetadata(thrownErrorAddress, false, recursion_limit); if (!thrownError) return BuiltType(); } @@ -1055,9 +1045,12 @@ class MetadataReader { BuiltType SuperclassType = BuiltType(); if (Exist->Flags.hasSuperclassConstraint()) { + auto superclassContraintAddress = + RemoteAddress(Exist->getSuperclassConstraint(), + MetadataAddress.getAddressSpace()); // The superclass is stored after the list of protocols. - SuperclassType = readTypeFromMetadata(Exist->getSuperclassConstraint(), - false, recursion_limit); + SuperclassType = readTypeFromMetadata(superclassContraintAddress, false, + recursion_limit); if (!SuperclassType) return BuiltType(); HasExplicitAnyObject = true; @@ -1087,7 +1080,10 @@ class MetadataReader { Demangler dem; std::vector Protocols; for (auto ProtocolAddress : Exist->getProtocols()) { - if (auto Protocol = readProtocol(ProtocolAddress, dem, resolver)) + auto ProtocolRef = RemoteTargetProtocolDescriptorRef( + RemoteAddress(ProtocolAddress.getRawData(), + MetadataAddress.getAddressSpace())); + if (auto Protocol = readProtocol(ProtocolRef, dem, resolver)) Protocols.push_back(Protocol); else return BuiltType(); @@ -1101,7 +1097,7 @@ class MetadataReader { auto Exist = cast>(Meta); // Read the shape for this existential. - StoredPointer shapeAddress = stripSignedPointer(Exist->Shape); + RemoteAddress shapeAddress = stripSignedPointer(Exist->Shape); ShapeRef Shape = readShape(shapeAddress); if (!Shape) return BuiltType(); @@ -1113,7 +1109,10 @@ class MetadataReader { std::vector builtArgs; for (unsigned i = 0; i < shapeArgumentCount; ++i) { auto remoteArg = Exist->getGeneralizationArguments()[i]; - auto builtArg = readTypeFromMetadata(remoteArg, false, recursion_limit); + auto remoteArgAddress = + RemoteAddress(remoteArg, MetadataAddress.getAddressSpace()); + auto builtArg = + readTypeFromMetadata(remoteArgAddress, false, recursion_limit); if (!builtArg) return BuiltType(); builtArgs.push_back(builtArg); @@ -1123,8 +1122,8 @@ class MetadataReader { Demangler dem; auto mangledExistentialAddr = resolveRelativeField(Shape, Shape->ExistentialType); - auto node = readMangledName(RemoteAddress(mangledExistentialAddr), - MangledNameKind::Type, dem); + auto node = + readMangledName(mangledExistentialAddr, MangledNameKind::Type, dem); if (!node) return BuiltType(); @@ -1158,8 +1157,8 @@ class MetadataReader { auto mangledContextName = Shape->getTypeExpression(); auto mangledNameAddress = resolveRelativeField(Shape, mangledContextName->name); - auto node = readMangledName(RemoteAddress(mangledNameAddress), - MangledNameKind::Type, dem); + auto node = + readMangledName(mangledNameAddress, MangledNameKind::Type, dem); if (!node) return BuiltType(); @@ -1178,8 +1177,10 @@ class MetadataReader { case MetadataKind::Metatype: { auto Metatype = cast>(Meta); + auto InstanceTypeAddress = RemoteAddress( + Metatype->InstanceType, MetadataAddress.getAddressSpace()); auto Instance = - readTypeFromMetadata(Metatype->InstanceType, false, recursion_limit); + readTypeFromMetadata(InstanceTypeAddress, false, recursion_limit); if (!Instance) return BuiltType(); auto BuiltMetatype = Builder.createMetatypeType(Instance); TypeCache[TypeCacheKey] = BuiltMetatype; @@ -1187,7 +1188,8 @@ class MetadataReader { } case MetadataKind::ObjCClassWrapper: { auto objcWrapper = cast>(Meta); - auto classAddress = objcWrapper->Class; + auto classAddress = + RemoteAddress(objcWrapper->Class, MetadataAddress.getAddressSpace()); std::string className; if (!readObjCClassName(classAddress, className)) @@ -1199,8 +1201,10 @@ class MetadataReader { } case MetadataKind::ExistentialMetatype: { auto Exist = cast>(Meta); + auto classAddress = + RemoteAddress(Exist->InstanceType, MetadataAddress.getAddressSpace()); auto Instance = - readTypeFromMetadata(Exist->InstanceType, false, recursion_limit); + readTypeFromMetadata(classAddress, false, recursion_limit); if (!Instance) return BuiltType(); auto BuiltExist = Builder.createExistentialMetatypeType(Instance); TypeCache[TypeCacheKey] = BuiltExist; @@ -1281,8 +1285,13 @@ class MetadataReader { switch (req.Flags.getKind()) { case GenericRequirementKind::SameType: { Demangler rdem; + // FIXME: This should not work since the mangled name pointer is on the + // local process. + auto mangledNameAddress = + RemoteAddress((uint64_t)req.getMangledTypeName().data(), + RemoteAddress::DefaultAddressSpace); auto demangledConstraint = - demangle(RemoteRef(req.getMangledTypeName().data(), + demangle(RemoteRef(mangledNameAddress, req.getMangledTypeName().data()), MangledNameKind::Type, rdem); auto constraintType = decodeMangledType(demangledConstraint); @@ -1323,7 +1332,9 @@ class MetadataReader { Demangler dem; auto protocolAddress = resolveRelativeIndirectProtocol(contextRef, req.Protocol); - auto protocol = readProtocol(protocolAddress, dem, resolver); + auto protocolRef = + RemoteTargetProtocolDescriptorRef(protocolAddress); + auto protocol = readProtocol(protocolRef, dem, resolver); if (!protocol) { return TypeLookupError("Failed to read protocol type in conformance " "requirement of runtime generic signature."); @@ -1335,8 +1346,13 @@ class MetadataReader { } case GenericRequirementKind::BaseClass: { Demangler rdem; + // FIXME: This should not work since the mangled name pointer is on the + // local process. + auto mangledNameAddress = + RemoteAddress((uint64_t)req.getMangledTypeName().data(), + RemoteAddress::DefaultAddressSpace); auto demangledConstraint = - demangle(RemoteRef(req.getMangledTypeName().data(), + demangle(RemoteRef(mangledNameAddress, req.getMangledTypeName().data()), MangledNameKind::Type, rdem); auto constraintType = decodeMangledType(demangledConstraint); @@ -1379,21 +1395,18 @@ class MetadataReader { ParentContextDescriptorRef readContextDescriptor(const RemoteAbsolutePointer &address) { // Map an unresolved pointer to an unresolved context ref. - if (!address.isResolved()) { + if (!address.getSymbol().empty()) { // We can only handle references to a symbol without an offset currently. - if (address.getOffset() != 0) { - return ParentContextDescriptorRef(); - } - return ParentContextDescriptorRef(address.getSymbol()); + if (address.getOffset() == 0) + return ParentContextDescriptorRef(address.getSymbol()); } - + return ParentContextDescriptorRef( - readContextDescriptor(address.getResolvedAddress().getAddressData())); + readContextDescriptor(address.getResolvedAddress())); } - ShapeRef - readShape(StoredPointer address) { - if (address == 0) + ShapeRef readShape(RemoteAddress address) { + if (!address) return nullptr; auto cached = ShapeCache.find(address); @@ -1403,8 +1416,7 @@ class MetadataReader { cached->second.get())); ExtendedExistentialTypeShapeFlags flags; - if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags, - sizeof(flags))) + if (!Reader->readBytes(address, (uint8_t *)&flags, sizeof(flags))) return nullptr; // Read the size of the requirement signature. @@ -1414,8 +1426,7 @@ class MetadataReader { GenericContextDescriptorHeader header; auto headerAddr = address + sizeof(flags); - if (!Reader->readBytes(RemoteAddress(headerAddr), - (uint8_t*)&header, sizeof(header))) + if (!Reader->readBytes(headerAddr, (uint8_t *)&header, sizeof(header))) return nullptr; reqSigGenericSize = reqSigGenericSize @@ -1433,7 +1444,7 @@ class MetadataReader { reqSigGenericSize; if (size > MaxMetadataSize) return nullptr; - auto readResult = Reader->readBytes(RemoteAddress(address), size); + auto readResult = Reader->readBytes(address, size); if (!readResult) return nullptr; @@ -1447,22 +1458,21 @@ class MetadataReader { } /// Given the address of a context descriptor, attempt to read it. - ContextDescriptorRef - readContextDescriptor(StoredPointer address) { - if (address == 0) + ContextDescriptorRef readContextDescriptor(RemoteAddress remoteAddress) { + if (!remoteAddress) return nullptr; - auto remoteAddress = RemoteAddress(address); auto ptr = Reader->readBytes(remoteAddress, sizeof(TargetContextDescriptor)); if (!ptr) return nullptr; - auto cached = ContextDescriptorCache.find(address); + auto cached = ContextDescriptorCache.find(remoteAddress); if (cached != ContextDescriptorCache.end()) return ContextDescriptorRef( - address, reinterpret_cast *>( - cached->second.get())); + remoteAddress, + reinterpret_cast *>( + cached->second.get())); bool success = false; switch ( @@ -1512,8 +1522,9 @@ class MetadataReader { auto *descriptor = reinterpret_cast *>(ptr.get()); - ContextDescriptorCache.insert(std::make_pair(address, std::move(ptr))); - return ContextDescriptorRef(address, descriptor); + ContextDescriptorCache.insert( + std::make_pair(remoteAddress, std::move(ptr))); + return ContextDescriptorRef(remoteAddress, descriptor); } template @@ -1626,19 +1637,17 @@ class MetadataReader { /// Read a context descriptor from the given address and build a mangling /// tree representing it. Demangle::NodePointer - readDemanglingForContextDescriptor(StoredPointer contextAddress, + readDemanglingForContextDescriptor(RemoteAddress contextAddress, Demangler &Dem) { auto context = readContextDescriptor(contextAddress); if (!context) return nullptr; return buildContextMangling(context, Dem); } - + /// Read the mangled underlying type from an opaque type descriptor. - Demangle::NodePointer - readUnderlyingTypeManglingForOpaqueTypeDescriptor(StoredPointer contextAddr, - unsigned ordinal, - Demangler &Dem) { + Demangle::NodePointer readUnderlyingTypeManglingForOpaqueTypeDescriptor( + RemoteAddress contextAddr, unsigned ordinal, Demangler &Dem) { auto context = readContextDescriptor(contextAddr); if (!context) return nullptr; @@ -1654,13 +1663,12 @@ class MetadataReader { auto nameAddr = resolveRelativeField(context, opaqueType->getUnderlyingTypeArgumentMangledName(ordinal)); - - return readMangledName(RemoteAddress(nameAddr), - MangledNameKind::Type, Dem); + + return readMangledName(nameAddr, MangledNameKind::Type, Dem); } TypeLookupErrorOr - readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr, + readUnderlyingTypeForOpaqueTypeDescriptor(RemoteAddress contextAddr, unsigned ordinal) { Demangle::Demangler Dem; auto node = readUnderlyingTypeManglingForOpaqueTypeDescriptor(contextAddr, @@ -1670,31 +1678,33 @@ class MetadataReader { return decodeMangledType(node); } - bool isTaggedPointer(StoredPointer objectAddress) { + bool isTaggedPointer(RemoteAddress objectAddress) { if (getTaggedPointerEncoding() != TaggedPointerEncodingKind::Extended) return false; - - return (objectAddress ^ TaggedPointerObfuscator) & TaggedPointerMask; + + return (bool)((objectAddress ^ TaggedPointerObfuscator) & + TaggedPointerMask); } /// Read the isa pointer of an Object-C tagged pointer value. - std::optional - readMetadataFromTaggedPointer(StoredPointer objectAddress) { + std::optional + readMetadataFromTaggedPointer(RemoteAddress objectAddress) { auto readArrayElement = - [&](StoredPointer base, - StoredPointer tag) -> std::optional { - StoredPointer addr = base + tag * sizeof(StoredPointer); - StoredPointer isa; - if (!Reader->readInteger(RemoteAddress(addr), &isa)) + [&](RemoteAddress base, + StoredPointer tag) -> std::optional { + RemoteAddress addr = base + tag * sizeof(StoredPointer); + RemoteAddress isa; + if (!Reader->template readRemoteAddress(addr, isa)) return std::nullopt; return isa; }; // Extended pointers have a tag of 0b111, using 8 additional bits // to specify the class. - if (TaggedPointerExtendedMask != 0 && - (((objectAddress ^ TaggedPointerObfuscator) & TaggedPointerExtendedMask) - == TaggedPointerExtendedMask)) { + if (TaggedPointerExtendedMask && + ((((StoredPointer)objectAddress.getRawAddress() ^ + TaggedPointerObfuscator) & + TaggedPointerExtendedMask) == TaggedPointerExtendedMask)) { auto tag = ((objectAddress >> TaggedPointerExtendedSlotShift) & TaggedPointerExtendedSlotMask); return readArrayElement(TaggedPointerExtendedClasses, tag); @@ -1708,13 +1718,13 @@ class MetadataReader { /// Read the isa pointer of a class or closure context instance and apply /// the isa mask. - std::optional - readMetadataFromInstance(StoredPointer objectAddress) { + std::optional + readMetadataFromInstance(RemoteAddress objectAddress) { if (isTaggedPointer(objectAddress)) return readMetadataFromTaggedPointer(objectAddress); - StoredPointer isa; - if (!Reader->readInteger(RemoteAddress(objectAddress), &isa)) + RemoteAddress isa; + if (!Reader->template readRemoteAddress(objectAddress, isa)) return std::nullopt; switch (getIsaEncoding()) { @@ -1731,11 +1741,12 @@ class MetadataReader { case IsaEncodingKind::Indexed: { // If applying the magic mask doesn't give us the magic value, // it's not an indexed isa. - if ((isa & IsaMagicMask) != IsaMagicValue) + if (((StoredPointer)(isa & IsaMagicMask).getRawAddress()) != + IsaMagicValue) return isa; // Extract the index. - auto classIndex = (isa & IsaIndexMask) >> IsaIndexShift; + StoredPointer classIndex = (isa & IsaIndexMask) >> IsaIndexShift; // 0 is never a valid index. if (classIndex == 0) { @@ -1761,10 +1772,10 @@ class MetadataReader { RemoteAddress eltPointer = RemoteAddress(IndexedClassesPointer + classIndex * sizeof(StoredPointer)); - StoredPointer metadataPointer; - if (!Reader->readInteger(eltPointer, &metadataPointer)) { + RemoteAddress metadataPointer; + if (!Reader->template readRemoteAddress(eltPointer, + metadataPointer)) return std::nullopt; - } return metadataPointer; } @@ -1865,7 +1876,7 @@ class MetadataReader { return cls->getClassBoundsAsSwiftSuperclass(); }, - [](StoredPointer objcClassName) + [](RemoteAddress objcClassName) -> std::optional { // We have no ability to look up an ObjC class by name. // FIXME: add a query for this; clients may have a way to do it. @@ -1883,14 +1894,14 @@ class MetadataReader { template std::optional forTypeReference(TypeReferenceKind refKind, - StoredPointer ref, + RemoteAddress ref, const DescriptorFn &descriptorFn, const MetadataFn &metadataFn, const ClassNameFn &classNameFn) { switch (refKind) { case TypeReferenceKind::IndirectTypeDescriptor: { StoredSignedPointer descriptorAddress; - if (!Reader->readInteger(RemoteAddress(ref), &descriptorAddress)) { + if (!Reader->readInteger(ref, &descriptorAddress)) { return std::nullopt; } @@ -1910,8 +1921,8 @@ class MetadataReader { return classNameFn(ref); case TypeReferenceKind::IndirectObjCClass: { - StoredPointer classRef = 0; - if (!Reader->readInteger(RemoteAddress(ref), &classRef)) + RemoteAddress classRef; + if (!Reader->template readRemoteAddress(ref, classRef)) return std::nullopt; auto metadata = readMetadata(classRef); @@ -1927,8 +1938,8 @@ class MetadataReader { /// Read a single generic type argument from a bound generic type /// metadata. - std::optional - readGenericArgFromMetadata(StoredPointer metadata, unsigned index) { + std::optional + readGenericArgFromMetadata(RemoteAddress metadata, unsigned index) { auto Meta = readMetadata(metadata); if (!Meta) return std::nullopt; @@ -1958,9 +1969,9 @@ class MetadataReader { if (index >= generics->getGenericContextHeader().getNumArguments()) return std::nullopt; - StoredPointer genericArgAddress; - if (!Reader->readInteger(RemoteAddress(addressOfGenericArgAddress), - &genericArgAddress)) + RemoteAddress genericArgAddress; + if (!Reader->template readRemoteAddress( + addressOfGenericArgAddress, genericArgAddress)) return std::nullopt; return genericArgAddress; @@ -1968,7 +1979,7 @@ class MetadataReader { /// Given the address of a nominal type descriptor, attempt to resolve /// its nominal type declaration. - BuiltTypeDecl readNominalTypeFromDescriptor(StoredPointer address) { + BuiltTypeDecl readNominalTypeFromDescriptor(RemoteAddress address) { auto descriptor = readContextDescriptor(address); if (!descriptor) return BuiltTypeDecl(); @@ -1977,7 +1988,7 @@ class MetadataReader { } /// Try to read the offset of a tuple element from a tuple metadata. - bool readTupleElementOffset(StoredPointer metadataAddress, unsigned eltIndex, + bool readTupleElementOffset(RemoteAddress metadataAddress, unsigned eltIndex, StoredSize *offset) { // Read the metadata. auto metadata = readMetadata(metadataAddress); @@ -2001,7 +2012,7 @@ class MetadataReader { /// Given a remote pointer to class metadata, attempt to read its superclass. std::optional - readOffsetToFirstCaptureFromMetadata(StoredPointer MetadataAddress) { + readOffsetToFirstCaptureFromMetadata(RemoteAddress MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return std::nullopt; @@ -2010,15 +2021,15 @@ class MetadataReader { return heapMeta->OffsetToFirstCapture; } - std::optional readPointer(StoredPointer address) { - return Reader->readPointer(RemoteAddress(address), sizeof(StoredPointer)); + std::optional readPointer(RemoteAddress address) { + return Reader->readPointer(address, sizeof(StoredPointer)); } - std::optional readResolvedPointerValue(StoredPointer address) { + std::optional readResolvedPointerValue(RemoteAddress address) { if (auto pointer = readPointer(address)) { - if (!pointer->isResolved()) + if (!pointer->getResolvedAddress()) return std::nullopt; - return (StoredPointer)pointer->getResolvedAddress().getAddressData(); + return pointer->getResolvedAddress(); } return std::nullopt; } @@ -2027,13 +2038,13 @@ class MetadataReader { RemoteAbsolutePointer resolvePointerField(RemoteRef base, const U &field) { auto pointerRef = base.getField(field); - return Reader->resolvePointer(RemoteAddress(getAddress(pointerRef)), + return Reader->resolvePointer(getAddress(pointerRef), *pointerRef.getLocalBuffer()); } /// Given a remote pointer to class metadata, attempt to read its superclass. std::optional - readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) { + readCaptureDescriptorFromMetadata(RemoteAddress MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return std::nullopt; @@ -2043,15 +2054,14 @@ class MetadataReader { } protected: - template - StoredPointer getAddress(RemoteRef base) { - return (StoredPointer)base.getAddressData(); + template + RemoteAddress getAddress(RemoteRef base) { + return base.getRemoteAddress(); } - - template - StoredPointer resolveRelativeField( - RemoteRef base, const Field &field) { - return (StoredPointer)base.resolveRelativeFieldData(field); + + template + RemoteAddress resolveRelativeField(RemoteRef base, const Field &field) { + return base.resolveRelativeFieldData(field); } template @@ -2067,9 +2077,9 @@ class MetadataReader { offset &= ~1u; using SignedPointer = typename std::make_signed::type; - - StoredPointer resultAddress = getAddress(fieldRef) + (SignedPointer)offset; - + + RemoteAddress resultAddress = getAddress(fieldRef) + (SignedPointer)offset; + // Low bit set in the offset indicates that the offset leads to the absolute // address in memory. if (indirect) { @@ -2078,16 +2088,16 @@ class MetadataReader { } return std::nullopt; } - - return RemoteAbsolutePointer("", resultAddress); + + return RemoteAbsolutePointer(resultAddress); } /// Given a pointer to an Objective-C class, try to read its class name. - bool readObjCClassName(StoredPointer classAddress, std::string &className) { + bool readObjCClassName(RemoteAddress classAddress, std::string &className) { // The following algorithm only works on the non-fragile Apple runtime. // Grab the RO-data pointer. This part is not ABI. - StoredPointer roDataPtr = readObjCRODataPtr(classAddress); + RemoteAddress roDataPtr = readObjCRODataPtr(classAddress); if (!roDataPtr) return false; // This is ABI. @@ -2096,18 +2106,19 @@ class MetadataReader { + sizeof(StoredPointer); // Read the name pointer. - StoredPointer namePtr; - if (!Reader->readInteger(RemoteAddress(roDataPtr + OffsetToName), &namePtr)) + RemoteAddress namePtr; + if (!Reader->template readRemoteAddress( + roDataPtr + OffsetToName, namePtr)) return false; // If the name pointer is null, treat that as an error. if (!namePtr) return false; - return Reader->readString(RemoteAddress(namePtr), className); + return Reader->readString(namePtr, className); } - MetadataRef readMetadata(StoredPointer address) { + MetadataRef readMetadata(RemoteAddress address) { auto cached = MetadataCache.find(address); if (cached != MetadataCache.end()) return MetadataRef(address, @@ -2115,7 +2126,7 @@ class MetadataReader { cached->second.get())); StoredPointer KindValue = 0; - if (!Reader->readInteger(RemoteAddress(address), &KindValue)) + if (!Reader->readInteger(address, &KindValue)) return nullptr; switch (getEnumeratedMetadataKind(KindValue)) { @@ -2128,20 +2139,17 @@ class MetadataReader { case MetadataKind::ErrorObject: return _readMetadata(address); case MetadataKind::Existential: { - StoredPointer flagsAddress = address + - sizeof(StoredPointer); + RemoteAddress flagsAddress = address + sizeof(StoredPointer); ExistentialTypeFlags::int_type flagsData; - if (!Reader->readInteger(RemoteAddress(flagsAddress), - &flagsData)) + if (!Reader->readInteger(flagsAddress, &flagsData)) return nullptr; ExistentialTypeFlags flags(flagsData); - StoredPointer numProtocolsAddress = flagsAddress + sizeof(flagsData); + RemoteAddress numProtocolsAddress = flagsAddress + sizeof(flagsData); uint32_t numProtocols; - if (!Reader->readInteger(RemoteAddress(numProtocolsAddress), - &numProtocols)) + if (!Reader->readInteger(numProtocolsAddress, &numProtocols)) return nullptr; // Make sure the number of protocols is reasonable @@ -2162,9 +2170,10 @@ class MetadataReader { case MetadataKind::ExtendedExistential: { // We need to read the shape in order to figure out how large // the generalization arguments are. - StoredPointer shapeAddress = address + sizeof(StoredPointer); - StoredSignedPointer signedShapePtr; - if (!Reader->readInteger(RemoteAddress(shapeAddress), &signedShapePtr)) + RemoteAddress shapeAddress = address + sizeof(StoredPointer); + RemoteAddress signedShapePtr; + if (!Reader->template readRemoteAddress(shapeAddress, + signedShapePtr)) return nullptr; auto shapePtr = stripSignedPointer(signedShapePtr); @@ -2186,7 +2195,7 @@ class MetadataReader { StoredSize flagsValue; auto flagsAddr = address + TargetFunctionTypeMetadata::OffsetToFlags; - if (!Reader->readInteger(RemoteAddress(flagsAddr), &flagsValue)) + if (!Reader->readInteger(flagsAddr, &flagsValue)) return nullptr; auto flags = @@ -2223,8 +2232,7 @@ class MetadataReader { auto numElementsAddress = address + TargetTupleTypeMetadata::getOffsetToNumElements(); StoredSize numElements; - if (!Reader->readInteger(RemoteAddress(numElementsAddress), - &numElements)) + if (!Reader->readInteger(numElementsAddress, &numElements)) return nullptr; auto totalSize = sizeof(TargetTupleTypeMetadata) + numElements * sizeof(TupleTypeMetadata::Element); @@ -2245,7 +2253,7 @@ class MetadataReader { return nullptr; } - StoredPointer + RemoteAddress readAddressOfNominalTypeDescriptor(MetadataRef &metadata, bool skipArtificialSubclasses = false) { switch (metadata->getKind()) { @@ -2253,28 +2261,29 @@ class MetadataReader { auto classMeta = cast(metadata); while (true) { if (!classMeta->isTypeMetadata()) - return 0; + return RemoteAddress(); StoredSignedPointer descriptorAddressSigned = classMeta->getDescriptionAsSignedPointer(); - StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + RemoteAddress descriptorAddress = + stripSignedPointer(descriptorAddressSigned); // If this class has a null descriptor, it's artificial, // and we need to skip it upon request. Otherwise, we're done. if (descriptorAddress || !skipArtificialSubclasses) - return static_cast(descriptorAddress); + return descriptorAddress; auto superclassMetadataAddress = stripSignedPointer(classMeta->Superclass); if (!superclassMetadataAddress) - return 0; + return RemoteAddress(); auto superMeta = readMetadata(superclassMetadataAddress); if (!superMeta) - return 0; + return RemoteAddress(); auto superclassMeta = dyn_cast(superMeta); if (!superclassMeta) - return 0; + return RemoteAddress(); classMeta = superclassMeta; metadata = superMeta; @@ -2286,39 +2295,42 @@ class MetadataReader { case MetadataKind::Enum: { auto valueMeta = cast>(metadata); StoredSignedPointer descriptorAddressSigned = valueMeta->getDescriptionAsSignedPointer(); - StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + RemoteAddress descriptorAddress = + stripSignedPointer(descriptorAddressSigned); return descriptorAddress; } case MetadataKind::ForeignClass: { auto foreignMeta = cast>(metadata); StoredSignedPointer descriptorAddressSigned = foreignMeta->getDescriptionAsSignedPointer(); - StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + RemoteAddress descriptorAddress = + stripSignedPointer(descriptorAddressSigned); return descriptorAddress; } case MetadataKind::ForeignReferenceType: { auto foreignMeta = cast>(metadata); StoredSignedPointer descriptorAddressSigned = foreignMeta->getDescriptionAsSignedPointer(); - StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); + RemoteAddress descriptorAddress = + stripSignedPointer(descriptorAddressSigned); return descriptorAddress; } default: - return 0; + return RemoteAddress(); } } private: template