From 6fd3ae7812b21133e4a40434a719d1edbca04e20 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 14 Sep 2021 19:38:46 +0900 Subject: [PATCH 01/53] [Wasm] Specify the least valid pointer for wasm32 WebAssembly doesn't reserve low addresses but without "extra inhabitants" of the pointer representation, runtime performance and memory footprint are worse. So assume that compiler driver uses wasm-ld and --global-base=1024 to reserve low 1KB. --- lib/Driver/WebAssemblyToolChains.cpp | 6 ++++-- lib/IRGen/SwiftTargetInfo.cpp | 10 ++++++++++ stdlib/public/SwiftShims/HeapObject.h | 16 ++++++++++++++++ stdlib/public/SwiftShims/System.h | 8 ++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/Driver/WebAssemblyToolChains.cpp b/lib/Driver/WebAssemblyToolChains.cpp index b4095ce61f36b..52c9a2cb06dc2 100644 --- a/lib/Driver/WebAssemblyToolChains.cpp +++ b/lib/Driver/WebAssemblyToolChains.cpp @@ -1,5 +1,4 @@ -//===---- WebAssemblyToolChains.cpp - Job invocations (WebAssembly-specific) -//------===// +//===---- WebAssemblyToolChains.cpp - Job invocations (WebAssembly-specific) ------===// // // This source file is part of the Swift.org open source project // @@ -189,6 +188,9 @@ toolchains::WebAssembly::constructInvocation(const DynamicLinkJobAction &job, // worse. So assume that compiler driver uses wasm-ld and --global-base=1024 // to reserve low 1KB. Arguments.push_back("-Xlinker"); + Arguments.push_back(context.Args.MakeArgString( + Twine("--global-base=") + + std::to_string(SWIFT_ABI_WASM32_LEAST_VALID_POINTER))); // These custom arguments should be right before the object file at the end. context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp index 97b70d6d75c0a..1832031cbf261 100644 --- a/lib/IRGen/SwiftTargetInfo.cpp +++ b/lib/IRGen/SwiftTargetInfo.cpp @@ -169,6 +169,13 @@ static void configureSystemZ(IRGenModule &IGM, const llvm::Triple &triple, target.SwiftRetainIgnoresNegativeValues = true; } +/// Configures target-specific information for wasm32 platforms. +static void configureWasm32(IRGenModule &IGM, const llvm::Triple &triple, + SwiftTargetInfo &target) { + target.LeastValidPointerValue = + SWIFT_ABI_WASM32_LEAST_VALID_POINTER; +} + /// Configure a default target. SwiftTargetInfo::SwiftTargetInfo( llvm::Triple::ObjectFormatType outputObjectFormat, @@ -240,6 +247,9 @@ SwiftTargetInfo SwiftTargetInfo::get(IRGenModule &IGM) { case llvm::Triple::systemz: configureSystemZ(IGM, triple, target); break; + case llvm::Triple::wasm32: + configureWasm32(IGM, triple, target); + break; default: // FIXME: Complain here? Default target info is unlikely to be correct. diff --git a/stdlib/public/SwiftShims/HeapObject.h b/stdlib/public/SwiftShims/HeapObject.h index 3933b0b8d40e2..3d4f12469f949 100644 --- a/stdlib/public/SwiftShims/HeapObject.h +++ b/stdlib/public/SwiftShims/HeapObject.h @@ -190,6 +190,22 @@ static_assert(alignof(HeapObject) == alignof(void*), #define _swift_BridgeObject_TaggedPointerBits \ (__swift_uintptr_t) SWIFT_ABI_DEFAULT_BRIDGEOBJECT_TAG_64 +#elif defined(__wasm32__) + +#define _swift_abi_LeastValidPointerValue \ + (__swift_uintptr_t) SWIFT_ABI_WASM32_LEAST_VALID_POINTER + +#define _swift_abi_SwiftSpareBitsMask \ + (__swift_uintptr_t) SWIFT_ABI_DEFAULT_SWIFT_SPARE_BITS_MASK + +#define _swift_abi_ObjCReservedBitsMask \ + (__swift_uintptr_t) SWIFT_ABI_DEFAULT_OBJC_RESERVED_BITS_MASK +#define _swift_abi_ObjCReservedLowBits \ + (unsigned) SWIFT_ABI_DEFAULT_OBJC_NUM_RESERVED_LOW_BITS + +#define _swift_BridgeObject_TaggedPointerBits \ + (__swift_uintptr_t) SWIFT_ABI_DEFAULT_BRIDGEOBJECT_TAG_32 + #else #define _swift_abi_LeastValidPointerValue \ diff --git a/stdlib/public/SwiftShims/System.h b/stdlib/public/SwiftShims/System.h index 978ec41f1eafb..2acfdd417ee03 100644 --- a/stdlib/public/SwiftShims/System.h +++ b/stdlib/public/SwiftShims/System.h @@ -207,4 +207,12 @@ #define SWIFT_ABI_S390X_OBJC_WEAK_REFERENCE_MARKER_VALUE \ (1< Date: Fri, 11 Feb 2022 09:32:48 +0100 Subject: [PATCH 02/53] [build-script] Add option to build lld as part of LLVM --- utils/build-script-impl | 12 ++---------- utils/build_swift/build_swift/driver_arguments.py | 3 +++ utils/build_swift/tests/expected_options.py | 2 ++ .../swift_build_support/build_script_invocation.py | 14 ++++++++++++++ validation-test/BuildSystem/build_lld.test | 9 +++++++++ 5 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 validation-test/BuildSystem/build_lld.test diff --git a/utils/build-script-impl b/utils/build-script-impl index c582c00264758..a7672d5ad404b 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -1833,16 +1833,8 @@ for host in "${ALL_HOSTS[@]}"; do llvm_enable_projects+=("clang-tools-extra") fi - # On non-Darwin platforms, build lld so we can always have a - # linker that is compatible with the swift we are using to - # compile the stdlib. - # - # This makes it easier to build target stdlibs on systems that - # have old toolchains without more modern linker features. - if [[ "$(uname -s)" != "Darwin" ]] ; then - if [[ ! "${SKIP_BUILD_LLD}" ]]; then - llvm_enable_projects+=("lld") - fi + if [[ ! "${SKIP_BUILD_LLD}" ]]; then + llvm_enable_projects+=("lld") fi cmake_options+=( diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 738042364c5a9..2caf55d14fee1 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -721,6 +721,9 @@ def create_argument_parser(): option(['--build-libparser-only'], toggle_true('build_libparser_only'), help='build only libParser for SwiftSyntax') + option(['--build-lld'], toggle_true('build_lld'), + help='build lld as part of llvm') + option('--skip-build-clang-tools-extra', toggle_false('build_clang_tools_extra'), default=True, diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index 9984cf0c439f3..2939738f677fd 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -71,6 +71,7 @@ 'build_lldb': False, 'build_libcxx': False, 'build_ninja': False, + 'build_lld': False, 'build_osx': True, 'build_playgroundsupport': False, 'build_runtime_with_host_compiler': False, @@ -531,6 +532,7 @@ class BuildScriptImplOption(_BaseOption): EnableOption('--android'), EnableOption('--build-external-benchmarks'), EnableOption('--build-ninja'), + EnableOption('--build-lld'), EnableOption('--build-runtime-with-host-compiler'), EnableOption('--build-swift-dynamic-sdk-overlay'), EnableOption('--build-swift-dynamic-stdlib'), diff --git a/utils/swift_build_support/swift_build_support/build_script_invocation.py b/utils/swift_build_support/swift_build_support/build_script_invocation.py index 5343318ad80fa..5f4dd06ec2d6c 100644 --- a/utils/swift_build_support/swift_build_support/build_script_invocation.py +++ b/utils/swift_build_support/swift_build_support/build_script_invocation.py @@ -427,6 +427,20 @@ def convert_to_impl_arguments(self): "--llvm-install-components=%s" % args.llvm_install_components ] + # On non-Darwin platforms, build lld so we can always have a + # linker that is compatible with the swift we are using to + # compile the stdlib. + # + # This makes it easier to build target stdlibs on systems that + # have old toolchains without more modern linker features. + # + # On Darwin, only build lld if explicitly requested using --build-lld. + should_build_lld = (platform.system() != 'Darwin' or args.build_lld) + if not should_build_lld: + impl_args += [ + "--skip-build-lld" + ] + if not args.clean_libdispatch: impl_args += [ "--skip-clean-libdispatch" diff --git a/validation-test/BuildSystem/build_lld.test b/validation-test/BuildSystem/build_lld.test new file mode 100644 index 0000000000000..4df80311c6f58 --- /dev/null +++ b/validation-test/BuildSystem/build_lld.test @@ -0,0 +1,9 @@ +# RUN: %empty-directory(%t) +# RUN: mkdir -p %t +# RUN: SKIP_XCODE_VERSION_CHECK=1 SWIFT_BUILD_ROOT=%t %swift_src_root/utils/build-script --dry-run --build-lld 2>&1 | %FileCheck %s + +# REQUIRES: standalone_build + +# Check that lld is in LLVM_ENABLE_PROJECTS of the llvm-project/llvm build + +# CHECK: '-DLLVM_ENABLE_PROJECTS={{[^']*}}lld{{[^']*}}'{{.*}}llvm-project/llvm{{$}} From 3843c7cd5e758d74d3c4981505d2b34049214720 Mon Sep 17 00:00:00 2001 From: Becca Royal-Gordon Date: Wed, 27 Apr 2022 17:55:55 -0700 Subject: [PATCH 03/53] Update SWIFT_COMPILER_VERSION language features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `SWIFT_COMPILER_VERSION` define is used to stamp a vendor’s version number into a Swift compiler binary. It can be queried from Swift code using `#if _compiler_version` and from Clang by using a preprocessor definition called `__SWIFT_COMPILER_VERSION`. These are unsupported compiler-internal features used primarily by Apple Swift. In Swift 1.0 through 5.5, Apple Swift used a scheme for `SWIFT_COMPILER_VERSION` where the major version matched the embedded clang (e.g. 1300 for Apple Clang 13.0.0) and the minor version was ignored. Starting in Swift 5.6, Apple Swift started using major and minor version numbers that matched the Swift.org version number. This makes them easier to understand, but it means that version 1300.0.x was followed by version 5.6.x. Not only did version numbers go backwards, but also the old logic to ignore minor versions was now a liability, because it meant you would not be able to target a change to 5.7.x compilers but not 5.6.x compilers. This commit addresses the problem by: * Modifying the existing `#if _compiler_version(string-literal)` feature so it transforms the major version into a major and minor that will compare correctly to new version numbers. For instance, “1300.*” is transformed into “1.300”, which will compare correctly to a “5.6” or “5.7” version even if it doesn’t really capture the fact that “1300” was a Swift 5.5 compiler. As a bonus, this allows you to use the feature to backwards-compatibly test new compilers using the existing feature: “5007.*” will be seen by compilers before 5.7 as an unknown future version, but will be seen by 5.7 compilers as targeting them. * Modifying the `__SWIFT_COMPILER_VERSION` clang define similarly so that, to preprocessor conditions written for the old scheme, a 5.7 compiler will appear to have major version 5007. * Adding a new variant of `#if _compiler_version` with the same syntax as `#if swift` and `#if compiler`—that is, taking a comparison operator and a bare set of dotted version numbers, rather than a string literal. Going forward, this will be how version checks are written once compatibility with compilers before this change is no longer a concern. These changes are only lightly tested because tests have to work without any compiler version defined (the default in most configurations), but I’ve tested what I can. Fixes rdar://89841295. --- include/swift/AST/DiagnosticsParse.def | 5 +- include/swift/Basic/Version.h | 7 ++- lib/Basic/Version.cpp | 59 ++++++++++++++++++- lib/ClangImporter/ClangImporter.cpp | 8 ++- lib/Parse/ParseIfConfig.cpp | 50 ++++++++-------- .../compiler_version.swift | 18 +++++- unittests/Parse/BuildConfigTests.cpp | 29 +++++++++ 7 files changed, 142 insertions(+), 34 deletions(-) diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 2267f88752ee2..79a5862d869d0 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1819,7 +1819,10 @@ ERROR(version_component_not_number,none, ERROR(compiler_version_too_many_components,none, "compiler version must not have more than five components", ()) WARNING(unused_compiler_version_component,NoUsage, - "the second version component is not used for comparison", ()) + "the second version component is not used for comparison in legacy " + "compiler versions%select{|; are you trying to encode a new Swift " + "compiler version for compatibility with legacy compilers?}0", + (bool)) ERROR(empty_version_component,none, "found empty version component", ()) ERROR(compiler_version_component_out_of_range,none, diff --git a/include/swift/Basic/Version.h b/include/swift/Basic/Version.h index 98ba4e2550f11..f6d9bd2b5ff23 100644 --- a/include/swift/Basic/Version.h +++ b/include/swift/Basic/Version.h @@ -129,7 +129,12 @@ class Version { /// Return this Version struct as the appropriate version string for APINotes. std::string asAPINotesVersionString() const; - /// Parse a version in the form used by the _compiler_version \#if condition. + /// Parse a version in the form used by the _compiler_version(string-literal) + /// \#if condition. + /// + /// \note This is \em only used for the string literal version, so it includes + /// backwards-compatibility logic to convert it to something that can be + /// compared with a modern SWIFT_COMPILER_VERSION. static Optional parseCompilerVersionString(StringRef VersionString, SourceLoc Loc, DiagnosticEngine *Diags); diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 918a34ba739fb..4c183c9f72733 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/CharInfo.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "swift/AST/DiagnosticsParse.h" @@ -132,9 +133,29 @@ Optional Version::parseCompilerVersionString( // The second version component isn't used for comparison. if (i == 1) { if (!SplitComponent.equals("*")) { - if (Diags) - Diags->diagnose(Range.Start, diag::unused_compiler_version_component) - .fixItReplaceChars(Range.Start, Range.End, "*"); + if (Diags) { + // Majors 600-1300 were used for Swift 1.0-5.5 (based on clang + // versions), but then we reset the numbering based on Swift versions, + // so 5.6 had major 5. We assume that majors below 600 use the new + // scheme and equal/above it use the old scheme. + bool firstComponentLooksNew = CV.Components[0] < 600; + + auto diag = Diags->diagnose(Range.Start, + diag::unused_compiler_version_component, + firstComponentLooksNew); + + if (firstComponentLooksNew && + !SplitComponent.getAsInteger(10, ComponentNumber)) { + // Fix-it version like "5.7.1.2.3" to "5007.*.1.2.3". + auto newDigits = llvm::formatv("{0}{1,0+3}.*", CV.Components[0], + ComponentNumber).str(); + diag.fixItReplaceChars(SplitComponents[0].second.Start, + Range.End, newDigits); + } + else { + diag.fixItReplaceChars(Range.Start, Range.End, "*"); + } + } } CV.Components.push_back(0); @@ -159,6 +180,38 @@ Optional Version::parseCompilerVersionString( isValidVersion = false; } + // In the beginning, '_compiler_version(string-literal)' was designed for a + // different version scheme where the major was fairly large and the minor + // was ignored; now we use one where the minor is significant and major and + // minor match the Swift language version. See the comment above on + // `firstComponentLooksNew` for details. + // + // However, we want the string literal variant of '_compiler_version' to + // maintain source compatibility with old checks; that means checks for new + // versions have to be written so that old compilers will think they represent + // newer versions, while new compilers have to interpret old version number + // strings in a way that will compare correctly to the new versions compiled + // into them. + // + // To achieve this, modern compilers divide the major by 1000 and overwrite + // the wildcard component with the remainder, effectively shifting the last + // three digits of the major into the minor, before comparing it to the + // compiler version: + // + // _compiler_version("5007.*.1.2.3") -> 5.7.1.2.3 + // _compiler_version("1300.*.1.2.3") -> 1.300.1.2.3 (smaller than 5.6) + // _compiler_version( "600.*.1.2.3") -> 0.600.1.2.3 (smaller than 5.6) + // + // So if you want to specify a 5.7.z.a.b version, we ask users to either write + // it as 5007.*.z.a.b, or to use the new '_compiler_version(>= version)' + // syntax instead, which does not perform this conversion. + if (!CV.Components.empty()) { + if (CV.Components.size() == 1) + CV.Components.push_back(0); + CV.Components[1] = CV.Components[0] % 1000; + CV.Components[0] = CV.Components[0] / 1000; + } + return isValidVersion ? Optional(CV) : None; } diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index bad622b161305..5a5b9580bdb45 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -649,9 +649,15 @@ importer::getNormalInvocationArguments( // declarations. auto V = version::Version::getCurrentCompilerVersion(); if (!V.empty()) { + // Note: Prior to Swift 5.7, the "Y" version component was omitted and the + // "X" component resided in its digits. invocationArgStrs.insert(invocationArgStrs.end(), { V.preprocessorDefinition("__SWIFT_COMPILER_VERSION", - {1000000000, /*ignored*/ 0, 1000000, 1000, 1}), + {1000000000000, // X + 1000000000, // Y + 1000000, // Z + 1000, // a + 1}), // b }); } } else { diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 4eb5f23f054c8..8e1a4e5cdba04 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -283,30 +283,26 @@ class ValidateIfConfigCondition : } // '_compiler_version' '(' string-literal ')' if (*KindName == "_compiler_version") { - auto SLE = dyn_cast(Arg); - if (!SLE) { - D.diagnose(Arg->getLoc(), - diag::unsupported_platform_condition_argument, - "string literal"); - return nullptr; - } - - auto ValStr = SLE->getValue(); - if (ValStr.empty()) { - D.diagnose(SLE->getLoc(), diag::empty_version_string); - return nullptr; + if (auto SLE = dyn_cast(Arg)) { + auto ValStr = SLE->getValue(); + if (ValStr.empty()) { + D.diagnose(SLE->getLoc(), diag::empty_version_string); + return nullptr; + } + + auto Val = version::Version::parseCompilerVersionString( + SLE->getValue(), SLE->getLoc(), &D); + if (!Val.hasValue()) + return nullptr; + return E; } - - auto Val = version::Version::parseCompilerVersionString( - SLE->getValue(), SLE->getLoc(), &D); - if (!Val.hasValue()) - return nullptr; - return E; } // 'swift' '(' ('>=' | '<') float-literal ( '.' integer-literal )* ')' // 'compiler' '(' ('>=' | '<') float-literal ( '.' integer-literal )* ')' - if (*KindName == "swift" || *KindName == "compiler") { + // '_compiler_version' '(' ('>=' | '<') float-literal ( '.' integer-literal )* ')' + if (*KindName == "swift" || *KindName == "compiler" || + *KindName == "_compiler_version") { auto PUE = dyn_cast(Arg); Optional PrefixName = PUE ? getDeclRefStr(PUE->getFn(), DeclRefKind::PrefixOperator) : None; @@ -500,28 +496,30 @@ class EvaluateIfConfigCondition : bool visitCallExpr(CallExpr *E) { auto KindName = getDeclRefStr(E->getFn()); auto *Arg = getSingleSubExp(E->getArgs(), KindName, nullptr); - if (KindName == "_compiler_version") { + if (KindName == "_compiler_version" && isa(Arg)) { auto Str = cast(Arg)->getValue(); auto Val = version::Version::parseCompilerVersionString( Str, SourceLoc(), nullptr).getValue(); auto thisVersion = version::Version::getCurrentCompilerVersion(); return thisVersion >= Val; - } else if ((KindName == "swift") || (KindName == "compiler")) { + } else if ((KindName == "swift") || (KindName == "compiler") || + (KindName == "_compiler_version")) { auto PUE = cast(Arg); auto PrefixName = getDeclRefStr(PUE->getFn()); auto Str = extractExprSource(Ctx.SourceMgr, PUE->getOperand()); auto Val = version::Version::parseVersionString( Str, SourceLoc(), nullptr).getValue(); + version::Version thisVersion; if (KindName == "swift") { - return isValidVersion(Ctx.LangOpts.EffectiveLanguageVersion, Val, - PrefixName); + thisVersion = Ctx.LangOpts.EffectiveLanguageVersion; } else if (KindName == "compiler") { - auto currentLanguageVersion = - version::Version::getCurrentLanguageVersion(); - return isValidVersion(currentLanguageVersion, Val, PrefixName); + thisVersion = version::Version::getCurrentLanguageVersion(); + } else if (KindName == "_compiler_version") { + thisVersion = version::Version::getCurrentCompilerVersion(); } else { llvm_unreachable("unsupported version conditional"); } + return isValidVersion(thisVersion, Val, PrefixName); } else if (KindName == "canImport") { auto Str = extractExprSource(Ctx.SourceMgr, Arg); bool underlyingModule = false; diff --git a/test/Parse/ConditionalCompilation/compiler_version.swift b/test/Parse/ConditionalCompilation/compiler_version.swift index 690364c1df764..0dad441005ed3 100644 --- a/test/Parse/ConditionalCompilation/compiler_version.swift +++ b/test/Parse/ConditionalCompilation/compiler_version.swift @@ -7,7 +7,7 @@ asdf asdf asdf asdf #endif -#if _compiler_version("10.*.10.10") +#if _compiler_version("600.*.10.10") #if os(iOS) let z = 1 @@ -48,7 +48,10 @@ let thisWillStillParseBecauseConfigIsError = 1 #endif -#if _compiler_version("700.0.100") // expected-warning {{the second version component is not used for comparison}} +#if _compiler_version("700.0.100") // expected-warning {{the second version component is not used for comparison in legacy compiler versions}} {{28-29=*}} +#endif + +#if _compiler_version("5.7.100") // expected-warning {{the second version component is not used for comparison in legacy compiler versions; are you trying to encode a new Swift compiler version for compatibility with legacy compilers?}} {{24-27=5007.*}} #endif #if _compiler_version("700.*.1.1.1.1") // expected-error {{version must not have more than five components}} @@ -65,3 +68,14 @@ #if _compiler_version("700.*.1.1.1000") // expected-error {{version component out of range: must be in [0, 999]}} #endif + +// New style _compiler_version() +#if _compiler_version(<4.0) + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif + +#if !_compiler_version(>=4.3.2.1.0) + // This shouldn't emit any diagnostics. + asdf asdf asdf asdf +#endif diff --git a/unittests/Parse/BuildConfigTests.cpp b/unittests/Parse/BuildConfigTests.cpp index 639e6527e9899..db526296e9d0f 100644 --- a/unittests/Parse/BuildConfigTests.cpp +++ b/unittests/Parse/BuildConfigTests.cpp @@ -8,6 +8,7 @@ using namespace llvm; class CompilerVersionTest : public ::testing::Test {}; class VersionTest : public ::testing::Test{}; +class CompilerVersionUnpackingTest : public ::testing::Test {}; Optional CV(const char *VersionString) { return version::Version::parseCompilerVersionString(VersionString, @@ -52,3 +53,31 @@ TEST_F(VersionTest, VersionComparison) { EXPECT_FALSE(V(".1").hasValue()); } + +TEST_F(CompilerVersionUnpackingTest, VersionComparison) { + EXPECT_EQ(CV("700").getValue(), V("0.700").getValue()); + EXPECT_EQ(CV("700.*").getValue(), V("0.700").getValue()); + EXPECT_EQ(CV("700.*.1").getValue(), V("0.700.1").getValue()); + EXPECT_EQ(CV("700.*.23").getValue(), V("0.700.23").getValue()); + EXPECT_EQ(CV("700.*.1.1").getValue(), V("0.700.1.1").getValue()); + + EXPECT_EQ(CV("1300").getValue(), V("1.300").getValue()); + EXPECT_EQ(CV("1300.*").getValue(), V("1.300").getValue()); + EXPECT_EQ(CV("1300.*.1").getValue(), V("1.300.1").getValue()); + EXPECT_EQ(CV("1300.*.23").getValue(), V("1.300.23").getValue()); + EXPECT_EQ(CV("1300.*.1.1").getValue(), V("1.300.1.1").getValue()); + + EXPECT_EQ(CV("5007").getValue(), V("5.7").getValue()); + EXPECT_EQ(CV("5007.*").getValue(), V("5.7").getValue()); + EXPECT_EQ(CV("5007.*.1").getValue(), V("5.7.1").getValue()); + EXPECT_EQ(CV("5007.*.23").getValue(), V("5.7.23").getValue()); + EXPECT_EQ(CV("5007.*.1.1").getValue(), V("5.7.1.1").getValue()); + + // Since this test was added during 5.7, we expect all of these comparisons to + // be GE, either because we are comparing to the empty version or because we + // are comparing to a version >= 5.7.0.0.0. + auto currentVersion = version::Version::getCurrentCompilerVersion(); + EXPECT_GE(CV("700"), currentVersion); + EXPECT_GE(CV("1300"), currentVersion); + EXPECT_GE(CV("5007"), currentVersion); +} From 50e599792eb43b2d40e30c95228178c91002798d Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 29 Apr 2022 00:50:39 +0000 Subject: [PATCH 04/53] [stdlib] Port SE-0329 Clock APIs to WASI WASI doesn't have "suspending-time" concept, so use `CLOCK_MONOTONIC` for both "continuous" and "suspending" clocks. WASI's "monotonic" doesn't guarantee any underlying system call implementation, but most of major implementations use `CLOCK_MONOTONIC` for all underlying platforms. This partially buildfixes this platform. See also: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#variant-cases --- stdlib/public/Concurrency/Clock.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/stdlib/public/Concurrency/Clock.cpp b/stdlib/public/Concurrency/Clock.cpp index c9586628a167a..bfeb1d4d06309 100644 --- a/stdlib/public/Concurrency/Clock.cpp +++ b/stdlib/public/Concurrency/Clock.cpp @@ -42,7 +42,7 @@ void swift_get_time( clock_gettime(CLOCK_MONOTONIC_RAW, &continuous); *seconds = continuous.tv_sec; *nanoseconds = continuous.tv_nsec; -#elif defined(__OpenBSD__) && HAS_TIME +#elif (defined(__OpenBSD__) || defined(__wasi__)) && HAS_TIME struct timespec continuous; clock_gettime(CLOCK_MONOTONIC, &continuous); *seconds = continuous.tv_sec; @@ -76,6 +76,11 @@ void swift_get_time( clock_gettime(CLOCK_UPTIME_RAW, &suspending); *seconds = suspending.tv_sec; *nanoseconds = suspending.tv_nsec; +#elif defined(__wasi__) && HAS_TIME + struct timespec suspending; + clock_gettime(CLOCK_MONOTONIC, &suspending); + *seconds = suspending.tv_sec; + *nanoseconds = suspending.tv_nsec; #elif defined(__OpenBSD__) && HAS_TIME struct timespec suspending; clock_gettime(CLOCK_UPTIME, &suspending); @@ -121,7 +126,7 @@ switch (clock_id) { clock_getres(CLOCK_MONOTONIC_RAW, &continuous); *seconds = continuous.tv_sec; *nanoseconds = continuous.tv_nsec; -#elif defined(__OpenBSD__) && HAS_TIME +#elif (defined(__OpenBSD__) || defined(__wasi__)) && HAS_TIME struct timespec continuous; clock_getres(CLOCK_MONOTONIC, &continuous); *seconds = continuous.tv_sec; @@ -144,6 +149,10 @@ switch (clock_id) { clock_getres(CLOCK_UPTIME_RAW, &suspending); *seconds = suspending.tv_sec; *nanoseconds = suspending.tv_nsec; +#elif defined(__wasi__) && HAS_TIME + clock_getres(CLOCK_MONOTONIC, &suspending); + *seconds = suspending.tv_sec; + *nanoseconds = suspending.tv_nsec; #elif defined(__OpenBSD__) && HAS_TIME clock_getres(CLOCK_UPTIME, &suspending); *seconds = suspending.tv_sec; From 8ce878f7e3a00f8f15be51040519649da96e349d Mon Sep 17 00:00:00 2001 From: "mdietsche@icloud.com" Date: Sun, 8 May 2022 01:53:37 +0200 Subject: [PATCH 05/53] Do not suggest moving `any` or `some` to the beginning of a composition if the first type is already an existential or opaque type. --- lib/Parse/ParseType.cpp | 15 +++++++++++---- test/type/explicit_existential.swift | 10 ++++++---- test/type/opaque.swift | 5 ++++- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 16feac79393db..3d732e62d57bd 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -881,13 +881,20 @@ Parser::parseTypeSimpleOrComposition(Diag<> MessageID, ParseTypeReason reason) { Tok.isContextualKeyword("any")) { auto keyword = Tok.getText(); auto badLoc = consumeToken(); + + // Suggest moving `some` or `any` in front of the first type unless + // the first type is an opaque or existential type. + if (opaqueLoc.isValid() || anyLoc.isValid()) { + diagnose(badLoc, diag::opaque_mid_composition, keyword) + .fixItRemove(badLoc); + } else { + diagnose(badLoc, diag::opaque_mid_composition, keyword) + .fixItRemove(badLoc) + .fixItInsert(FirstTypeLoc, keyword.str() + " "); + } const bool isAnyKeyword = keyword.equals("any"); - diagnose(badLoc, diag::opaque_mid_composition, keyword) - .fixItRemove(badLoc) - .fixItInsert(FirstTypeLoc, keyword.str() + " "); - if (isAnyKeyword) { if (anyLoc.isInvalid()) { anyLoc = badLoc; diff --git a/test/type/explicit_existential.swift b/test/type/explicit_existential.swift index 340ad8b705397..aa706b63167e2 100644 --- a/test/type/explicit_existential.swift +++ b/test/type/explicit_existential.swift @@ -156,15 +156,17 @@ func anyAny() { protocol P1 {} protocol P2 {} +protocol P3 {} do { // Test that we don't accidentally misparse an 'any' type as a 'some' type // and vice versa. - let _: P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} - let _: any P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} - let _: any P1 & some P2 // expected-error {{'some' should appear at the beginning of a composition}} + let _: P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} {{15-19=}} {{10-10=any }} + let _: any P1 & any P2 // expected-error {{'any' should appear at the beginning of a composition}} {{19-23=}} + let _: any P1 & P2 & any P3 // expected-error {{'any' should appear at the beginning of a composition}} {{24-28=}} + let _: any P1 & some P2 // expected-error {{'some' should appear at the beginning of a composition}} {{19-24=}} let _: some P1 & any P2 // expected-error@-1 {{'some' type can only be declared on a single property declaration}} - // expected-error@-2 {{'any' should appear at the beginning of a composition}} + // expected-error@-2 {{'any' should appear at the beginning of a composition}} {{20-24=}} } struct ConcreteComposition: P1, P2 {} diff --git a/test/type/opaque.swift b/test/type/opaque.swift index b07882b922bd0..dc4fe826214ab 100644 --- a/test/type/opaque.swift +++ b/test/type/opaque.swift @@ -488,8 +488,11 @@ func foo_repl(_ s: S) -> some Proto { protocol SomeProtocolA {} protocol SomeProtocolB {} -struct SomeStructC: SomeProtocolA, SomeProtocolB {} +protocol SomeProtocolC {} +struct SomeStructC: SomeProtocolA, SomeProtocolB, SomeProtocolC {} let someProperty: SomeProtocolA & some SomeProtocolB = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{35-40=}}{{19-19=some }} +let someOtherProperty: some SomeProtocolA & some SomeProtocolB = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{45-50=}} +let someThirdProperty: some SomeProtocolA & SomeProtocolB & some SomeProtocolC = SomeStructC() // expected-error {{'some' should appear at the beginning of a composition}}{{61-66=}} // An opaque result type on a protocol extension member effectively // contains an invariant reference to 'Self', and therefore cannot From c163e0fe5e3167c0c99e40d011833ee17470d87c Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Wed, 18 May 2022 17:16:51 -0700 Subject: [PATCH 06/53] [Tests] Make OS features consistent lit.py currently allows any substring of `target_triple` to be used as a feature in REQUIRES/UNSUPPORTED/XFAIL. This results in various forms of the OS spread across the tests and is also somewhat confusing since they aren't actually listed in the available features. Modify all OS-related features to use the `OS=` version that Swift adds instead. We can later remove `config.target_triple` so that these don't the non-OS versions don't work in the first place. --- ...nested-differentiation-of-extension-method-optimized.swift | 2 +- test/Concurrency/Reflection/reflect_task.swift | 2 +- .../Runtime/async_taskgroup_asynciterator_semantics.swift | 2 +- .../Runtime/async_taskgroup_is_asyncsequence.swift | 2 +- test/Concurrency/Runtime/executor_deinit1.swift | 2 +- test/DebugInfo/local-vars.swift.gyb | 2 +- ...ule_final_class_adhoc_requirement_not_optimized_away.swift | 2 +- test/Distributed/Runtime/distributed_actor_deinit.swift | 2 +- .../distributed_actor_func_calls_remoteCall_echo.swift | 2 +- .../distributed_actor_func_calls_remoteCall_empty.swift | 2 +- .../distributed_actor_func_calls_remoteCall_genericFunc.swift | 2 +- .../distributed_actor_func_calls_remoteCall_hello.swift | 2 +- .../distributed_actor_func_calls_remoteCall_take.swift | 2 +- ...tributed_actor_func_calls_remoteCall_takeThrowReturn.swift | 2 +- .../distributed_actor_func_calls_remoteCall_take_two.swift | 2 +- .../distributed_actor_func_calls_remoteCall_throw.swift | 2 +- test/Distributed/Runtime/distributed_actor_hop_to.swift | 2 +- .../Runtime/distributed_actor_in_other_module.swift | 2 +- test/Distributed/Runtime/distributed_actor_remoteCall.swift | 2 +- ...ributed_actor_remoteCallTarget_demanglingTargetNames.swift | 2 +- .../Runtime/distributed_actor_remoteCall_roundtrip.swift | 2 +- test/Distributed/Runtime/distributed_actor_whenLocal.swift | 2 +- test/Driver/Dependencies/embed-bitcode-parallel-fine.swift | 2 +- test/Driver/Dependencies/one-way-parallel-fine.swift | 2 +- test/Driver/Dependencies/only-skip-once.swift | 2 +- test/Driver/batch_mode_bridging_pch.swift | 1 - test/Driver/environment.swift | 2 +- test/Driver/filelists.swift | 2 +- test/Driver/frontend.swift | 2 +- test/Driver/fuzzer.swift | 2 +- test/Driver/loaded_module_trace_nocrash.swift | 2 +- test/Driver/loaded_module_trace_swiftinterface.swift | 2 +- test/Driver/macabi-environment.swift | 2 +- test/Driver/parseable_output.swift | 2 +- test/Driver/parseable_output_unicode.swift | 2 +- test/Driver/pipe_round_robin.swift.gyb | 2 +- test/Driver/sdk-apple.swift | 2 +- test/IDE/print_clang_header_i386.swift | 2 +- test/IRGen/abitypes.swift | 2 +- test/Interpreter/shebang-direct.swift | 2 +- test/ModuleInterface/BadStdlib.swiftinterface | 2 +- .../swift_build_sdk_interfaces/compiler-crash.test-sh | 2 +- test/Prototypes/CollectionTransformers.swift | 2 +- test/Reflection/box_descriptors.sil | 4 ++-- test/Reflection/capture_descriptors.sil | 2 +- test/Reflection/conformance_descriptors.swift | 2 +- test/Reflection/typeref_decoding_imported.swift | 2 +- test/SILOptimizer/addr_escape_info.sil | 2 +- test/SILOptimizer/escape_info.sil | 2 +- test/SILOptimizer/no-external-defs-onone.sil | 2 +- test/SILOptimizer/ranges.sil | 2 +- test/Sanitizers/asan/recover.swift | 2 +- test/Sanitizers/tsan/actor_counters.swift | 4 ++-- test/Sanitizers/tsan/objc_async.swift | 4 ++-- test/decl/result_builder_fixits.swift | 2 +- test/multifile/protocol-conformance-redundant.swift | 2 +- test/stdlib/simd_diagnostics.swift | 2 +- validation-test/SILOptimizer/large_string_array.swift.gyb | 2 +- .../Sema/type_checker_perf/fast/rdar23620262.swift | 2 +- .../Sema/type_checker_perf/fast/rdar54580427.swift | 2 +- validation-test/execution/dsohandle-multi-module.swift | 2 +- validation-test/stdlib/SIMDParameterPassing.swift.gyb | 2 +- 62 files changed, 64 insertions(+), 65 deletions(-) diff --git a/test/AutoDiff/compiler_crashers_fixed/rdar71191415-nested-differentiation-of-extension-method-optimized.swift b/test/AutoDiff/compiler_crashers_fixed/rdar71191415-nested-differentiation-of-extension-method-optimized.swift index 7a8a5f5ce8fc2..2aac3e1a58adc 100644 --- a/test/AutoDiff/compiler_crashers_fixed/rdar71191415-nested-differentiation-of-extension-method-optimized.swift +++ b/test/AutoDiff/compiler_crashers_fixed/rdar71191415-nested-differentiation-of-extension-method-optimized.swift @@ -1,7 +1,7 @@ // RUN: %target-build-swift -O %s // FIXME(rdar://89055298) -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // rdar://71191415 diff --git a/test/Concurrency/Reflection/reflect_task.swift b/test/Concurrency/Reflection/reflect_task.swift index 97267593888ea..9101fe70a174b 100644 --- a/test/Concurrency/Reflection/reflect_task.swift +++ b/test/Concurrency/Reflection/reflect_task.swift @@ -10,7 +10,7 @@ // UNSUPPORTED: use_os_stdlib // UNSUPPORTED: back_deployment_runtime // -// UNSUPPORTED: OS=macosx,ios,watchos,tvos +// UNSUPPORTED: OS=macosx, OS=ios, OS=watchos, OS=tvos import Swift import _Concurrency diff --git a/test/Concurrency/Runtime/async_taskgroup_asynciterator_semantics.swift b/test/Concurrency/Runtime/async_taskgroup_asynciterator_semantics.swift index c12695aa359cd..a2961f5da8394 100644 --- a/test/Concurrency/Runtime/async_taskgroup_asynciterator_semantics.swift +++ b/test/Concurrency/Runtime/async_taskgroup_asynciterator_semantics.swift @@ -3,7 +3,7 @@ // REQUIRES: concurrency // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // REQUIRES: rdar86028226 diff --git a/test/Concurrency/Runtime/async_taskgroup_is_asyncsequence.swift b/test/Concurrency/Runtime/async_taskgroup_is_asyncsequence.swift index 8f036a0023a82..5ec0e92fc874f 100644 --- a/test/Concurrency/Runtime/async_taskgroup_is_asyncsequence.swift +++ b/test/Concurrency/Runtime/async_taskgroup_is_asyncsequence.swift @@ -7,7 +7,7 @@ // REQUIRES: concurrency_runtime // UNSUPPORTED: back_deployment_runtime -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu @available(SwiftStdlib 5.1, *) func test_taskGroup_is_asyncSequence() async { diff --git a/test/Concurrency/Runtime/executor_deinit1.swift b/test/Concurrency/Runtime/executor_deinit1.swift index a5f04ec1db5e7..904defa6bbea8 100644 --- a/test/Concurrency/Runtime/executor_deinit1.swift +++ b/test/Concurrency/Runtime/executor_deinit1.swift @@ -7,7 +7,7 @@ // UNSUPPORTED: back_deployment_runtime // https://bugs.swift.org/browse/SR-14461 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // REQUIRES: rdar78325660 diff --git a/test/DebugInfo/local-vars.swift.gyb b/test/DebugInfo/local-vars.swift.gyb index 082d967215109..c13f46fa0a451 100644 --- a/test/DebugInfo/local-vars.swift.gyb +++ b/test/DebugInfo/local-vars.swift.gyb @@ -3,7 +3,7 @@ // all. There are other tests testing liveness and representation. // rdar://problem/57611302 -// XFAIL: windows +// XFAIL: OS=windows-msvc // RUN: %gyb %s -o %t.swift // RUN: %target-swift-frontend %t.swift -g -emit-ir -o - | %FileCheck %t.swift diff --git a/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift b/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift index 03767a199b30d..e685e70719453 100644 --- a/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift +++ b/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift @@ -13,7 +13,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_deinit.swift b/test/Distributed/Runtime/distributed_actor_deinit.swift index 5a4d79f53ced8..e781c5e0a80fe 100644 --- a/test/Distributed/Runtime/distributed_actor_deinit.swift +++ b/test/Distributed/Runtime/distributed_actor_deinit.swift @@ -8,7 +8,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_echo.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_echo.swift index 8b26af2a09be3..bbcad0d4740d7 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_echo.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_echo.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_empty.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_empty.swift index b3cf476d23876..11e6de63d7141 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_empty.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_empty.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_genericFunc.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_genericFunc.swift index 23c778ca5524e..7ff6dcb0e9b02 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_genericFunc.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_genericFunc.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_hello.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_hello.swift index e3be138706354..c3bf701bc94b3 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_hello.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_hello.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take.swift index 2857b2dbe605f..e8d9c58600d05 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_takeThrowReturn.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_takeThrowReturn.swift index 271ed8c2c65b2..1073ba2a84d41 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_takeThrowReturn.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_takeThrowReturn.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take_two.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take_two.swift index 201d2794ea812..435582b86f4d9 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take_two.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_take_two.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_throw.swift b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_throw.swift index c051b3e28f95e..a2664a6970a5d 100644 --- a/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_throw.swift +++ b/test/Distributed/Runtime/distributed_actor_func_calls_remoteCall_throw.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_hop_to.swift b/test/Distributed/Runtime/distributed_actor_hop_to.swift index 4d977f274ea2c..54186c8828011 100644 --- a/test/Distributed/Runtime/distributed_actor_hop_to.swift +++ b/test/Distributed/Runtime/distributed_actor_hop_to.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed diff --git a/test/Distributed/Runtime/distributed_actor_in_other_module.swift b/test/Distributed/Runtime/distributed_actor_in_other_module.swift index 21c545caccf2a..785b6d8d9285f 100644 --- a/test/Distributed/Runtime/distributed_actor_in_other_module.swift +++ b/test/Distributed/Runtime/distributed_actor_in_other_module.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // REQUIRES: rdar92277324 diff --git a/test/Distributed/Runtime/distributed_actor_remoteCall.swift b/test/Distributed/Runtime/distributed_actor_remoteCall.swift index d339aa6ad29e9..3f6dbeb06fd74 100644 --- a/test/Distributed/Runtime/distributed_actor_remoteCall.swift +++ b/test/Distributed/Runtime/distributed_actor_remoteCall.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed diff --git a/test/Distributed/Runtime/distributed_actor_remoteCallTarget_demanglingTargetNames.swift b/test/Distributed/Runtime/distributed_actor_remoteCallTarget_demanglingTargetNames.swift index 26f626d44d527..7f705dae84100 100644 --- a/test/Distributed/Runtime/distributed_actor_remoteCallTarget_demanglingTargetNames.swift +++ b/test/Distributed/Runtime/distributed_actor_remoteCallTarget_demanglingTargetNames.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_remoteCall_roundtrip.swift b/test/Distributed/Runtime/distributed_actor_remoteCall_roundtrip.swift index 8302d69a152da..cd3b03c60ee8b 100644 --- a/test/Distributed/Runtime/distributed_actor_remoteCall_roundtrip.swift +++ b/test/Distributed/Runtime/distributed_actor_remoteCall_roundtrip.swift @@ -14,7 +14,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/Runtime/distributed_actor_whenLocal.swift b/test/Distributed/Runtime/distributed_actor_whenLocal.swift index f474ed9b1e353..67c09e85af7f4 100644 --- a/test/Distributed/Runtime/distributed_actor_whenLocal.swift +++ b/test/Distributed/Runtime/distributed_actor_whenLocal.swift @@ -12,7 +12,7 @@ // UNSUPPORTED: back_deployment_runtime // FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc import Distributed diff --git a/test/Driver/Dependencies/embed-bitcode-parallel-fine.swift b/test/Driver/Dependencies/embed-bitcode-parallel-fine.swift index 8de4fb11423cb..4f61676a7e854 100644 --- a/test/Driver/Dependencies/embed-bitcode-parallel-fine.swift +++ b/test/Driver/Dependencies/embed-bitcode-parallel-fine.swift @@ -1,5 +1,5 @@ // Windows doesn't support parallel execution yet -// XFAIL: windows +// XFAIL: OS=windows-msvc // RUN: %empty-directory(%t) // RUN: cp -r %S/Inputs/one-way-fine/* %t // RUN: touch -t 201401240005 %t/* diff --git a/test/Driver/Dependencies/one-way-parallel-fine.swift b/test/Driver/Dependencies/one-way-parallel-fine.swift index 5f30a6377af69..a6a47f1a14328 100644 --- a/test/Driver/Dependencies/one-way-parallel-fine.swift +++ b/test/Driver/Dependencies/one-way-parallel-fine.swift @@ -1,5 +1,5 @@ // Windows doesn't support parallel execution yet -// XFAIL: windows +// XFAIL: OS=windows-msvc // RUN: %empty-directory(%t) // RUN: cp -r %S/Inputs/one-way-fine/* %t // RUN: touch -t 201401240005 %t/* diff --git a/test/Driver/Dependencies/only-skip-once.swift b/test/Driver/Dependencies/only-skip-once.swift index 314c29f752b14..a710f20bfa3eb 100644 --- a/test/Driver/Dependencies/only-skip-once.swift +++ b/test/Driver/Dependencies/only-skip-once.swift @@ -1,4 +1,4 @@ -// XFAIL: linux, openbsd, windows +// XFAIL: OS=linux-gnu, OS=openbsd, OS=windows-msvc // RUN: %empty-directory(%t) // RUN: cp -r %S/Inputs/only-skip-once/* %t diff --git a/test/Driver/batch_mode_bridging_pch.swift b/test/Driver/batch_mode_bridging_pch.swift index 4100a01ffb7c1..f55c4eac2c7b8 100644 --- a/test/Driver/batch_mode_bridging_pch.swift +++ b/test/Driver/batch_mode_bridging_pch.swift @@ -1,4 +1,3 @@ -// XFAIL: win32 // RUN: %empty-directory(%t) // RUN: touch %t/file-01.swift %t/file-02.swift %t/file-03.swift // RUN: echo 'public func main() {}' >%t/main.swift diff --git a/test/Driver/environment.swift b/test/Driver/environment.swift index e8ec6d1cbfd2d..62d625ab30496 100644 --- a/test/Driver/environment.swift +++ b/test/Driver/environment.swift @@ -1,5 +1,5 @@ // UNSUPPORTED: objc_interop -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // Apple's "System Integrity Protection" makes this test fail on OS X. // RUN: %swift_driver_plain -sdk "" -target x86_64-unknown-gnu-linux -L/foo/ -driver-use-frontend-path %S/Inputs/print-var.sh %s LD_LIBRARY_PATH | %FileCheck -check-prefix=CHECK${LD_LIBRARY_PATH+_LAX} %s diff --git a/test/Driver/filelists.swift b/test/Driver/filelists.swift index 732f4914e580b..7b52089623f48 100644 --- a/test/Driver/filelists.swift +++ b/test/Driver/filelists.swift @@ -1,4 +1,4 @@ -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // RUN: %empty-directory(%t) // RUN: touch %t/a.swift %t/b.swift %t/c.swift diff --git a/test/Driver/frontend.swift b/test/Driver/frontend.swift index f0ee617810814..b34eb00876f34 100644 --- a/test/Driver/frontend.swift +++ b/test/Driver/frontend.swift @@ -1,5 +1,5 @@ // RUN: %swiftc_driver %s -### 2>&1 | %FileCheck %s -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // CHECK: swift-frontend diff --git a/test/Driver/fuzzer.swift b/test/Driver/fuzzer.swift index 308ba01f4374a..92536e81e58f9 100644 --- a/test/Driver/fuzzer.swift +++ b/test/Driver/fuzzer.swift @@ -1,4 +1,4 @@ -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // UNSUPPORTED: CPU=powerpc64le // RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -target x86_64-apple-macosx10.9 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER_OSX %s // RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -target x86_64-unknown-linux-gnu -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER_LINUX %s diff --git a/test/Driver/loaded_module_trace_nocrash.swift b/test/Driver/loaded_module_trace_nocrash.swift index 70960b5bbcdcb..b3b995071573e 100644 --- a/test/Driver/loaded_module_trace_nocrash.swift +++ b/test/Driver/loaded_module_trace_nocrash.swift @@ -1,4 +1,4 @@ -// UNSUPPORTED: -windows-msvc +// UNSUPPORTED: OS=windows-msvc // RUN: %empty-directory(%t) // RUN: mkdir -p %t/Mods/Foo.swiftmodule diff --git a/test/Driver/loaded_module_trace_swiftinterface.swift b/test/Driver/loaded_module_trace_swiftinterface.swift index 140215561e1b7..6289a02a0d120 100644 --- a/test/Driver/loaded_module_trace_swiftinterface.swift +++ b/test/Driver/loaded_module_trace_swiftinterface.swift @@ -1,4 +1,4 @@ -// UNSUPPORTED: -windows-msvc +// UNSUPPORTED: OS=windows-msvc // REQUIRES: SR13034 // 1) If there is no swiftmodule, use the swiftinterface diff --git a/test/Driver/macabi-environment.swift b/test/Driver/macabi-environment.swift index 928e31456a9d8..a55b43104be88 100644 --- a/test/Driver/macabi-environment.swift +++ b/test/Driver/macabi-environment.swift @@ -1,6 +1,6 @@ // Tests to check that the driver finds standard library in the macabi environment. -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // RUN: %swiftc_driver -sdk "" -sdk "" -driver-print-jobs -target x86_64-apple-ios13.1-macabi -sdk %S/../Inputs/clang-importer-sdk %s | %FileCheck -check-prefix=IOS13-MACABI %s // IOS13-MACABI: bin/swift diff --git a/test/Driver/parseable_output.swift b/test/Driver/parseable_output.swift index 46458c013c404..fda873a44d5ac 100644 --- a/test/Driver/parseable_output.swift +++ b/test/Driver/parseable_output.swift @@ -1,6 +1,6 @@ // RUN: %swiftc_driver_plain -emit-executable %s -o %t.out -emit-module -emit-module-path %t.swiftmodule -emit-objc-header-path %t.h -serialize-diagnostics -emit-dependencies -parseable-output -driver-skip-execution 2>&1 | %FileCheck %s -// XFAIL: freebsd, openbsd, linux +// XFAIL: OS=freebsd, OS=openbsd, OS=linux-gnu // CHECK: {{[1-9][0-9]*}} // CHECK-NEXT: { diff --git a/test/Driver/parseable_output_unicode.swift b/test/Driver/parseable_output_unicode.swift index f8e8925cfe430..462fd6318a210 100644 --- a/test/Driver/parseable_output_unicode.swift +++ b/test/Driver/parseable_output_unicode.swift @@ -2,7 +2,7 @@ // RUN: cat "%S/Inputs/unicode.txt" >> %t.rsp // RUN: %swiftc_driver_plain -emit-executable @%t.rsp -o %t.out -emit-module -emit-module-path %t.swiftmodule -emit-objc-header-path %t.h -serialize-diagnostics -emit-dependencies -parseable-output -driver-skip-execution 2>&1 | %FileCheck %s -// XFAIL: freebsd, openbsd, linux +// XFAIL: OS=freebsd, OS=openbsd, OS=linux-gnu // CHECK: {{[1-9][0-9]*}} // CHECK-NEXT: { diff --git a/test/Driver/pipe_round_robin.swift.gyb b/test/Driver/pipe_round_robin.swift.gyb index fcdc4211a9df5..343a34fd0038f 100644 --- a/test/Driver/pipe_round_robin.swift.gyb +++ b/test/Driver/pipe_round_robin.swift.gyb @@ -1,5 +1,5 @@ // Windows doesn't track/use read() and poll() -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // This test is unreliable on busy machines. // ALLOW_RETRIES: 5 // RUN: %empty-directory(%t/manyfuncs) diff --git a/test/Driver/sdk-apple.swift b/test/Driver/sdk-apple.swift index 228657231d4ea..481ebadcac64b 100644 --- a/test/Driver/sdk-apple.swift +++ b/test/Driver/sdk-apple.swift @@ -1,4 +1,4 @@ -// XFAIL: freebsd, openbsd, linux, windows +// XFAIL: OS=freebsd, OS=openbsd, OS=linux-gnu, OS=windows-msvc // Test SDK detection for immediate mode. // RUN: %empty-directory(%t) diff --git a/test/IDE/print_clang_header_i386.swift b/test/IDE/print_clang_header_i386.swift index d78436f712305..4a5e6d78ea37a 100644 --- a/test/IDE/print_clang_header_i386.swift +++ b/test/IDE/print_clang_header_i386.swift @@ -1,7 +1,7 @@ // REQUIRES: OS=macosx // REQUIRES: CPU=x86_64 // FIXME: rdar://problem/19648117 Needs splitting objc parts out -// XFAIL: linux, freebsd +// XFAIL: OS=linux-gnu, OS=freebsd // RUN: echo '#include "header-to-print.h"' > %t.i386.m // RUN: %empty-directory(%t) diff --git a/test/IRGen/abitypes.swift b/test/IRGen/abitypes.swift index 1b6e28275fdaa..4be683f963b8f 100644 --- a/test/IRGen/abitypes.swift +++ b/test/IRGen/abitypes.swift @@ -1,7 +1,7 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/abi %s -emit-ir -enable-objc-interop | %FileCheck -check-prefix=%target-cpu-%target-os-abi %s // FIXME: rdar://problem/19648117 Needs splitting objc parts out -// XFAIL: linux, windows, openbsd +// XFAIL: OS=linux-gnu, OS=windows-msvc, OS=openbsd import gadget import Foundation diff --git a/test/Interpreter/shebang-direct.swift b/test/Interpreter/shebang-direct.swift index cec0bb21344eb..ca6d376ad55e9 100644 --- a/test/Interpreter/shebang-direct.swift +++ b/test/Interpreter/shebang-direct.swift @@ -6,4 +6,4 @@ // RUN: %t.shebang.swift a b c | %FileCheck -check-prefix=THREE-ARGS %S/shebang-env.swift // REQUIRES: swift_interpreter -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu diff --git a/test/ModuleInterface/BadStdlib.swiftinterface b/test/ModuleInterface/BadStdlib.swiftinterface index f5375dabdfccb..54edbeda2e31d 100644 --- a/test/ModuleInterface/BadStdlib.swiftinterface +++ b/test/ModuleInterface/BadStdlib.swiftinterface @@ -16,4 +16,4 @@ import ClangMod public func useHasPointer(_: HasPointer) // FIXME: SR-14489 -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc diff --git a/test/ModuleInterface/swift_build_sdk_interfaces/compiler-crash.test-sh b/test/ModuleInterface/swift_build_sdk_interfaces/compiler-crash.test-sh index 73b53dcc6ab27..e17a48e34f491 100644 --- a/test/ModuleInterface/swift_build_sdk_interfaces/compiler-crash.test-sh +++ b/test/ModuleInterface/swift_build_sdk_interfaces/compiler-crash.test-sh @@ -1,5 +1,5 @@ # For its Windows counterpart, see compiler-crash-windows.test-sh -UNSUPPORTED: windows +UNSUPPORTED: OS=windows-msvc RUN: not %swift_build_sdk_interfaces -sdk %S/Inputs/mock-sdk/ -o %t/output -debug-crash-compiler 2>&1 | %FileCheck %s diff --git a/test/Prototypes/CollectionTransformers.swift b/test/Prototypes/CollectionTransformers.swift index 84dcafe4c04c6..e3a405c78486b 100644 --- a/test/Prototypes/CollectionTransformers.swift +++ b/test/Prototypes/CollectionTransformers.swift @@ -200,7 +200,7 @@ import Darwin import Dispatch // FIXME: port to Linux. -// XFAIL: linux, windows, openbsd +// XFAIL: OS=linux-gnu, OS=windows-msvc, OS=openbsd // A wrapper for pthread_t with platform-independent interface. public struct _stdlib_pthread_t : Equatable, Hashable { diff --git a/test/Reflection/box_descriptors.sil b/test/Reflection/box_descriptors.sil index 1c0392b6972dc..641eab38e4178 100644 --- a/test/Reflection/box_descriptors.sil +++ b/test/Reflection/box_descriptors.sil @@ -3,10 +3,10 @@ // RUN: %target-swift-reflection-dump -binary-filename %t/capture_descriptors%{target-shared-library-suffix} | %FileCheck %s // SR-10758 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // SR-12893 -// XFAIL: openbsd +// XFAIL: OS=openbsd sil_stage canonical diff --git a/test/Reflection/capture_descriptors.sil b/test/Reflection/capture_descriptors.sil index ef71fc31dc682..75d99f22138ea 100644 --- a/test/Reflection/capture_descriptors.sil +++ b/test/Reflection/capture_descriptors.sil @@ -2,7 +2,7 @@ // REQUIRES: no_asan // SR-12893 -// XFAIL: openbsd +// XFAIL: OS=openbsd // UNSUPPORTED: OS=linux-android, OS=linux-androideabi // RUN: %empty-directory(%t) diff --git a/test/Reflection/conformance_descriptors.swift b/test/Reflection/conformance_descriptors.swift index 91caa8cc2351a..f6d6fc65aad34 100644 --- a/test/Reflection/conformance_descriptors.swift +++ b/test/Reflection/conformance_descriptors.swift @@ -1,4 +1,4 @@ -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // Temporarily disable on AArch64 Linux (rdar://88451721) // UNSUPPORTED: OS=linux-gnu && CPU=aarch64 diff --git a/test/Reflection/typeref_decoding_imported.swift b/test/Reflection/typeref_decoding_imported.swift index 4d2c7bcc8a75b..de550812f7ba3 100644 --- a/test/Reflection/typeref_decoding_imported.swift +++ b/test/Reflection/typeref_decoding_imported.swift @@ -1,7 +1,7 @@ // XFAIL: OS=windows-msvc // SR-12893 -// XFAIL: openbsd +// XFAIL: OS=openbsd // RUN: %empty-directory(%t) diff --git a/test/SILOptimizer/addr_escape_info.sil b/test/SILOptimizer/addr_escape_info.sil index 2bc43557ec89e..0f6c069cec95a 100644 --- a/test/SILOptimizer/addr_escape_info.sil +++ b/test/SILOptimizer/addr_escape_info.sil @@ -3,7 +3,7 @@ // REQUIRES: swift_in_compiler // rdar92963081 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu sil_stage canonical diff --git a/test/SILOptimizer/escape_info.sil b/test/SILOptimizer/escape_info.sil index f51e6022f0d46..8503be891ce3f 100644 --- a/test/SILOptimizer/escape_info.sil +++ b/test/SILOptimizer/escape_info.sil @@ -3,7 +3,7 @@ // REQUIRES: swift_in_compiler // rdar92963081 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu sil_stage canonical diff --git a/test/SILOptimizer/no-external-defs-onone.sil b/test/SILOptimizer/no-external-defs-onone.sil index 046df6f55074f..a7230a8105811 100644 --- a/test/SILOptimizer/no-external-defs-onone.sil +++ b/test/SILOptimizer/no-external-defs-onone.sil @@ -7,7 +7,7 @@ // CHECK-NOT: public_external_unused_test // TODO: update check line for the hidden_external_test for Windows. -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc sil public_external [serialized] @public_external_test : $@convention(thin) () -> () { %0 = tuple() diff --git a/test/SILOptimizer/ranges.sil b/test/SILOptimizer/ranges.sil index f28e4a5d2c896..ee34a648f64e3 100644 --- a/test/SILOptimizer/ranges.sil +++ b/test/SILOptimizer/ranges.sil @@ -3,7 +3,7 @@ // REQUIRES: swift_in_compiler // rdar92963081 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu sil_stage canonical diff --git a/test/Sanitizers/asan/recover.swift b/test/Sanitizers/asan/recover.swift index ee879e0f7dee5..d858c333f4298 100644 --- a/test/Sanitizers/asan/recover.swift +++ b/test/Sanitizers/asan/recover.swift @@ -1,6 +1,6 @@ // REQUIRES: executable_test // REQUIRES: asan_runtime -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // Check with recovery instrumentation and the runtime option to continue execution. // RUN: %target-swiftc_driver %s -target %sanitizers-target-triple -g -sanitize=address -sanitize-recover=address -import-objc-header %S/asan_interface.h -emit-ir -o %t.asan_recover.ll diff --git a/test/Sanitizers/tsan/actor_counters.swift b/test/Sanitizers/tsan/actor_counters.swift index 9cf11f4a98964..4fd7d86140daa 100644 --- a/test/Sanitizers/tsan/actor_counters.swift +++ b/test/Sanitizers/tsan/actor_counters.swift @@ -5,8 +5,8 @@ // REQUIRES: libdispatch // REQUIRES: tsan_runtime // UNSUPPORTED: use_os_stdlib -// UNSUPPORTED: linux -// UNSUPPORTED: windows +// UNSUPPORTED: OS=linux-gnu +// UNSUPPORTED: OS=windows-msvc // REQUIRES: rdar83246843 diff --git a/test/Sanitizers/tsan/objc_async.swift b/test/Sanitizers/tsan/objc_async.swift index 50ee8ce60b5b4..1e5e58696c3ec 100644 --- a/test/Sanitizers/tsan/objc_async.swift +++ b/test/Sanitizers/tsan/objc_async.swift @@ -7,8 +7,8 @@ // REQUIRES: concurrency // REQUIRES: objc_interop // REQUIRES: tsan_runtime -// UNSUPPORTED: linux -// UNSUPPORTED: windows +// UNSUPPORTED: OS=linux-gnu +// UNSUPPORTED: OS=windows-msvc // rdar://76038845 // UNSUPPORTED: use_os_stdlib diff --git a/test/decl/result_builder_fixits.swift b/test/decl/result_builder_fixits.swift index 9c49ff29d6d3d..2a1584e4c3d57 100644 --- a/test/decl/result_builder_fixits.swift +++ b/test/decl/result_builder_fixits.swift @@ -1,5 +1,5 @@ // RUN: %target-typecheck-verify-swift -disable-availability-checking -// UNSUPPORTED: windows +// UNSUPPORTED: OS=windows-msvc // Line-feeds in Fix-Its fail to check on Windows. @resultBuilder diff --git a/test/multifile/protocol-conformance-redundant.swift b/test/multifile/protocol-conformance-redundant.swift index 05f87440cde59..f27a8a346b5d6 100644 --- a/test/multifile/protocol-conformance-redundant.swift +++ b/test/multifile/protocol-conformance-redundant.swift @@ -6,7 +6,7 @@ // RUN: %target-run %t/main %t/%target-library-name(Def) %t/%target-library-name(Ext) 2>&1 | %FileCheck %s // REQUIRES: executable_test -// XFAIL: windows +// XFAIL: OS=windows-msvc // CHECK: Warning: 'main.Sub' conforms to protocol 'Hello', but it also inherits conformance from 'Def.Super'. Relying on a particular conformance is undefined behaviour. // CHECK: Hello diff --git a/test/stdlib/simd_diagnostics.swift b/test/stdlib/simd_diagnostics.swift index 44fa7da18625e..03f7ce260f214 100644 --- a/test/stdlib/simd_diagnostics.swift +++ b/test/stdlib/simd_diagnostics.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift // FIXME: No simd module on linux rdar://problem/20795411 -// XFAIL: linux, windows, openbsd +// XFAIL: OS=linux-gnu, OS=windows-msvc, OS=openbsd // XFAIL: OS=wasi import simd diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 360790a651285..b86e6201391bb 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -2,7 +2,7 @@ // RUN: %gyb %s > %t/main.swift // https://bugs.swift.org/browse/SR-14460 -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // The compiler should finish in less than 1 minute. To give some slack, // specify a timeout of 5 minutes. diff --git a/validation-test/Sema/type_checker_perf/fast/rdar23620262.swift b/validation-test/Sema/type_checker_perf/fast/rdar23620262.swift index 3f503115680aa..fdd04f1b2b283 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar23620262.swift +++ b/validation-test/Sema/type_checker_perf/fast/rdar23620262.swift @@ -1,7 +1,7 @@ // RUN: %target-typecheck-verify-swift -solver-expression-time-threshold=1 // REQUIRES: tools-release,no_asan -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu // expected-no-diagnostics diff --git a/validation-test/Sema/type_checker_perf/fast/rdar54580427.swift b/validation-test/Sema/type_checker_perf/fast/rdar54580427.swift index faac1e377ff9b..a53909ab0ec96 100644 --- a/validation-test/Sema/type_checker_perf/fast/rdar54580427.swift +++ b/validation-test/Sema/type_checker_perf/fast/rdar54580427.swift @@ -1,7 +1,7 @@ // RUN: %scale-test --begin 1 --end 20 --step 1 --select NumLeafScopes %s -Xfrontend=-solver-expression-time-threshold=1 // REQUIRES: asserts,no_asan -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu enum Val { case d([String: Val]) diff --git a/validation-test/execution/dsohandle-multi-module.swift b/validation-test/execution/dsohandle-multi-module.swift index 3a7f98c2b2c5a..bda5819b0102f 100644 --- a/validation-test/execution/dsohandle-multi-module.swift +++ b/validation-test/execution/dsohandle-multi-module.swift @@ -8,7 +8,7 @@ // REQUIRES: executable_test -// UNSUPPORTED: linux +// UNSUPPORTED: OS=linux-gnu import first import second diff --git a/validation-test/stdlib/SIMDParameterPassing.swift.gyb b/validation-test/stdlib/SIMDParameterPassing.swift.gyb index 5cf58db6c77e6..d2ed07df5ca00 100644 --- a/validation-test/stdlib/SIMDParameterPassing.swift.gyb +++ b/validation-test/stdlib/SIMDParameterPassing.swift.gyb @@ -18,7 +18,7 @@ // REQUIRES: executable_test // REQUIRES: long_test -// XFAIL: linux +// XFAIL: OS=linux-gnu import StdlibUnittest import simd From 20e0e1542a3fdcb4656c2986fdad72f16d00a045 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Thu, 12 May 2022 14:47:11 -0700 Subject: [PATCH 07/53] [dbg-info][move-function] Add DWARF filecheck lines for conditional control flow tests. --- .../move_function_dbginfo_async.swift | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/test/DebugInfo/move_function_dbginfo_async.swift b/test/DebugInfo/move_function_dbginfo_async.swift index d451952f9ab72..721c592bc52e0 100644 --- a/test/DebugInfo/move_function_dbginfo_async.swift +++ b/test/DebugInfo/move_function_dbginfo_async.swift @@ -342,6 +342,45 @@ public func varSimpleTestVar() async { // This is the continuation block // CHECK-LABEL: define internal swifttailcc void @"$s27move_function_dbginfo_async20letArgCCFlowTrueTestyyxnYalFTQ4_"( // CHECK: call void @llvm.dbg.value(metadata %swift.opaque* undef, metadata !{{.*}}, metadata !DIExpression(DW_OP_deref)), + +// DWARF: DW_TAG_subprogram +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalF") +// DWARF: DW_AT_name ("letArgCCFlowTrueTest") + +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x8, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalFTQ0_") +// DWARF-NEXT: DW_AT_name ("letArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (DW_OP_entry_value([[ASYNC_REG]]), DW_OP_deref, DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x8, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalFTY1_") +// DWARF-NEXT: DW_AT_name ("letArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x8, DW_OP_deref +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x8, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalFTQ2_") +// DWARF-NEXT: DW_AT_name ("letArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalFTQ3_") +// DWARF-NEXT: DW_AT_name ("letArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_deref, DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x8, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20letArgCCFlowTrueTestyyxnYalFTQ4_") +// DWARF-NEXT: DW_AT_name ("letArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_name ("msg") public func letArgCCFlowTrueTest(_ msg: __owned T) async { await forceSplit1() if trueValue { @@ -441,6 +480,58 @@ public func letArgCCFlowTrueTest(_ msg: __owned T) async { // CHECK: musttail call swifttailcc void %{{[0-9]+}}(%swift.context* swiftasync // CHECK-NEXT: ret void, // CHECK-NEXT: } + +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlF") +// DWARF: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ0_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (DW_OP_entry_value([[ASYNC_REG]]), DW_OP_deref, DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY1_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ2_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY3_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ4_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_deref, DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTY5_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (0x{{[a-f0-9]+}}: +// DWARF-NEXT: [0x{{[a-f0-9]+}}, 0x{{[a-f0-9]+}}): DW_OP_entry_value([[ASYNC_REG]]), DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") +// +// DWARF: DW_AT_linkage_name ("$s3out20varArgCCFlowTrueTestyyxzYaAA1PRzlFTQ6_") +// DWARF-NEXT: DW_AT_name ("varArgCCFlowTrueTest") +// DWARF: DW_TAG_formal_parameter +// DWARF-NEXT: DW_AT_location (DW_OP_entry_value([[ASYNC_REG]]), DW_OP_deref, DW_OP_plus_uconst 0x10, DW_OP_plus_uconst 0x30, DW_OP_deref) +// DWARF-NEXT: DW_AT_name ("msg") public func varArgCCFlowTrueTest(_ msg: inout T) async { await forceSplit1() if trueValue { From e9c14cd88b325f589c8a9dba4d92874aa9d1cacb Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 23 May 2022 19:43:51 -0700 Subject: [PATCH 08/53] [ASTPrinter] Print the desugared constraint type following the 'any' keyword. --- lib/AST/ASTPrinter.cpp | 7 ++++++- test/ModuleInterface/existential-any.swift | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 67600e3bc2262..abb43dc16f040 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -6211,7 +6211,12 @@ class TypePrinter : public TypeVisitor { if (Options.PrintExplicitAny) Printer << "any "; - visit(T->getConstraintType()); + // FIXME: The desugared type is used here only to support + // existential types with protocol typealiases in Swift + // interfaces. Verifying that the underlying type of a + // protocol typealias is a constriant type is fundamentally + // circular, so the desugared type should be written in source. + visit(T->getConstraintType()->getDesugaredType()); } void visitLValueType(LValueType *T) { diff --git a/test/ModuleInterface/existential-any.swift b/test/ModuleInterface/existential-any.swift index 69c49a3cd7e6a..8b475e58f570b 100644 --- a/test/ModuleInterface/existential-any.swift +++ b/test/ModuleInterface/existential-any.swift @@ -38,3 +38,11 @@ public struct S { // CHECK: public var q: any main.Q public var q: any Q } + + +public protocol ProtocolTypealias { + typealias A = P +} + +// CHECK: public func dependentExistential(value: (T) -> any main.P) where T : main.ProtocolTypealias +public func dependentExistential(value: (T) -> T.A) {} From dd4cdfb653e8105fb36baac7fee0a6edad299f83 Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Mon, 23 May 2022 17:47:54 -0700 Subject: [PATCH 09/53] [C++-Interop] Fix EffectiveClangContext for NS_OPTIONS EnumDecl lookup. This patch fixes an issue with C++-Interop that has been making it so that enums under interop were not getting properly looked up and therefore not getting imported. The reason for this was that the proper DeclContext was not getting applied when grabbing the decls use by VisitDecls later in the ClangImporter. The lookup code at SwiftLookupTable::lookup is given a clang TU which is what implcitly gets turned into an EffectiveClangContext. The EffectiveClangContext is the piece that decides which DeclContext to use. In the case of an extern "C" (ie LinkageSpecDecl), the EffectiveClangContext was not traversing inside the lexical scope of the extern "C" as the context for searching the EnumDecl (the NS_OPTIONS Enum). This patch adds new behavior when EffectiveClangContext is given a LinkageSpecDecl. It sets the DeclContext to the lexical decl context. With this fix in place in the presence of C++-Interop we not only import the NS_OPTIONS typedef properly, but we also import the enum (and therefore the EnumConstants) correctly (which are used for getting to the flags for populating the NS_OPTIONS bitfields. --- lib/ClangImporter/SwiftLookupTable.h | 3 ++ .../Cxx/enum/Inputs/c-enums-NS_OPTIONS.h | 29 +++++++++++++++++++ test/Interop/Cxx/enum/Inputs/module.modulemap | 5 ++++ .../Interop/Cxx/enum/c-enums-NS_OPTIONS.swift | 22 ++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h create mode 100644 test/Interop/Cxx/enum/c-enums-NS_OPTIONS.swift diff --git a/lib/ClangImporter/SwiftLookupTable.h b/lib/ClangImporter/SwiftLookupTable.h index e132b135cd0fa..99f81be41834b 100644 --- a/lib/ClangImporter/SwiftLookupTable.h +++ b/lib/ClangImporter/SwiftLookupTable.h @@ -21,6 +21,7 @@ #include "swift/Basic/LLVM.h" #include "swift/AST/Identifier.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ModuleFileExtension.h" @@ -197,6 +198,8 @@ class EffectiveClangContext { DC = omDecl->getCanonicalDecl(); } else if (auto fDecl = dyn_cast(dc)) { DC = fDecl->getCanonicalDecl(); + } else if (auto externCDecl = dyn_cast(dc)) { + DC = externCDecl->getLexicalDeclContext(); } else { assert(isa(dc) || isa(dc) || diff --git a/test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h b/test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h new file mode 100644 index 0000000000000..252bc96627b16 --- /dev/null +++ b/test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h @@ -0,0 +1,29 @@ +// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS +// does things. + +#if __has_attribute(enum_extensibility) +#define __CF_ENUM_ATTRIBUTES __attribute__((enum_extensibility(open))) +#define __CF_CLOSED_ENUM_ATTRIBUTES __attribute__((enum_extensibility(closed))) +#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open))) +#else +#define __CF_ENUM_ATTRIBUTES +#define __CF_CLOSED_ENUM_ATTRIBUTES +#define __CF_OPTIONS_ATTRIBUTES +#endif + +// explicitly use extern "C" rather than setting it in the modulemap file as +// would be the case with Foundation's modulemap. +extern "C" { + +#define CF_OPTIONS(_type, _name) _type __attribute__((availability(swift, unavailable))) _name; enum __CF_OPTIONS_ATTRIBUTES : _name +#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name) + +typedef unsigned long NSUInteger; + +typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) { + NSBinarySearchingFirstEqual = (1UL << 8), + NSBinarySearchingLastEqual = (1UL << 9), + NSBinarySearchingInsertionIndex = (1UL << 10), +}; + +} \ No newline at end of file diff --git a/test/Interop/Cxx/enum/Inputs/module.modulemap b/test/Interop/Cxx/enum/Inputs/module.modulemap index 5bbdebe622303..ef4d86f2bfef8 100644 --- a/test/Interop/Cxx/enum/Inputs/module.modulemap +++ b/test/Interop/Cxx/enum/Inputs/module.modulemap @@ -17,3 +17,8 @@ module CenumsWithOptionsOmit { header "c-enums-withOptions-omit.h" requires cplusplus } + +module CenumsNSOptions { + header "c-enums-NS_OPTIONS.h" + requires cplusplus +} \ No newline at end of file diff --git a/test/Interop/Cxx/enum/c-enums-NS_OPTIONS.swift b/test/Interop/Cxx/enum/c-enums-NS_OPTIONS.swift new file mode 100644 index 0000000000000..6b7efc355ceef --- /dev/null +++ b/test/Interop/Cxx/enum/c-enums-NS_OPTIONS.swift @@ -0,0 +1,22 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=CenumsNSOptions -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s +// REQUIRES: objc_interop + +import CenumsNSOptions + +// CHECK: typealias NSBinarySearchingOptions = UInt +// CHECK-NEXT: struct NSBinarySearchingOptions : OptionSet, @unchecked Sendable { +// CHECK-NEXT: init(rawValue: UInt) +// CHECK-NEXT: let rawValue: UInt +// CHECK-NEXT: typealias RawValue = UInt +// CHECK-NEXT: typealias Element = NSBinarySearchingOptions +// CHECK-NEXT: typealias ArrayLiteralElement = NSBinarySearchingOptions +// CHECK-NEXT: static var firstEqual: NSBinarySearchingOptions { get } +// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "firstEqual") +// CHECK-NEXT: static var FirstEqual: NSBinarySearchingOptions { get } +// CHECK-NEXT: static var lastEqual: NSBinarySearchingOptions { get } +// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "lastEqual") +// CHECK-NEXT: static var LastEqual: NSBinarySearchingOptions { get } +// CHECK-NEXT: static var insertionIndex: NSBinarySearchingOptions { get } +// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "insertionIndex") +// CHECK-NEXT: static var InsertionIndex: NSBinarySearchingOptions { get } +// CHECK-NEXT: } From 7687a63dcf1acf03fea0c850614888ddcdeade6d Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Fri, 20 May 2022 11:01:30 -0700 Subject: [PATCH 10/53] Sema: Use the availability of the extended nominal as a floor for the availability of extensions. The primary motivation for this change is to reduce unnecessary availability diagnostics for API library authors. Many API libraries contain existing extension decls that lack declared availability where the extension introduces additional members to the extended type in the same release that the extended type was declared. Others contain extensions where the extension itself does not have declared availability but each of the members do. In both cases, the code is safe as written so the extra diagnostics would be a nuisance. Resolves rdar://93630782 --- include/swift/AST/Availability.h | 27 ++- include/swift/AST/TypeRefinementContext.h | 29 ++- lib/AST/TypeRefinementContext.cpp | 14 +- lib/Sema/TypeCheckAccess.cpp | 15 +- lib/Sema/TypeCheckAvailability.cpp | 131 ++++++---- ...inement_contexts_target_min_inlining.swift | 8 +- ...exts_target_min_inlining_maccatalyst.swift | 2 +- test/attr/attr_inlinable_available.swift | 225 ++++++++++++------ 8 files changed, 289 insertions(+), 162 deletions(-) diff --git a/include/swift/AST/Availability.h b/include/swift/AST/Availability.h index 1639f899ca272..fd3cb83ea341e 100644 --- a/include/swift/AST/Availability.h +++ b/include/swift/AST/Availability.h @@ -93,6 +93,18 @@ class VersionRange { return getLowerEndpoint() >= Other.getLowerEndpoint(); } + // Returns true if all the versions in the Other range are versions in this + // range and the ranges are not equal. + bool isSupersetOf(const VersionRange &Other) const { + if (isEmpty() || Other.isAll()) + return false; + + if (isAll() || Other.isEmpty()) + return true; + + return getLowerEndpoint() < Other.getLowerEndpoint(); + } + /// Mutates this range to be a best-effort underapproximation of /// the intersection of itself and Other. This is the /// meet operation (greatest lower bound) in the version range lattice. @@ -244,10 +256,17 @@ class AvailabilityContext { /// Returns true if \p other makes stronger guarantees than this context. /// /// That is, `a.isContainedIn(b)` implies `a.union(b) == b`. - bool isContainedIn(AvailabilityContext other) const { + bool isContainedIn(const AvailabilityContext &other) const { return OSVersion.isContainedIn(other.OSVersion); } + /// Returns true if \p other is a strict subset of this context. + /// + /// That is, `a.isSupersetOf(b)` implies `a != b` and `a.union(b) == a`. + bool isSupersetOf(const AvailabilityContext &other) const { + return OSVersion.isSupersetOf(other.OSVersion); + } + /// Returns true if this context has constraints that make it impossible to /// actually occur. /// @@ -272,7 +291,7 @@ class AvailabilityContext { /// /// As an example, this is used when figuring out the required availability /// for a type that references multiple nominal decls. - void intersectWith(AvailabilityContext other) { + void intersectWith(const AvailabilityContext &other) { OSVersion.intersectWith(other.getOSVersion()); } @@ -283,7 +302,7 @@ class AvailabilityContext { /// treating some invalid deployment environments as available. /// /// As an example, this is used for the true branch of `#available`. - void constrainWith(AvailabilityContext other) { + void constrainWith(const AvailabilityContext &other) { OSVersion.constrainWith(other.getOSVersion()); } @@ -295,7 +314,7 @@ class AvailabilityContext { /// /// As an example, this is used for the else branch of a conditional with /// multiple `#available` checks. - void unionWith(AvailabilityContext other) { + void unionWith(const AvailabilityContext &other) { OSVersion.unionWith(other.getOSVersion()); } diff --git a/include/swift/AST/TypeRefinementContext.h b/include/swift/AST/TypeRefinementContext.h index 6b42ed83c429c..dbe492476b8b7 100644 --- a/include/swift/AST/TypeRefinementContext.h +++ b/include/swift/AST/TypeRefinementContext.h @@ -54,15 +54,19 @@ class TypeRefinementContext : public ASTAllocated { /// The root refinement context. Root, - /// The context was introduced by a declaration (e.g., the body of a - /// function declaration or the contents of a class declaration). + /// The context was introduced by a declaration with an explicit + /// availability attribute. The context contains both the signature and the + /// body of the declaration. Decl, - /// The context was introduced by an API boundary; that is, we are in - /// a module with library evolution enabled and the parent context's - /// contents can be visible to the module's clients, but this context's - /// contents are not. - APIBoundary, + /// The context was introduced implicitly by a declaration. The context may + /// cover the entire declaration or it may cover a subset of it. For + /// example, a public, non-inlinable function declaration in an API module + /// will have at least two associated contexts: one for the entire + /// declaration at the declared availability of the API and a nested + /// implicit context for the body of the function, which will always run at + /// the deployment target of the library. + DeclImplicit, /// The context was introduced for the Then branch of an IfStmt. IfStmtThenBranch, @@ -131,7 +135,8 @@ class TypeRefinementContext : public ASTAllocated { } Decl *getAsDecl() const { - assert(IntroReason == Reason::Decl || IntroReason == Reason::APIBoundary); + assert(IntroReason == Reason::Decl || + IntroReason == Reason::DeclImplicit); return D; } @@ -163,8 +168,8 @@ class TypeRefinementContext : public ASTAllocated { SourceRange SrcRange; - /// A canonical availability info for this context, computed top-down from the root - /// context (compilation deployment target). + /// A canonical availability info for this context, computed top-down from the + /// root context. AvailabilityContext AvailabilityInfo; /// If this context was annotated with an availability attribute, this property captures that. @@ -194,8 +199,8 @@ class TypeRefinementContext : public ASTAllocated { /// Create a refinement context for the given declaration. static TypeRefinementContext * - createForAPIBoundary(ASTContext &Ctx, Decl *D, TypeRefinementContext *Parent, - const AvailabilityContext &Info, SourceRange SrcRange); + createForDeclImplicit(ASTContext &Ctx, Decl *D, TypeRefinementContext *Parent, + const AvailabilityContext &Info, SourceRange SrcRange); /// Create a refinement context for the Then branch of the given IfStmt. static TypeRefinementContext * diff --git a/lib/AST/TypeRefinementContext.cpp b/lib/AST/TypeRefinementContext.cpp index d0ab3efb043ba..08c21dfee9910 100644 --- a/lib/AST/TypeRefinementContext.cpp +++ b/lib/AST/TypeRefinementContext.cpp @@ -64,13 +64,13 @@ TypeRefinementContext::createForDecl(ASTContext &Ctx, Decl *D, TypeRefinementContext(Ctx, D, Parent, SrcRange, Info, ExplicitInfo); } -TypeRefinementContext *TypeRefinementContext::createForAPIBoundary( +TypeRefinementContext *TypeRefinementContext::createForDeclImplicit( ASTContext &Ctx, Decl *D, TypeRefinementContext *Parent, const AvailabilityContext &Info, SourceRange SrcRange) { assert(D); assert(Parent); return new (Ctx) TypeRefinementContext( - Ctx, IntroNode(D, Reason::APIBoundary), Parent, SrcRange, Info, + Ctx, IntroNode(D, Reason::DeclImplicit), Parent, SrcRange, Info, AvailabilityContext::alwaysAvailable()); } @@ -180,7 +180,7 @@ void TypeRefinementContext::dump(raw_ostream &OS, SourceManager &SrcMgr) const { SourceLoc TypeRefinementContext::getIntroductionLoc() const { switch (getReason()) { case Reason::Decl: - case Reason::APIBoundary: + case Reason::DeclImplicit: return Node.getAsDecl()->getLoc(); case Reason::IfStmtThenBranch: @@ -294,7 +294,7 @@ TypeRefinementContext::getAvailabilityConditionVersionSourceRange( Node.getAsWhileStmt()->getCond(), Platform, Version); case Reason::Root: - case Reason::APIBoundary: + case Reason::DeclImplicit: return SourceRange(); } @@ -308,7 +308,7 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr, OS << " versions=" << AvailabilityInfo.getOSVersion().getAsString(); - if (getReason() == Reason::Decl || getReason() == Reason::APIBoundary) { + if (getReason() == Reason::Decl || getReason() == Reason::DeclImplicit) { Decl *D = Node.getAsDecl(); OS << " decl="; if (auto VD = dyn_cast(D)) { @@ -350,8 +350,8 @@ StringRef TypeRefinementContext::getReasonName(Reason R) { case Reason::Decl: return "decl"; - case Reason::APIBoundary: - return "api_boundary"; + case Reason::DeclImplicit: + return "decl_implicit"; case Reason::IfStmtThenBranch: return "if_then"; diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 437db59565502..31dfc556efc61 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1850,21 +1850,8 @@ class DeclAvailabilityChecker : public DeclVisitor { }); Where = wasWhere.withExported(hasExportedMembers); - - // When diagnosing potential unavailability of the extended type, downgrade - // the diagnostics to warnings when the extension decl has no declared - // availability and the required availability is more than the deployment - // target. - DeclAvailabilityFlags extendedTypeFlags = None; - auto annotatedRange = - AvailabilityInference::annotatedAvailableRange(ED, ED->getASTContext()); - if (!annotatedRange.hasValue()) - extendedTypeFlags |= DeclAvailabilityFlag:: - WarnForPotentialUnavailabilityBeforeDeploymentTarget; - checkType(ED->getExtendedType(), ED->getExtendedTypeRepr(), ED, - ExportabilityReason::ExtensionWithPublicMembers, - extendedTypeFlags); + ExportabilityReason::ExtensionWithPublicMembers); // 3) If the extension contains exported members or defines conformances, // the 'where' clause must only name exported types. diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 377a29ae2381c..8734085287d10 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -460,6 +460,9 @@ class TypeRefinementContextBuilder : private ASTWalker { // Adds in a TRC that covers the entire declaration. if (auto DeclTRC = getNewContextForSignatureOfDecl(D)) { pushContext(DeclTRC, D); + + // Possibly use this as an effective parent context later. + recordEffectiveParentContext(D, DeclTRC); } // Create TRCs that cover only the body of the declaration. @@ -542,46 +545,63 @@ class TypeRefinementContextBuilder : private ASTWalker { return nullptr; } - // A decl only introduces a new context when it either has explicit - // availability or requires the deployment target. - bool HasExplicitAvailability = hasActiveAvailableAttribute(D, Context); - bool ConstrainToDeploymentTarget = - shouldConstrainSignatureToDeploymentTarget(D); - if (!HasExplicitAvailability && !ConstrainToDeploymentTarget) - return nullptr; + // Declarations with an explicit availability attribute always get a TRC. + if (hasActiveAvailableAttribute(D, Context)) { + AvailabilityContext DeclaredAvailability = + swift::AvailabilityInference::availableRange(D, Context); - // We require a valid range in order to be able to query for the TRC - // corresponding to a given SourceLoc. - // If this assert fires, it means we have probably synthesized an implicit - // declaration without location information. The appropriate fix is - // probably to gin up a source range for the declaration when synthesizing - // it. - assert(D->getSourceRange().isValid()); + return TypeRefinementContext::createForDecl( + Context, D, getCurrentTRC(), + getEffectiveAvailabilityForDeclSignature(D, DeclaredAvailability), + DeclaredAvailability, refinementSourceRangeForDecl(D)); + } - // The potential versions in the declaration are constrained by both - // the declared availability of the declaration and the potential versions - // of its lexical context. - AvailabilityContext ExplicitDeclInfo = - swift::AvailabilityInference::availableRange(D, Context); - AvailabilityContext DeclInfo = ExplicitDeclInfo; - DeclInfo.intersectWith(getCurrentTRC()->getAvailabilityInfo()); - - if (ConstrainToDeploymentTarget) - DeclInfo.intersectWith(AvailabilityContext::forDeploymentTarget(Context)); - - SourceRange Range = refinementSourceRangeForDecl(D); - TypeRefinementContext *NewTRC; - if (HasExplicitAvailability) - NewTRC = TypeRefinementContext::createForDecl( - Context, D, getCurrentTRC(), DeclInfo, ExplicitDeclInfo, Range); - else - NewTRC = TypeRefinementContext::createForAPIBoundary( - Context, D, getCurrentTRC(), DeclInfo, Range); + // Declarations without explicit availability get a TRC if they are + // effectively less available than the surrounding context. For example, an + // internal property in a public struct can be effectively less available + // than the containing struct decl because the internal property will only + // be accessed by code running at the deployment target or later. + AvailabilityContext CurrentAvailability = + getCurrentTRC()->getAvailabilityInfo(); + AvailabilityContext EffectiveAvailability = + getEffectiveAvailabilityForDeclSignature(D, CurrentAvailability); + if (CurrentAvailability.isSupersetOf(EffectiveAvailability)) + return TypeRefinementContext::createForDeclImplicit( + Context, D, getCurrentTRC(), EffectiveAvailability, + refinementSourceRangeForDecl(D)); + + return nullptr; + } - // Possibly use this as an effective parent context later. - recordEffectiveParentContext(D, NewTRC); + AvailabilityContext getEffectiveAvailabilityForDeclSignature( + Decl *D, const AvailabilityContext BaseAvailability) { + AvailabilityContext EffectiveAvailability = BaseAvailability; + + // As a special case, extension decls are treated as effectively as + // available as the nominal type they extend, up to the deployment target. + // This rule is a convenience for library authors who have written + // extensions without specifying availabilty on the extension itself. + if (auto *ED = dyn_cast(D)) { + auto *Nominal = ED->getExtendedNominal(); + if (Nominal && !hasActiveAvailableAttribute(D, Context)) { + EffectiveAvailability.intersectWith( + swift::AvailabilityInference::availableRange(Nominal, Context)); + + // We want to require availability to be specified on extensions of + // types that would be potentially unavailable to the module containing + // the extension, so limit the effective availability to the deployment + // target. + EffectiveAvailability.unionWith( + AvailabilityContext::forDeploymentTarget(Context)); + } + } - return NewTRC; + EffectiveAvailability.intersectWith(getCurrentTRC()->getAvailabilityInfo()); + if (shouldConstrainSignatureToDeploymentTarget(D)) + EffectiveAvailability.intersectWith( + AvailabilityContext::forDeploymentTarget(Context)); + + return EffectiveAvailability; } /// Checks whether the entire declaration, including its signature, should be @@ -607,6 +627,14 @@ class TypeRefinementContextBuilder : private ASTWalker { /// provides a convenient place to specify the refined range when it is /// different than the declaration's source range. SourceRange refinementSourceRangeForDecl(Decl *D) { + // We require a valid range in order to be able to query for the TRC + // corresponding to a given SourceLoc. + // If this assert fires, it means we have probably synthesized an implicit + // declaration without location information. The appropriate fix is + // probably to gin up a source range for the declaration when synthesizing + // it. + assert(D->getSourceRange().isValid()); + if (auto *storageDecl = dyn_cast(D)) { // Use the declaration's availability for the context when checking // the bodies of its accessors. @@ -642,25 +670,26 @@ class TypeRefinementContextBuilder : private ASTWalker { return D->getSourceRange(); } - TypeRefinementContext *createAPIBoundaryContext(Decl *D, SourceRange range) { - AvailabilityContext DeploymentTargetInfo = - AvailabilityContext::forDeploymentTarget(Context); - DeploymentTargetInfo.intersectWith(getCurrentTRC()->getAvailabilityInfo()); - - return TypeRefinementContext::createForAPIBoundary( - Context, D, getCurrentTRC(), DeploymentTargetInfo, range); - } - void buildContextsForBodyOfDecl(Decl *D) { // Are we already constrained by the deployment target? If not, adding // new contexts won't change availability. if (isCurrentTRCContainedByDeploymentTarget()) return; + // A lambda that creates an implicit decl TRC specifying the deployment + // target for `range` in decl `D`. + auto createContext = [this](Decl *D, SourceRange range) { + AvailabilityContext Availability = + AvailabilityContext::forDeploymentTarget(Context); + Availability.intersectWith(getCurrentTRC()->getAvailabilityInfo()); + + return TypeRefinementContext::createForDeclImplicit( + Context, D, getCurrentTRC(), Availability, range); + }; + // Top level code always uses the deployment target. if (auto tlcd = dyn_cast(D)) { - auto *topLevelTRC = - createAPIBoundaryContext(tlcd, tlcd->getSourceRange()); + auto *topLevelTRC = createContext(tlcd, tlcd->getSourceRange()); pushContext(topLevelTRC, D); return; } @@ -670,8 +699,7 @@ class TypeRefinementContextBuilder : private ASTWalker { if (auto afd = dyn_cast(D)) { if (!afd->isImplicit() && afd->getBodySourceRange().isValid() && afd->getResilienceExpansion() != ResilienceExpansion::Minimal) { - auto *functionBodyTRC = - createAPIBoundaryContext(afd, afd->getBodySourceRange()); + auto *functionBodyTRC = createContext(afd, afd->getBodySourceRange()); pushContext(functionBodyTRC, D); } return; @@ -693,8 +721,7 @@ class TypeRefinementContextBuilder : private ASTWalker { // Create a TRC for the init written in the source. The ASTWalker // won't visit these expressions so instead of pushing these onto the // stack we build them directly. - auto *initTRC = - createAPIBoundaryContext(vd, initExpr->getSourceRange()); + auto *initTRC = createContext(vd, initExpr->getSourceRange()); TypeRefinementContextBuilder(initTRC, Context).build(initExpr); } @@ -710,7 +737,7 @@ class TypeRefinementContextBuilder : private ASTWalker { // example, property wrapper initializers that takes block arguments // are not handled correctly because of this (rdar://77841331). for (auto *wrapper : vd->getAttachedPropertyWrappers()) { - createAPIBoundaryContext(vd, wrapper->getRange()); + createContext(vd, wrapper->getRange()); } } diff --git a/test/Sema/availability_refinement_contexts_target_min_inlining.swift b/test/Sema/availability_refinement_contexts_target_min_inlining.swift index 321386501ed1b..e07c00057f5d7 100644 --- a/test/Sema/availability_refinement_contexts_target_min_inlining.swift +++ b/test/Sema/availability_refinement_contexts_target_min_inlining.swift @@ -11,8 +11,8 @@ // CHECK-tvos: {{^}}(root versions=[9.0,+Inf) // CHECK-watchos: {{^}}(root versions=[2.0,+Inf) -// CHECK-macosx-NEXT: {{^}} (api_boundary versions=[10.15.0,+Inf) decl=foo() -// CHECK-ios-NEXT: {{^}} (api_boundary versions=[13.0.0,+Inf) decl=foo() -// CHECK-tvos-NEXT: {{^}} (api_boundary versions=[13.0.0,+Inf) decl=foo() -// CHECK-watchos-NEXT: {{^}} (api_boundary versions=[6.0.0,+Inf) decl=foo() +// CHECK-macosx-NEXT: {{^}} (decl_implicit versions=[10.15.0,+Inf) decl=foo() +// CHECK-ios-NEXT: {{^}} (decl_implicit versions=[13.0.0,+Inf) decl=foo() +// CHECK-tvos-NEXT: {{^}} (decl_implicit versions=[13.0.0,+Inf) decl=foo() +// CHECK-watchos-NEXT: {{^}} (decl_implicit versions=[6.0.0,+Inf) decl=foo() func foo() {} diff --git a/test/Sema/availability_refinement_contexts_target_min_inlining_maccatalyst.swift b/test/Sema/availability_refinement_contexts_target_min_inlining_maccatalyst.swift index 3b11368547d13..a3e41616fe962 100644 --- a/test/Sema/availability_refinement_contexts_target_min_inlining_maccatalyst.swift +++ b/test/Sema/availability_refinement_contexts_target_min_inlining_maccatalyst.swift @@ -11,5 +11,5 @@ // Verify that -target-min-inlining-version min implies 13.1 on macCatalyst. // CHECK: {{^}}(root versions=[13.1,+Inf) -// CHECK-NEXT: {{^}} (api_boundary versions=[14.4.0,+Inf) decl=foo() +// CHECK-NEXT: {{^}} (decl_implicit versions=[14.4.0,+Inf) decl=foo() func foo() {} diff --git a/test/attr/attr_inlinable_available.swift b/test/attr/attr_inlinable_available.swift index fa4fdcd4cbc1d..85edb1d1ffa74 100644 --- a/test/attr/attr_inlinable_available.swift +++ b/test/attr/attr_inlinable_available.swift @@ -929,120 +929,209 @@ internal struct InternalStruct { // expected-note 2 {{add @available attribute}} // // Extensions are externally visible if they extend a public type and (1) have -// public members or (2) declare a conformance to a public protocol. Externally -// visible extensions should be typechecked with the inlining target. +// public members or (2) declare a conformance to a public protocol. +// +// Extensions without explicit availability that are externally visible use an +// implied floor of either the availability of the extended type or the +// deployment target, whichever is more available. This is a special rule +// designed as a convenience to library authors who have written quite a bit of +// code without annotating availability on their extensions and getting away +// with it because previously the deployment target was always used as the +// floor. +// +// Extensions without explicit availability that are not visible externally are +// checked using an implied floor of the deployment target. // -// OK, NoAvailable is always available, both internally and externally. -extension NoAvailable {} -extension NoAvailable { - public func publicFunc1() {} -} -// OK, no public members and BetweenTargets is always available internally. -extension BetweenTargets {} +// MARK: Extensions on NoAvailable -// OK, no public members and BetweenTargets is always available internally. -extension BetweenTargets { - internal func internalFunc1() {} - private func privateFunc1() {} - fileprivate func fileprivateFunc1() {} -} +extension NoAvailable {} -// expected-warning@+1 {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension BetweenTargets { - public func publicFunc1() {} +extension NoAvailable { // expected-note {{add @available attribute to enclosing extension}} + func internalFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -// expected-warning@+1 {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension BetweenTargets { - @usableFromInline - internal func usableFromInlineFunc1() {} +extension NoAvailable { // expected-note 3 {{add @available attribute to enclosing extension}} + public func publicFuncInExtension( // expected-note 3 {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, // expected-error {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} + _: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}} + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -// expected-warning@+1 {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension BetweenTargets { - internal func internalFunc2() {} - private func privateFunc2() {} - fileprivate func fileprivateFunc2() {} - public func publicFunc2() {} -} +// MARK: Extensions on BetweenTargets -// An extension with more availability than BetweenTargets. -// expected-error@+2 {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} -@available(macOS 10.10, *) -extension BetweenTargets { - public func publicFunc3() {} +extension BetweenTargets {} + +extension BetweenTargets { // expected-note {{add @available attribute to enclosing extension}} + func internalFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -// FIXME: Can we prevent this warning when SPI members are the reason the extension is exported? -// expected-warning@+1 {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension BetweenTargets { - @_spi(Private) - public func spiFunc1() {} +extension BetweenTargets { // expected-note 2 {{add @available attribute to enclosing extension}} + public func publicFuncInExtension( // expected-note 2 {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}} + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -@_spi(Private) +@available(macOS 10.15, *) extension BetweenTargets { - internal func internalFunc3() {} - private func privateFunc3() {} - fileprivate func fileprivateFunc3() {} - public func spiFunc2() {} + public func publicFuncInExtensionWithExplicitAvailability( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -@available(macOS, unavailable) -extension BetweenTargets { - public func inheritsUnavailable( +extension BetweenTargets { // expected-note {{add @available attribute to enclosing extension}} + @available(macOS 10.15, *) + public func publicFuncWithExplicitAvailabilityInExtension( _: NoAvailable, _: BeforeInliningTarget, _: AtInliningTarget, _: BetweenTargets, _: AtDeploymentTarget, - _: AfterDeploymentTarget, - _: Unavailable - ) { } + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } @_spi(Private) -extension BetweenTargets { // expected-note 1 {{add @available attribute to enclosing extension}} - public func inheritsSPINoAvailable( // expected-note 1 {{add @available attribute to enclosing instance method}} +extension BetweenTargets { // expected-note {{add @available attribute to enclosing extension}} + public func inheritedSPIFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} _: NoAvailable, _: BeforeInliningTarget, _: AtInliningTarget, _: BetweenTargets, _: AtDeploymentTarget, _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} - ) { } + ) {} +} + +@available(macOS, unavailable) +extension BetweenTargets { + public func inheritsUnavailableFuncInExtension( + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget, + _: Unavailable + ) {} +} + +// This extension is explicitly more available than BetweenTargets but because +// it only contains internal members, the availability floor is still the +// deployment target. +@available(macOS 10.10, *) +extension BetweenTargets { + func internalFuncInExcessivelyAvailableExtension() {} +} + +extension BetweenTargets { + @available(macOS 10.10, *) + func excessivelyAvailableInternalFuncInExtension() {} } +@available(macOS 10.10, *) +extension BetweenTargets { // expected-error {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} + public func publicFuncInExcessivelyAvailableExtension() {} +} + +// MARK: Extensions on BetweenTargetsInternal + // Same availability as BetweenTargets but internal instead of public. @available(macOS 10.14.5, *) internal struct BetweenTargetsInternal {} -// OK, extensions on internal types are never visible externally. extension BetweenTargetsInternal {} -extension BetweenTargetsInternal { - public func publicFunc() {} + +extension BetweenTargetsInternal { // expected-note {{add @available attribute to enclosing extension}} + func internalFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -// expected-warning@+1 {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension AtDeploymentTarget { - public func publicFunc() {} +extension BetweenTargetsInternal { // expected-note {{add @available attribute to enclosing extension}} + public func publicFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } +// MARK: Extensions on AfterDeploymentTarget + // expected-error@+1 {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note@+1 {{add @available attribute to enclosing extension}} extension AfterDeploymentTarget {} -// expected-error@+1 {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note@+1 {{add @available attribute to enclosing extension}} -extension AfterDeploymentTarget { - internal func internalFunc1() {} - private func privateFunc1() {} - fileprivate func fileprivateFunc1() {} +// expected-error@+1 {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} +extension AfterDeploymentTarget { // expected-note 2 {{add @available attribute to enclosing extension}} + func internalFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} } -// expected-error@+1 {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note@+1 {{add @available attribute to enclosing extension}} +// expected-error@+1 {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} +extension AfterDeploymentTarget { // expected-note 2 {{add @available attribute to enclosing extension}} + public func publicFuncInExtension( // expected-note {{add @available attribute to enclosing instance method}} + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} + ) {} +} + +@available(macOS 11, *) extension AfterDeploymentTarget { - public func publicFunc1() {} + public func publicFuncInExtensionWithExplicitAvailability( + _: NoAvailable, + _: BeforeInliningTarget, + _: AtInliningTarget, + _: BetweenTargets, + _: AtDeploymentTarget, + _: AfterDeploymentTarget + ) {} } @@ -1062,8 +1151,8 @@ public protocol PublicProto {} extension NoAvailable: PublicProto {} extension BeforeInliningTarget: PublicProto {} extension AtInliningTarget: PublicProto {} -extension BetweenTargets: PublicProto {} // expected-warning {{'BetweenTargets' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note {{add @available attribute to enclosing extension}} -extension AtDeploymentTarget: PublicProto {} // expected-warning {{'AtDeploymentTarget' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}} expected-note {{add @available attribute to enclosing extension}} +extension BetweenTargets: PublicProto {} +extension AtDeploymentTarget: PublicProto {} extension AfterDeploymentTarget: PublicProto {} // expected-error {{'AfterDeploymentTarget' is only available in macOS 11 or newer}} expected-note {{add @available attribute to enclosing extension}} From 38dfb99031bb21a1bb2c60296e28d9f557d3ff31 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Mon, 23 May 2022 22:15:17 -0700 Subject: [PATCH 11/53] [ASTPrinter] Put desugaring constraints for existential types behind a PrintOptions flag that is only enabled for interface printing. --- include/swift/AST/PrintOptions.h | 3 +++ lib/AST/ASTPrinter.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/swift/AST/PrintOptions.h b/include/swift/AST/PrintOptions.h index de095ed34659a..e24d5c4f12f6d 100644 --- a/include/swift/AST/PrintOptions.h +++ b/include/swift/AST/PrintOptions.h @@ -285,6 +285,9 @@ struct PrintOptions { /// types. bool PrintExplicitAny = false; + /// Whether to desugar the constraint for an existential type. + bool DesugarExistentialConstraint = false; + /// Whether to skip keywords with a prefix of underscore such as __consuming. bool SkipUnderscoredKeywords = false; diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index abb43dc16f040..62a75827ff45a 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -156,6 +156,7 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint, result.AlwaysTryPrintParameterLabels = true; result.PrintSPIs = printSPIs; result.PrintExplicitAny = true; + result.DesugarExistentialConstraint = true; // We should print __consuming, __owned, etc for the module interface file. result.SkipUnderscoredKeywords = false; @@ -6216,7 +6217,11 @@ class TypePrinter : public TypeVisitor { // interfaces. Verifying that the underlying type of a // protocol typealias is a constriant type is fundamentally // circular, so the desugared type should be written in source. - visit(T->getConstraintType()->getDesugaredType()); + if (Options.DesugarExistentialConstraint) { + visit(T->getConstraintType()->getDesugaredType()); + } else { + visit(T->getConstraintType()); + } } void visitLValueType(LValueType *T) { From 7712387cd2c771e99d188ee69cbbb23881c516f9 Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Tue, 8 Feb 2022 16:35:34 +0100 Subject: [PATCH 12/53] [Build System] Don't clean sourcekit-lsp prior to running tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we were always cleaning the sourcekit-lsp build directory prior to running tests and installing. That’s a waste of time. Only clean prior to the first build. --- .../swift_build_support/products/indexstoredb.py | 5 ++++- .../swift_build_support/products/sourcekitlsp.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/utils/swift_build_support/swift_build_support/products/indexstoredb.py b/utils/swift_build_support/swift_build_support/products/indexstoredb.py index af187e9e612ce..cd6fedcbb0334 100644 --- a/utils/swift_build_support/swift_build_support/products/indexstoredb.py +++ b/utils/swift_build_support/swift_build_support/products/indexstoredb.py @@ -76,7 +76,7 @@ def get_dependencies(cls): def run_build_script_helper(action, host_target, product, args, - sanitize_all=False): + sanitize_all=False, clean=True): script_path = os.path.join( product.source_dir, 'Utilities', 'build-script-helper.py') @@ -105,6 +105,9 @@ def run_build_script_helper(action, host_target, product, args, elif args.enable_tsan: helper_cmd.extend(['--sanitize', 'thread']) + if not clean: + helper_cmd.append('--no-clean') + if not product.is_darwin_host( host_target) and product.is_cross_compile_target(host_target): helper_cmd.extend(['--cross-compile-host', host_target]) diff --git a/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py b/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py index c7349ab7e60de..eae0165927069 100644 --- a/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py +++ b/utils/swift_build_support/swift_build_support/products/sourcekitlsp.py @@ -50,14 +50,14 @@ def should_test(self, host_target): def test(self, host_target): indexstoredb.run_build_script_helper( 'test', host_target, self, self.args, - self.args.test_sourcekitlsp_sanitize_all) + self.args.test_sourcekitlsp_sanitize_all, clean=False) def should_install(self, host_target): return self.args.install_sourcekitlsp def install(self, host_target): indexstoredb.run_build_script_helper( - 'install', host_target, self, self.args) + 'install', host_target, self, self.args, clean=False) @classmethod def get_dependencies(cls): From e39caea26a92b0158e4c64a8a01dcede42ef7442 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 24 May 2022 08:03:11 -0700 Subject: [PATCH 13/53] [Test] Run test with 64-bit SIL on 64-bit arch. --- validation-test/SILOptimizer/hoist_destroy_addr.sil | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validation-test/SILOptimizer/hoist_destroy_addr.sil b/validation-test/SILOptimizer/hoist_destroy_addr.sil index 25158a97fac9a..fe5912e4d007a 100644 --- a/validation-test/SILOptimizer/hoist_destroy_addr.sil +++ b/validation-test/SILOptimizer/hoist_destroy_addr.sil @@ -3,6 +3,8 @@ // REQUIRES: long_test // REQUIRES: objc_interop +// SIL includes assumption of 64-bit wordsize +// REQUIRES: PTRSIZE=64 import Builtin import Swift From bdc1f404e6c243705335aa93d7433e59a349eb9d Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 19 May 2022 08:32:05 -0700 Subject: [PATCH 14/53] [Gardening] Recapitalized type. --- lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp index a37d7c36d933f..602f85b7e01a0 100644 --- a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp +++ b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp @@ -139,17 +139,17 @@ struct DeinitBarriers final { /// place they can be hoisted to. /// /// Implements BackwardReachability::BlockReachability. -class DataFlow final { +class Dataflow final { Context const &context; Usage const &uses; DeinitBarriers &result; enum class Classification { Barrier, Copy, Other }; - BackwardReachability reachability; + BackwardReachability reachability; public: - DataFlow(Context const &context, Usage const &uses, DeinitBarriers &result) + Dataflow(Context const &context, Usage const &uses, DeinitBarriers &result) : context(context), uses(uses), result(result), reachability(&context.function, *this) { // Seed reachability with the scope ending uses from which the backwards @@ -158,13 +158,13 @@ class DataFlow final { reachability.initLastUse(end); } } - DataFlow(DataFlow const &) = delete; - DataFlow &operator=(DataFlow const &) = delete; + Dataflow(Dataflow const &) = delete; + Dataflow &operator=(Dataflow const &) = delete; void run() { reachability.solveBackward(); } private: - friend class BackwardReachability; + friend class BackwardReachability; bool hasReachableBegin(SILBasicBlock *block) { return result.hoistingReachesBeginBlocks.contains(block); @@ -207,8 +207,8 @@ bool isSimpleExtendedIntroducerDef(Context const &context, SILValue value) { } } -DataFlow::Classification -DataFlow::classifyInstruction(SILInstruction *instruction) { +Dataflow::Classification +Dataflow::classifyInstruction(SILInstruction *instruction) { if (instruction == &context.introducer) { return Classification::Barrier; } @@ -226,7 +226,7 @@ DataFlow::classifyInstruction(SILInstruction *instruction) { return Classification::Other; } -bool DataFlow::classificationIsBarrier(Classification classification) { +bool Dataflow::classificationIsBarrier(Classification classification) { switch (classification) { case Classification::Barrier: return true; @@ -237,7 +237,7 @@ bool DataFlow::classificationIsBarrier(Classification classification) { llvm_unreachable("exhaustive switch not exhaustive?!"); } -void DataFlow::visitedInstruction(SILInstruction *instruction, +void Dataflow::visitedInstruction(SILInstruction *instruction, Classification classification) { assert(classifyInstruction(instruction) == classification); switch (classification) { @@ -253,13 +253,13 @@ void DataFlow::visitedInstruction(SILInstruction *instruction, llvm_unreachable("exhaustive switch not exhaustive?!"); } -bool DataFlow::checkReachableBarrier(SILInstruction *instruction) { +bool Dataflow::checkReachableBarrier(SILInstruction *instruction) { auto classification = classifyInstruction(instruction); visitedInstruction(instruction, classification); return classificationIsBarrier(classification); } -bool DataFlow::checkReachablePhiBarrier(SILBasicBlock *block) { +bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { assert(llvm::all_of(block->getArguments(), [&](auto argument) { return PhiValue(argument); })); @@ -397,7 +397,7 @@ bool run(Context &context) { return false; DeinitBarriers barriers(context); - DataFlow flow(context, usage, barriers); + Dataflow flow(context, usage, barriers); flow.run(); Rewriter rewriter(context, usage, barriers); From 180095ae3a1b8db200d36a79ba1126768e19bce6 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 16 May 2022 12:57:34 -0700 Subject: [PATCH 15/53] [ShrinkBorrowScope] Adopt iterative dataflow. Adopt IterativeBackwardReachability. Enables hoisting end_borrow instructions over loops. That in turn enables hoisting destroy_values over those same loops. rdar://93186505 --- lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp | 152 +++++++++---------- test/SILOptimizer/shrink_borrow_scope.sil | 6 +- 2 files changed, 73 insertions(+), 85 deletions(-) diff --git a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp index 602f85b7e01a0..3fb261bd2d813 100644 --- a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp +++ b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp @@ -49,6 +49,8 @@ struct Context final { /// introducer->getOperand() SILValue const borrowee; + SILBasicBlock *defBlock; + SILFunction &function; /// The copy_value instructions that the utility creates or changes. @@ -62,7 +64,8 @@ struct Context final { SmallVectorImpl &modifiedCopyValueInsts, InstructionDeleter &deleter) : introducer(introducer), borrowedValue(BorrowedValue(&introducer)), - borrowee(introducer.getOperand()), function(*introducer.getFunction()), + borrowee(introducer.getOperand()), defBlock(introducer.getParent()), + function(*introducer.getFunction()), modifiedCopyValueInsts(modifiedCopyValueInsts), deleter(deleter) {} Context(Context const &) = delete; Context &operator=(Context const &) = delete; @@ -75,7 +78,7 @@ struct Usage final { SmallPtrSet users; // The instructions from which the shrinking starts, the scope ending // instructions. - llvm::SmallSetVector ends; + llvm::SmallVector ends; Usage(){}; Usage(Usage const &) = delete; @@ -95,7 +98,7 @@ bool findUsage(Context const &context, Usage &usage) { // If a scope ending instruction is not an end_borrow, bail out. if (!isa(instruction)) return false; - usage.ends.insert(instruction); + usage.ends.push_back(instruction); } SmallVector uses; @@ -112,25 +115,21 @@ bool findUsage(Context const &context, Usage &usage) { /// How end_borrow hoisting is obstructed. struct DeinitBarriers final { - /// Blocks up to "before the beginning" of which hoisting was able to proceed. - BasicBlockSetVector hoistingReachesBeginBlocks; - - /// Blocks to "after the end" of which hoisting was able to proceed. - BasicBlockSet hoistingReachesEndBlocks; - /// Copies to be rewritten as copies of %borrowee. SmallVector copies; /// Instructions above which end_borrows cannot be hoisted. - SmallVector barriers; + SmallVector instructions; /// Blocks one of whose phis is a barrier and consequently out of which /// end_borrows cannot be hoisted. - SmallVector phiBarriers; + SmallVector phis; + + /// Blocks whose single predecessors has another successor to the top of which + /// end_borrows cannot be hoisted. + SmallVector blocks; - DeinitBarriers(Context &context) - : hoistingReachesBeginBlocks(&context.function), - hoistingReachesEndBlocks(&context.function) {} + DeinitBarriers(Context &context) {} DeinitBarriers(DeinitBarriers const &) = delete; DeinitBarriers &operator=(DeinitBarriers const &) = delete; }; @@ -138,55 +137,60 @@ struct DeinitBarriers final { /// Works backwards from the current location of end_borrows to the earliest /// place they can be hoisted to. /// -/// Implements BackwardReachability::BlockReachability. +/// Implements IterativeBackwardReachability::Effects. +/// Implements IterativeBackwardReachability::findBarrier::Visitor. class Dataflow final { +public: + using Reachability = IterativeBackwardReachability; + using Effect = Reachability::Effect; + +private: Context const &context; Usage const &uses; - DeinitBarriers &result; + DeinitBarriers &barriers; + Reachability::Result result; + Reachability reachability; + SmallPtrSet barrierAccessScopes; + bool recordCopies = false; enum class Classification { Barrier, Copy, Other }; - BackwardReachability reachability; - public: - Dataflow(Context const &context, Usage const &uses, DeinitBarriers &result) - : context(context), uses(uses), result(result), - reachability(&context.function, *this) { - // Seed reachability with the scope ending uses from which the backwards - // data flow will begin. - for (auto *end : uses.ends) { - reachability.initLastUse(end); - } - } + Dataflow(Context const &context, Usage const &uses, DeinitBarriers &barriers) + : context(context), uses(uses), barriers(barriers), + result(&context.function), + reachability(&context.function, context.defBlock, *this, result) {} Dataflow(Dataflow const &) = delete; Dataflow &operator=(Dataflow const &) = delete; - void run() { reachability.solveBackward(); } + void run(); private: - friend class BackwardReachability; + friend Reachability; - bool hasReachableBegin(SILBasicBlock *block) { - return result.hoistingReachesBeginBlocks.contains(block); - } + Classification classifyInstruction(SILInstruction *); - void markReachableBegin(SILBasicBlock *block) { - result.hoistingReachesBeginBlocks.insert(block); - } + bool classificationIsBarrier(Classification); - void markReachableEnd(SILBasicBlock *block) { - result.hoistingReachesEndBlocks.insert(block); - } + /// Implements IterativeBackwardReachability::Effects. - Classification classifyInstruction(SILInstruction *); + ArrayRef gens() { return uses.ends; } - bool classificationIsBarrier(Classification); + Effect effectForInstruction(SILInstruction *); - void visitedInstruction(SILInstruction *, Classification); + Effect effectForPhi(SILBasicBlock *); - bool checkReachableBarrier(SILInstruction *); + /// IterativeBackwardReachability::findBarrier::Visitor. - bool checkReachablePhiBarrier(SILBasicBlock *); + void visitBarrierInstruction(SILInstruction *instruction) { + barriers.instructions.push_back(instruction); + } + + void visitBarrierPhi(SILBasicBlock *block) { barriers.phis.push_back(block); } + + void visitBarrierBlock(SILBasicBlock *block) { + barriers.blocks.push_back(block); + } }; /// Whether the specified value is %lifetime or its iterated copy_value. @@ -237,29 +241,17 @@ bool Dataflow::classificationIsBarrier(Classification classification) { llvm_unreachable("exhaustive switch not exhaustive?!"); } -void Dataflow::visitedInstruction(SILInstruction *instruction, - Classification classification) { - assert(classifyInstruction(instruction) == classification); - switch (classification) { - case Classification::Barrier: - result.barriers.push_back(instruction); - return; - case Classification::Copy: - result.copies.push_back(cast(instruction)); - return; - case Classification::Other: - return; - } - llvm_unreachable("exhaustive switch not exhaustive?!"); -} - -bool Dataflow::checkReachableBarrier(SILInstruction *instruction) { +Dataflow::Effect Dataflow::effectForInstruction(SILInstruction *instruction) { + if (llvm::find(uses.ends, instruction) != uses.ends.end()) + return Effect::Gen(); auto classification = classifyInstruction(instruction); - visitedInstruction(instruction, classification); - return classificationIsBarrier(classification); + if (recordCopies && classification == Classification::Copy) + barriers.copies.push_back(cast(instruction)); + return classificationIsBarrier(classification) ? Effect::Kill() + : Effect::NoEffect(); } -bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { +Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) { assert(llvm::all_of(block->getArguments(), [&](auto argument) { return PhiValue(argument); })); @@ -268,10 +260,14 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { return classificationIsBarrier( classifyInstruction(predecessor->getTerminator())); }); - if (isBarrier) { - result.phiBarriers.push_back(block); - } - return isBarrier; + return isBarrier ? Effect::Kill() : Effect::NoEffect(); +} + +void Dataflow::run() { + reachability.initialize(); + reachability.solve(); + recordCopies = true; + reachability.findBarriers(*this); } /// Hoist the scope ends of %lifetime, rewriting copies and borrows along the @@ -311,7 +307,7 @@ bool Rewriter::run() { // A block is a phi barrier iff any of its predecessors' terminators get // classified as barriers. That happens when a copy of %lifetime is passed // to a phi. - for (auto *block : barriers.phiBarriers) { + for (auto *block : barriers.phis) { madeChange |= createEndBorrow(&block->front()); } @@ -324,15 +320,11 @@ bool Rewriter::run() { // of a block P's successors B had reachable beginnings. If any of them // didn't, then BackwardReachability::meetOverSuccessors would never have // returned true for P, so none of its instructions would ever have been - // classified (except for via checkReachablePhiBarrier, which doesn't record - // terminator barriers). - for (auto instruction : barriers.barriers) { + // classified (except for via effectForPhi, which doesn't record terminator + // barriers). + for (auto instruction : barriers.instructions) { if (auto *terminator = dyn_cast(instruction)) { auto successors = terminator->getParentBlock()->getSuccessorBlocks(); - // In order for the instruction to have been classified as a barrier, - // reachability would have had to reach the block containing it. - assert(barriers.hoistingReachesEndBlocks.contains( - terminator->getParentBlock())); for (auto *successor : successors) { madeChange |= createEndBorrow(&successor->front()); } @@ -356,12 +348,8 @@ bool Rewriter::run() { // P not having a reachable end--see BackwardReachability::meetOverSuccessors. // // control-flow-boundary(B) := beginning-reachable(B) && !end-reachable(P) - for (auto *block : barriers.hoistingReachesBeginBlocks) { - if (auto *predecessor = block->getSinglePredecessorBlock()) { - if (!barriers.hoistingReachesEndBlocks.contains(predecessor)) { - madeChange |= createEndBorrow(&block->front()); - } - } + for (auto *block : barriers.blocks) { + madeChange |= createEndBorrow(&block->front()); } if (madeChange) { @@ -379,7 +367,7 @@ bool Rewriter::run() { bool Rewriter::createEndBorrow(SILInstruction *insertionPoint) { if (auto *ebi = dyn_cast(insertionPoint)) { - if (uses.ends.contains(insertionPoint)) { + if (llvm::find(uses.ends, insertionPoint) != uses.ends.end()) { reusedEndBorrowInsts.insert(insertionPoint); return false; } diff --git a/test/SILOptimizer/shrink_borrow_scope.sil b/test/SILOptimizer/shrink_borrow_scope.sil index 42821d9535e60..553568e4b9be9 100644 --- a/test/SILOptimizer/shrink_borrow_scope.sil +++ b/test/SILOptimizer/shrink_borrow_scope.sil @@ -457,13 +457,14 @@ exit: // loop tests {{ // ============================================================================= -// Don't hoist over loop without uses. -// TODO: Eventually, we should hoist over such loops. +// Hoist over loop without uses. +// // CHECK-LABEL: sil [ossa] @hoist_over_loop_1 : {{.*}} { // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C): // CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]] // CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed // CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]]) +// CHECK: end_borrow [[LIFETIME]] // CHECK: br [[LOOP_HEADER:bb[0-9]+]] // CHECK: [[LOOP_HEADER]]: // CHECK: br [[LOOP_BODY:bb[0-9]+]] @@ -474,7 +475,6 @@ exit: // CHECK: [[LOOP_BACKEDGE]]: // CHECK: br [[LOOP_HEADER]] // CHECK: [[EXIT]]: -// CHECK: end_borrow [[LIFETIME]] // CHECK: return [[INSTANCE]] // CHECK-LABEL: } // end sil function 'hoist_over_loop_1' sil [ossa] @hoist_over_loop_1 : $@convention(thin) (@owned C) -> @owned C { From 3c7ad6013a64b4f998f25a2a5f35c40e11d9fabb Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 20 May 2022 09:20:28 -0700 Subject: [PATCH 16/53] [ShrinkBorrowScope] Adopt VisitBarrierAccessScopes. Avoids hoisting borrow scopes into unrelated access scopes which could introduce exclusivity violations. rdar://93060369 --- lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp | 57 ++++++++++++++- test/SILOptimizer/shrink_borrow_scope.sil | 73 ++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp index 3fb261bd2d813..064eb410dab55 100644 --- a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp +++ b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp @@ -21,6 +21,7 @@ #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILInstruction.h" #include "swift/SILOptimizer/Analysis/Reachability.h" +#include "swift/SILOptimizer/Analysis/VisitBarrierAccessScopes.h" #include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h" #include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/InstructionDeleter.h" @@ -134,11 +135,14 @@ struct DeinitBarriers final { DeinitBarriers &operator=(DeinitBarriers const &) = delete; }; +class BarrierAccessScopeFinder; + /// Works backwards from the current location of end_borrows to the earliest /// place they can be hoisted to. /// /// Implements IterativeBackwardReachability::Effects. /// Implements IterativeBackwardReachability::findBarrier::Visitor. +/// Implements VisitBarrierAccessScopes::Effects class Dataflow final { public: using Reachability = IterativeBackwardReachability; @@ -167,12 +171,15 @@ class Dataflow final { private: friend Reachability; + friend class BarrierAccessScopeFinder; + friend class VisitBarrierAccessScopes; Classification classifyInstruction(SILInstruction *); bool classificationIsBarrier(Classification); - /// Implements IterativeBackwardReachability::Effects. + /// IterativeBackwardReachability::Effects + /// VisitBarrierAccessScopes::Effects ArrayRef gens() { return uses.ends; } @@ -180,6 +187,14 @@ class Dataflow final { Effect effectForPhi(SILBasicBlock *); + /// VisitBarrierAccessScopes::Effects + + auto localGens() { return result.localGens; } + + bool isLocalGen(SILInstruction *instruction) { + return result.localGens.contains(instruction); + } + /// IterativeBackwardReachability::findBarrier::Visitor. void visitBarrierInstruction(SILInstruction *instruction) { @@ -224,6 +239,11 @@ Dataflow::classifyInstruction(SILInstruction *instruction) { if (uses.users.contains(instruction)) { return Classification::Barrier; } + if (auto *eai = dyn_cast(instruction)) { + return barrierAccessScopes.contains(eai->getBeginAccess()) + ? Classification::Barrier + : Classification::Other; + } if (isDeinitBarrier(instruction)) { return Classification::Barrier; } @@ -263,8 +283,43 @@ Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) { return isBarrier ? Effect::Kill() : Effect::NoEffect(); } +/// Finds end_access instructions which are barriers to hoisting because the +/// access scopes they contain barriers to hoisting. Hoisting end_borrows into +/// such access scopes could introduce exclusivity violations. +/// +/// Implements BarrierAccessScopeFinder::Visitor +class BarrierAccessScopeFinder final { + using Impl = VisitBarrierAccessScopes; + Context const &context; + Impl impl; + Dataflow &dataflow; + +public: + BarrierAccessScopeFinder(Context const &context, Dataflow &dataflow) + : context(context), impl(&context.function, dataflow, *this), + dataflow(dataflow) {} + + void find() { impl.visit(); } + +private: + friend Impl; + + bool isInRegion(SILBasicBlock *block) { + return dataflow.result.discoveredBlocks.contains(block); + } + + void visitBarrierAccessScope(BeginAccessInst *bai) { + dataflow.barrierAccessScopes.insert(bai); + for (auto *eai : bai->getEndAccesses()) { + dataflow.reachability.addKill(eai); + } + } +}; + void Dataflow::run() { reachability.initialize(); + BarrierAccessScopeFinder finder(context, *this); + finder.find(); reachability.solve(); recordCopies = true; reachability.findBarriers(*this); diff --git a/test/SILOptimizer/shrink_borrow_scope.sil b/test/SILOptimizer/shrink_borrow_scope.sil index 553568e4b9be9..59e0f28b9986d 100644 --- a/test/SILOptimizer/shrink_borrow_scope.sil +++ b/test/SILOptimizer/shrink_borrow_scope.sil @@ -1097,3 +1097,76 @@ bb0(%0 : $*ClassWrapper): // ============================================================================= // instruction tests }} // ============================================================================= + +// ============================================================================= +// access scope tests {{ +// ============================================================================= + +// Don't hoist into an access scope that contains a barrier. +// +// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier : {{.*}} { +// CHECK: end_access +// CHECK: end_access +// CHECK: end_borrow +// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier' +sil [ossa] @nofold_scoped_load_barrier : $@convention(thin) (@owned C, @owned C) -> (@owned C) { +entry(%instance : @owned $C, %other : @owned $C): + %lifetime = begin_borrow [lexical] %instance : $C + apply undef(%lifetime) : $@convention(thin) (@guaranteed C) -> () + %addr = alloc_stack $C + %store_scope = begin_access [modify] [static] %addr : $*C + store %other to [init] %store_scope : $*C + end_access %store_scope : $*C + %load_scope = begin_access [read] [static] %addr : $*C + %value = load [copy] %load_scope : $*C + %barrier = function_ref @barrier : $@convention(thin) () -> () + apply %barrier() : $@convention(thin) () -> () + end_access %load_scope : $*C + destroy_addr %addr : $*C + dealloc_stack %addr : $*C + end_borrow %lifetime : $C + destroy_value %instance : $C + return %value : $C +} + +// Access scopes that are open at barrier blocks are barriers. Otherwise, we +// would hoist end_borrows into the scopes when the end_borrows are hoisted up +// to the begin of blocks whose predecessor is the barrier block. +// +// CHECK-LABEL: sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[INOUT:%[^,]+]] : $*C): +// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[INSTANCE]] +// CHECK: [[SCOPE:%[^,]+]] = begin_access [modify] [static] [[INOUT]] : $*C +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], +// CHECK: [[LEFT]]: +// CHECK: end_access [[SCOPE]] : $*C +// CHECK-NEXT: end_borrow [[LIFETIME]] : $C +// CHECK-LABEL: } // end sil function 'nohoist_into_access_scope_barred_by_barrier_block' +sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : $@convention(thin) (@owned C, @inout C) -> () { +entry(%instance : @owned $C, %second : $*C): + %lifetime = begin_borrow [lexical] %instance : $C + %scope = begin_access [modify] [static] %second : $*C + cond_br undef, left, right + +left: + end_access %scope : $*C + %ignore = tuple () + end_borrow %lifetime : $C + destroy_value %instance : $C + br exit + +right: + end_access %scope : $*C + apply undef(%lifetime) : $@convention(thin) (@guaranteed C) -> () + end_borrow %lifetime : $C + destroy_value %instance : $C + br exit + +exit: + %retval = tuple () + return %retval : $() +} + +// ============================================================================= +// access scope tests }} +// ============================================================================= From b996bb5735852bb167b7e334c679d016874a7e1c Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 23 May 2022 09:58:07 -0700 Subject: [PATCH 17/53] build: start building static version of ICU for Windows This builds ICU from source, statically builds and links it into the toolchain image. This removes the last piece that we were using that is not auditable. We now fully build the toolchain on the host on swift-ci. --- utils/build-windows-toolchain.bat | 62 ++++++++++++++++--------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/utils/build-windows-toolchain.bat b/utils/build-windows-toolchain.bat index 09d239499b5a0..a53f7acb20ef6 100644 --- a/utils/build-windows-toolchain.bat +++ b/utils/build-windows-toolchain.bat @@ -45,13 +45,29 @@ call :CloneRepositories || (exit /b) md "%BuildRoot%\Library" -:: TODO(compnerd) build ICU from source -curl.exe -sOL "https://github.com/unicode-org/icu/releases/download/release-67-1/icu4c-67_1-Win64-MSVC2017.zip" || (exit /b) -"%SystemDrive%\Program Files\Git\usr\bin\unzip.exe" -o icu4c-67_1-Win64-MSVC2017.zip -d %BuildRoot%\Library\icu-67.1 -md %BuildRoot%\Library\icu-67.1\usr\bin -copy %BuildRoot%\Library\icu-67.1\bin64\icudt67.dll %BuildRoot%\Library\icu-67.1\usr\bin || (exit /b) -copy %BuildRoot%\Library\icu-67.1\bin64\icuin67.dll %BuildRoot%\Library\icu-67.1\usr\bin || (exit /b) -copy %BuildRoot%\Library\icu-67.1\bin64\icuuc67.dll %BuildRoot%\Library\icu-67.1\usr\bin || (exit /b) +:: Build ICU +copy %SourceRoot%\swift-installer-scripts\shared\ICU\CMakeLists.txt %SourceRoot%\icu\icu4c\ || (exit /b) +cmake ^ + -B %BuildRoot%\icu ^ + + -D BUILD_SHARED_LIBS=NO ^ + -D CMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE% ^ + -D CMAKE_C_COMPILER=cl ^ + -D CMAKE_C_FLAGS="/GS- /Oy /Gw /Gy" ^ + -D CMAKE_CXX_COMPILER=cl ^ + -D CMAKE_CXX_FLAGS="/GS- /Oy /Gw /Gy" ^ + -D CMAKE_MT=mt ^ + -D CMAKE_EXE_LINKER_FLAGS="/INCREMENTAL:NO" ^ + -D CMAKE_SHARED_LINKER_FLAGS="/INCREMENTAL:NO" ^ + + -D CMAKE_INSTALL_PREFIX=%BuildRoot%\Library\icu-69.1\usr ^ + + -D BUILD_TOOLS=YES ^ + + -G Ninja ^ + -S %SourceRoot%\icu\icu4c || (exit /b) +cmake --build "%BuildRoot%\icu" || (exit /b) +cmake --build "%BuildRoot%\icu" --target install || (exit /b) :: FIXME(compnerd) is there a way to build the sources without downloading the amalgamation? curl.exe -sOL "https://sqlite.org/2021/sqlite-amalgamation-3360000.zip" || (exit /b) @@ -280,9 +296,10 @@ cmake ^ -D CMAKE_INSTALL_PREFIX=%SDKInstallRoot%\usr ^ -D CURL_DIR=%BuildRoot%\Library\curl-7.77.0\usr\lib\cmake\CURL ^ - -D ICU_ROOT=%BuildRoot%\Library\icu-67.1 ^ - -D ICU_UC_LIBRARY=%BuildRoot%\Library\icu-67.1\lib64\icuuc67.lib ^ - -D ICU_I18N_LIBRARY=%BuildRoot%\Library\icu-67.1\lib64\icuin67.lib ^ + -D ICU_ROOT=%BuildRoot%\Library\icu-69.1\usr ^ + -D ICU_DATA_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicudt69.lib ^ + -D ICU_UC_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicuuc69.lib ^ + -D ICU_I18N_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicuin69.lib ^ -D LIBXML2_LIBRARY=%BuildRoot%\Library\libxml2-2.9.12\usr\lib\libxml2s.lib ^ -D LIBXML2_INCLUDE_DIR=%BuildRoot%\Library\libxml2-2.9.12\usr\include\libxml2 ^ -D LIBXML2_DEFINITIONS="/DLIBXML_STATIC" ^ @@ -655,17 +672,6 @@ msbuild %SourceRoot%\swift-installer-scripts\platforms\Windows\runtime.wixproj ^ :: TODO(compnerd) actually perform the code-signing :: signtool sign /f Apple_CodeSign.pfx /p Apple_CodeSign_Password /tr http://timestamp.digicert.com /fd sha256 %PackageRoot%\runtime\runtime.msi -:: Package icu.msi -msbuild %SourceRoot%\swift-installer-scripts\platforms\Windows\icu.wixproj ^ - -p:RunWixToolsOutOfProc=true ^ - -p:OutputPath=%PackageRoot%\icu\ ^ - -p:IntermediateOutputPath=%PackageRoot%\icu\ ^ - -p:ProductVersion=67.1 ^ - -p:ProductVersionMajor=67 ^ - -p:ICU_ROOT=%BuildRoot% -:: TODO(compnerd) actually perform the code-signing -:: signtool sign /f Apple_CodeSign.pfx /p Apple_CodeSign_Password /tr http://timestamp.digicert.com /fd sha256 %PackageRoot%\icu\icu.msi - :: Package devtools.msi msbuild %SourceRoot%\swift-installer-scripts\platforms\Windows\devtools.wixproj ^ -p:RunWixToolsOutOfProc=true ^ @@ -679,7 +685,6 @@ msbuild %SourceRoot%\swift-installer-scripts\platforms\Windows\devtools.wixproj move %PackageRoot%\toolchain\toolchain.msi %PackageRoot% || (exit /b) move %PackageRoot%\sdk\sdk.msi %PackageRoot% || (exit /b) move %PackageRoot%\runtime\runtime.msi %PackageRoot% || (exit /b) -move %PackageRoot%\icu\icu.msi %PackageRoot% || (exit /b) move %PackageRoot%\devtools\devtools.msi %PackageRoot% || (exit /b) :: Build Installer @@ -693,8 +698,6 @@ msbuild %SourceRoot%\swift-installer-scripts\platforms\Windows\installer.wixproj :: Stage Artifacts md %BuildRoot%\artifacts -:: ICU Dependency for runtime libraries -move %PackageRoot%\icu.msi %BuildRoot%\artifacts || (exit /b) :: Redistributable libraries for developers move %PackageRoot%\runtime.msi %BuildRoot%\artifacts || (exit /b) :: Toolchain @@ -708,7 +711,7 @@ move %PackageRoot%\installer\installer.exe %BuildRoot%\artifacts || (exit /b) :: Test Swift :: TODO(compnerd) make lit adjust the path properly -path %BuildRoot%\3;%BuildRoot%\1\bin;%BuildRoot%\Library\icu-67.1\usr\bin;%PATH%;%SystemDrive%\Program Files\Git\usr\bin +path %BuildRoot%\3;%BuildRoot%\1\bin;%PATH%;%SystemDrive%\Program Files\Git\usr\bin cmake --build %BuildRoot%\1 --target check-swift || (exit /b) :: Test dispatch @@ -735,9 +738,10 @@ cmake ^ -D CMAKE_INSTALL_PREFIX=%SDKInstallRoot%\usr ^ -D CURL_DIR=%BuildRoot%\Library\curl-7.77.0\usr\lib\cmake\CURL ^ - -D ICU_ROOT=%BuildRoot%\Library\icu-67.1 ^ - -D ICU_UC_LIBRARY=%BuildRoot%\Library\icu-67.1\lib64\icuuc67.lib ^ - -D ICU_I18N_LIBRARY=%BuildRoot%\Library\icu-67.1\lib64\icuin67.lib ^ + -D ICU_ROOT=%BuildRoot%\Library\icu-69.1\usr ^ + -D ICU_DATA_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicudt69.lib ^ + -D ICU_I18N_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicuin69.lib ^ + -D ICU_UC_LIBRARY_RELEASE=%BuildRoot%\Library\icu-69.1\usr\lib\sicuuc69.lib ^ -D LIBXML2_LIBRARY=%BuildRoot%\Library\libxml2-2.9.12\usr\lib\libxml2s.lib ^ -D LIBXML2_INCLUDE_DIR=%BuildRoot%\Library\libxml2-2.9.12\usr\include\libxml2 ^ -D LIBXML2_DEFINITIONS="/DLIBXML_STATIC" ^ @@ -832,7 +836,7 @@ rd /s /q zlib libxml2 sqlite icu curl git clone --quiet --no-tags --depth 1 --branch v1.2.11 https://github.com/madler/zlib git clone --quiet --no-tags --depth 1 --branch v2.9.12 https://github.com/gnome/libxml2 git clone --quiet --no-tags --depth 1 --branch version-3.36.0 https://github.com/sqlite/sqlite -git clone --quiet --no-tags --depth 1 --branch maint/maint-67 https://github.com/unicode-org/icu +git clone --quiet --no-tags --depth 1 --branch maint/maint-69 https://github.com/unicode-org/icu git clone --quiet --no-tags --depth 1 --branch curl-7_77_0 https://github.com/curl/curl goto :eof From 158db440fc3fe0bf32a4a062728dcd526827cbad Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 19 May 2022 08:41:54 -0700 Subject: [PATCH 18/53] [Gardening] Recapitalized type. --- .../Utils/LexicalDestroyHoisting.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp index 2467b54ccb268..f75498d8d09e6 100644 --- a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp +++ b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp @@ -119,17 +119,17 @@ struct DeinitBarriers final { /// place they can be hoisted to. /// /// Implements BackwardReachability::BlockReachability. -class DataFlow final { +class Dataflow final { Context const &context; Usage const &uses; DeinitBarriers &result; enum class Classification { Barrier, Other }; - BackwardReachability reachability; + BackwardReachability reachability; public: - DataFlow(Context const &context, Usage const &uses, DeinitBarriers &result) + Dataflow(Context const &context, Usage const &uses, DeinitBarriers &result) : context(context), uses(uses), result(result), reachability(&context.function, *this) { // Seed reachability with the scope ending uses from which the backwards @@ -138,13 +138,13 @@ class DataFlow final { reachability.initLastUse(end); } } - DataFlow(DataFlow const &) = delete; - DataFlow &operator=(DataFlow const &) = delete; + Dataflow(Dataflow const &) = delete; + Dataflow &operator=(Dataflow const &) = delete; void run() { reachability.solveBackward(); } private: - friend class BackwardReachability; + friend class BackwardReachability; bool hasReachableBegin(SILBasicBlock *block) { return result.hoistingReachesBeginBlocks.contains(block); @@ -169,8 +169,8 @@ class DataFlow final { bool checkReachablePhiBarrier(SILBasicBlock *); }; -DataFlow::Classification -DataFlow::classifyInstruction(SILInstruction *instruction) { +Dataflow::Classification +Dataflow::classifyInstruction(SILInstruction *instruction) { if (instruction == context.definition) { return Classification::Barrier; } @@ -183,7 +183,7 @@ DataFlow::classifyInstruction(SILInstruction *instruction) { return Classification::Other; } -bool DataFlow::classificationIsBarrier(Classification classification) { +bool Dataflow::classificationIsBarrier(Classification classification) { switch (classification) { case Classification::Barrier: return true; @@ -193,7 +193,7 @@ bool DataFlow::classificationIsBarrier(Classification classification) { llvm_unreachable("exhaustive switch not exhaustive?!"); } -void DataFlow::visitedInstruction(SILInstruction *instruction, +void Dataflow::visitedInstruction(SILInstruction *instruction, Classification classification) { assert(classifyInstruction(instruction) == classification); switch (classification) { @@ -206,13 +206,13 @@ void DataFlow::visitedInstruction(SILInstruction *instruction, llvm_unreachable("exhaustive switch not exhaustive?!"); } -bool DataFlow::checkReachableBarrier(SILInstruction *instruction) { +bool Dataflow::checkReachableBarrier(SILInstruction *instruction) { auto classification = classifyInstruction(instruction); visitedInstruction(instruction, classification); return classificationIsBarrier(classification); } -bool DataFlow::checkReachablePhiBarrier(SILBasicBlock *block) { +bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { assert(llvm::all_of(block->getArguments(), [&](auto argument) { return PhiValue(argument); })); @@ -342,7 +342,7 @@ bool run(Context &context) { return false; DeinitBarriers barriers(context); - DataFlow flow(context, usage, barriers); + Dataflow flow(context, usage, barriers); flow.run(); Rewriter rewriter(context, usage, barriers); From fdc35a113872602ca405f035eea81dcbc2a2ab97 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Mon, 16 May 2022 14:51:23 -0700 Subject: [PATCH 19/53] [LexicalDestroyHoisting] Adopt iterative dataflow. Adopt IterativeBackwardReachability. Enables hoisting destroy_values over loops. rdar://93369506 --- .../Utils/LexicalDestroyHoisting.cpp | 134 ++++++++---------- .../SILOptimizer/lexical_destroy_hoisting.sil | 3 +- 2 files changed, 58 insertions(+), 79 deletions(-) diff --git a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp index f75498d8d09e6..36a197220d5ea 100644 --- a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp +++ b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp @@ -43,6 +43,8 @@ struct Context final { /// value->getDefiningInstruction() SILInstruction *const definition; + SILBasicBlock *defBlock; + SILFunction &function; InstructionDeleter &deleter; @@ -50,7 +52,8 @@ struct Context final { Context(SILValue const &value, SILFunction &function, InstructionDeleter &deleter) : value(value), definition(value->getDefiningInstruction()), - function(function), deleter(deleter) { + defBlock(value->getParentBlock()), function(function), + deleter(deleter) { assert(value->isLexical()); assert(value->getOwnershipKind() == OwnershipKind::Owned); } @@ -63,7 +66,7 @@ struct Usage final { /// Instructions which are users of the simple (i.e. not reborrowed) value. SmallPtrSet users; // The instructions from which the hoisting starts, the destroy_values. - llvm::SmallSetVector ends; + llvm::SmallVector ends; Usage(){}; Usage(Usage const &) = delete; @@ -85,7 +88,7 @@ bool findUsage(Context const &context, Usage &usage) { // flow and determine whether any were reused. They aren't uses over which // we can't hoist though. if (isa(use->getUser())) { - usage.ends.insert(use->getUser()); + usage.ends.push_back(use->getUser()); } else { usage.users.insert(use->getUser()); } @@ -95,22 +98,16 @@ bool findUsage(Context const &context, Usage &usage) { /// How destroy_value hoisting is obstructed. struct DeinitBarriers final { - /// Blocks up to "before the beginning" of which hoisting was able to proceed. - BasicBlockSetVector hoistingReachesBeginBlocks; - - /// Blocks to "after the end" of which hoisting was able to proceed. - BasicBlockSet hoistingReachesEndBlocks; - /// Instructions above which destroy_values cannot be hoisted. - SmallVector barriers; + SmallVector instructions; /// Blocks one of whose phis is a barrier and consequently out of which /// destroy_values cannot be hoisted. - SmallVector phiBarriers; + SmallVector phis; + + SmallVector blocks; - DeinitBarriers(Context &context) - : hoistingReachesBeginBlocks(&context.function), - hoistingReachesEndBlocks(&context.function) {} + DeinitBarriers(Context &context) {} DeinitBarriers(DeinitBarriers const &) = delete; DeinitBarriers &operator=(DeinitBarriers const &) = delete; }; @@ -118,55 +115,54 @@ struct DeinitBarriers final { /// Works backwards from the current location of destroy_values to the earliest /// place they can be hoisted to. /// -/// Implements BackwardReachability::BlockReachability. +/// Implements IterativeBackwardReachability::Effects +/// Implements IterativeBackwardReachability::bindBarriers::Visitor class Dataflow final { + using Reachability = IterativeBackwardReachability; + using Effect = Reachability::Effect; Context const &context; Usage const &uses; - DeinitBarriers &result; + DeinitBarriers &barriers; + Reachability::Result result; + Reachability reachability; enum class Classification { Barrier, Other }; - BackwardReachability reachability; - public: - Dataflow(Context const &context, Usage const &uses, DeinitBarriers &result) - : context(context), uses(uses), result(result), - reachability(&context.function, *this) { - // Seed reachability with the scope ending uses from which the backwards - // data flow will begin. - for (auto *end : uses.ends) { - reachability.initLastUse(end); - } - } + Dataflow(Context const &context, Usage const &uses, DeinitBarriers &barriers) + : context(context), uses(uses), barriers(barriers), + result(&context.function), + reachability(&context.function, context.defBlock, *this, result) {} Dataflow(Dataflow const &) = delete; Dataflow &operator=(Dataflow const &) = delete; - void run() { reachability.solveBackward(); } + void run(); private: - friend class BackwardReachability; + friend Reachability; - bool hasReachableBegin(SILBasicBlock *block) { - return result.hoistingReachesBeginBlocks.contains(block); - } + Classification classifyInstruction(SILInstruction *); - void markReachableBegin(SILBasicBlock *block) { - result.hoistingReachesBeginBlocks.insert(block); - } + bool classificationIsBarrier(Classification); - void markReachableEnd(SILBasicBlock *block) { - result.hoistingReachesEndBlocks.insert(block); - } + /// IterativeBackwardReachability::Effects - Classification classifyInstruction(SILInstruction *); + ArrayRef gens() { return uses.ends; } - bool classificationIsBarrier(Classification); + Effect effectForInstruction(SILInstruction *); + Effect effectForPhi(SILBasicBlock *); - void visitedInstruction(SILInstruction *, Classification); + /// IterativeBackwardReachability::bindBarriers::Visitor - bool checkReachableBarrier(SILInstruction *); + void visitBarrierInstruction(SILInstruction *instruction) { + barriers.instructions.push_back(instruction); + } - bool checkReachablePhiBarrier(SILBasicBlock *); + void visitBarrierPhi(SILBasicBlock *block) { barriers.phis.push_back(block); } + + void visitBarrierBlock(SILBasicBlock *block) { + barriers.blocks.push_back(block); + } }; Dataflow::Classification @@ -193,26 +189,15 @@ bool Dataflow::classificationIsBarrier(Classification classification) { llvm_unreachable("exhaustive switch not exhaustive?!"); } -void Dataflow::visitedInstruction(SILInstruction *instruction, - Classification classification) { - assert(classifyInstruction(instruction) == classification); - switch (classification) { - case Classification::Barrier: - result.barriers.push_back(instruction); - return; - case Classification::Other: - return; - } - llvm_unreachable("exhaustive switch not exhaustive?!"); -} - -bool Dataflow::checkReachableBarrier(SILInstruction *instruction) { +Dataflow::Effect Dataflow::effectForInstruction(SILInstruction *instruction) { + if (llvm::find(uses.ends, instruction) != uses.ends.end()) + return Effect::Gen(); auto classification = classifyInstruction(instruction); - visitedInstruction(instruction, classification); - return classificationIsBarrier(classification); + return classificationIsBarrier(classification) ? Effect::Kill() + : Effect::NoEffect(); } -bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { +Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) { assert(llvm::all_of(block->getArguments(), [&](auto argument) { return PhiValue(argument); })); @@ -221,10 +206,13 @@ bool Dataflow::checkReachablePhiBarrier(SILBasicBlock *block) { return classificationIsBarrier( classifyInstruction(predecessor->getTerminator())); }); - if (isBarrier) { - result.phiBarriers.push_back(block); - } - return isBarrier; + return isBarrier ? Effect::Kill() : Effect::NoEffect(); +} + +void Dataflow::run() { + reachability.initialize(); + reachability.solve(); + reachability.findBarriers(*this); } /// Hoist the destroy_values of %value. @@ -256,7 +244,7 @@ bool Rewriter::run() { // // A block is a phi barrier iff any of its predecessors' terminators get // classified as barriers. - for (auto *block : barriers.phiBarriers) { + for (auto *block : barriers.phis) { madeChange |= createDestroyValue(&block->front()); } @@ -271,13 +259,9 @@ bool Rewriter::run() { // have returned true for P, so none of its instructions would ever have been // classified (except for via checkReachablePhiBarrier, which doesn't record // terminator barriers). - for (auto instruction : barriers.barriers) { + for (auto instruction : barriers.instructions) { if (auto *terminator = dyn_cast(instruction)) { auto successors = terminator->getParentBlock()->getSuccessorBlocks(); - // In order for the instruction to have been classified as a barrier, - // reachability would have had to reach the block containing it. - assert(barriers.hoistingReachesEndBlocks.contains( - terminator->getParentBlock())); for (auto *successor : successors) { madeChange |= createDestroyValue(&successor->front()); } @@ -301,12 +285,8 @@ bool Rewriter::run() { // P not having a reachable end--see BackwardReachability::meetOverSuccessors. // // control-flow-boundary(B) := beginning-reachable(B) && !end-reachable(P) - for (auto *block : barriers.hoistingReachesBeginBlocks) { - if (auto *predecessor = block->getSinglePredecessorBlock()) { - if (!barriers.hoistingReachesEndBlocks.contains(predecessor)) { - madeChange |= createDestroyValue(&block->front()); - } - } + for (auto *block : barriers.blocks) { + madeChange |= createDestroyValue(&block->front()); } if (madeChange) { @@ -324,7 +304,7 @@ bool Rewriter::run() { bool Rewriter::createDestroyValue(SILInstruction *insertionPoint) { if (auto *ebi = dyn_cast(insertionPoint)) { - if (uses.ends.contains(insertionPoint)) { + if (llvm::find(uses.ends, insertionPoint) != uses.ends.end()) { reusedDestroyValueInsts.insert(insertionPoint); return false; } diff --git a/test/SILOptimizer/lexical_destroy_hoisting.sil b/test/SILOptimizer/lexical_destroy_hoisting.sil index 16e29693cc602..9cd8bf41f56c0 100644 --- a/test/SILOptimizer/lexical_destroy_hoisting.sil +++ b/test/SILOptimizer/lexical_destroy_hoisting.sil @@ -237,11 +237,11 @@ exit(%thing : @owned $C): // Don't hoist over loop without uses. // -// TODO: Eventually, we should hoist over such loops. // CHECK-LABEL: sil [ossa] @hoist_over_loop_1 : {{.*}} { // CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C): // CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed // CHECK: apply [[CALLEE_GUARANTEED]]([[INSTANCE]]) +// CHECK: destroy_value [[INSTANCE]] // CHECK: br [[LOOP_HEADER:bb[0-9]+]] // CHECK: [[LOOP_HEADER]]: // CHECK: br [[LOOP_BODY:bb[0-9]+]] @@ -252,7 +252,6 @@ exit(%thing : @owned $C): // CHECK: [[LOOP_BACKEDGE]]: // CHECK: br [[LOOP_HEADER]] // CHECK: [[EXIT]]: -// CHECK: destroy_value [[INSTANCE]] // CHECK-LABEL: } // end sil function 'hoist_over_loop_1' sil [ossa] @hoist_over_loop_1 : $@convention(thin) (@owned C) -> () { entry(%instance: @owned $C): From e68c12f251b023e80eae967c6df28f28482b7047 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 20 May 2022 19:49:58 -0700 Subject: [PATCH 20/53] [LexicalDestroyHoisting] Adopt VisitBarrierAccessScopes. Avoids hoisting destroy_values into unrelated access scopes which could introduce exclusivity violations. --- .../Utils/LexicalDestroyHoisting.cpp | 54 ++++++++++++++++ .../SILOptimizer/lexical_destroy_hoisting.sil | 64 +++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp index 36a197220d5ea..254008483c0a5 100644 --- a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp +++ b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp @@ -20,6 +20,7 @@ #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" #include "swift/SILOptimizer/Analysis/Reachability.h" +#include "swift/SILOptimizer/Analysis/VisitBarrierAccessScopes.h" #include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h" #include "swift/SILOptimizer/Utils/InstOptUtils.h" #include "swift/SILOptimizer/Utils/InstructionDeleter.h" @@ -112,11 +113,14 @@ struct DeinitBarriers final { DeinitBarriers &operator=(DeinitBarriers const &) = delete; }; +class BarrierAccessScopeFinder; + /// Works backwards from the current location of destroy_values to the earliest /// place they can be hoisted to. /// /// Implements IterativeBackwardReachability::Effects /// Implements IterativeBackwardReachability::bindBarriers::Visitor +/// Implements VisitBarrierAccessScopes::Effects class Dataflow final { using Reachability = IterativeBackwardReachability; using Effect = Reachability::Effect; @@ -125,6 +129,7 @@ class Dataflow final { DeinitBarriers &barriers; Reachability::Result result; Reachability reachability; + SmallPtrSet barrierAccessScopes; enum class Classification { Barrier, Other }; @@ -140,18 +145,29 @@ class Dataflow final { private: friend Reachability; + friend class BarrierAccessScopeFinder; + friend class VisitBarrierAccessScopes; Classification classifyInstruction(SILInstruction *); bool classificationIsBarrier(Classification); /// IterativeBackwardReachability::Effects + /// VisitBarrierAccessScopes::Effects ArrayRef gens() { return uses.ends; } Effect effectForInstruction(SILInstruction *); Effect effectForPhi(SILBasicBlock *); + /// VisitBarrierAccessScopes::Effects + + auto localGens() { return result.localGens; } + + bool isLocalGen(SILInstruction *instruction) { + return result.localGens.contains(instruction); + } + /// IterativeBackwardReachability::bindBarriers::Visitor void visitBarrierInstruction(SILInstruction *instruction) { @@ -173,6 +189,11 @@ Dataflow::classifyInstruction(SILInstruction *instruction) { if (uses.users.contains(instruction)) { return Classification::Barrier; } + if (auto *eai = dyn_cast(instruction)) { + return barrierAccessScopes.contains(eai->getBeginAccess()) + ? Classification::Barrier + : Classification::Other; + } if (isDeinitBarrier(instruction)) { return Classification::Barrier; } @@ -209,8 +230,41 @@ Dataflow::Effect Dataflow::effectForPhi(SILBasicBlock *block) { return isBarrier ? Effect::Kill() : Effect::NoEffect(); } +/// Finds end_access instructions which are barriers to hoisting because the +/// access scopes they contain barriers to hoisting. Hoisting destroy_values +/// into such access scopes could introduce exclusivity violations. +/// +/// Implements BarrierAccessScopeFinder::Visitor +class BarrierAccessScopeFinder final { + using Impl = VisitBarrierAccessScopes; + Impl impl; + Dataflow &dataflow; + +public: + BarrierAccessScopeFinder(Context const &context, Dataflow &dataflow) + : impl(&context.function, dataflow, *this), dataflow(dataflow) {} + + void find() { impl.visit(); } + +private: + friend Impl; + + bool isInRegion(SILBasicBlock *block) { + return dataflow.result.discoveredBlocks.contains(block); + } + + void visitBarrierAccessScope(BeginAccessInst *bai) { + dataflow.barrierAccessScopes.insert(bai); + for (auto *eai : bai->getEndAccesses()) { + dataflow.reachability.addKill(eai); + } + } +}; + void Dataflow::run() { reachability.initialize(); + BarrierAccessScopeFinder finder(context, *this); + finder.find(); reachability.solve(); reachability.findBarriers(*this); } diff --git a/test/SILOptimizer/lexical_destroy_hoisting.sil b/test/SILOptimizer/lexical_destroy_hoisting.sil index 9cd8bf41f56c0..8cff942dcdc00 100644 --- a/test/SILOptimizer/lexical_destroy_hoisting.sil +++ b/test/SILOptimizer/lexical_destroy_hoisting.sil @@ -460,3 +460,67 @@ entry(%instance : @owned $C, %input : $S): // instruction tests }} // ============================================================================= +// ============================================================================= +// access scope tests {{ +// ============================================================================= + +// Don't hoist into an access scope that contains a barrier. +// +// CHECK-LABEL: sil [ossa] @nofold_scoped_load_barrier : {{.*}} { +// CHECK: end_access +// CHECK: end_access +// CHECK: destroy_value +// CHECK-LABEL: // end sil function 'nofold_scoped_load_barrier' +sil [ossa] @nofold_scoped_load_barrier : $@convention(thin) (@owned C, @owned C) -> (@owned C) { +entry(%instance : @owned $C, %other : @owned $C): + %addr = alloc_stack $C + %store_scope = begin_access [modify] [static] %addr : $*C + store %other to [init] %store_scope : $*C + end_access %store_scope : $*C + %load_scope = begin_access [read] [static] %addr : $*C + %value = load [copy] %load_scope : $*C + %barrier = function_ref @barrier : $@convention(thin) () -> () + apply %barrier() : $@convention(thin) () -> () + end_access %load_scope : $*C + destroy_addr %addr : $*C + dealloc_stack %addr : $*C + destroy_value %instance : $C + return %value : $C +} + +// Access scopes that are open at barrier blocks are barriers. Otherwise, we +// would hoist destroy_values into the scopes when the destroy_values are +// hoisted up to the begin of blocks whose predecessor is the barrier block. +// +// CHECK-LABEL: sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : {{.*}} { +// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[INOUT:%[^,]+]] : $*C): +// CHECK: [[SCOPE:%[^,]+]] = begin_access [modify] [static] [[INOUT]] : $*C +// CHECK: cond_br undef, [[LEFT:bb[0-9]+]], +// CHECK: [[LEFT]]: +// CHECK: end_access [[SCOPE]] : $*C +// CHECK-NEXT: destroy_value [[INSTANCE]] : $C +// CHECK-LABEL: } // end sil function 'nohoist_into_access_scope_barred_by_barrier_block' +sil [ossa] @nohoist_into_access_scope_barred_by_barrier_block : $@convention(thin) (@owned C, @inout C) -> () { +entry(%instance : @owned $C, %second : $*C): + %scope = begin_access [modify] [static] %second : $*C + cond_br undef, left, right + +left: + end_access %scope : $*C + %ignore = tuple () + destroy_value %instance : $C + br exit + +right: + end_access %scope : $*C + apply undef(%instance) : $@convention(thin) (@owned C) -> () + br exit + +exit: + %retval = tuple () + return %retval : $() +} + +// ============================================================================= +// access scope tests }} +// ============================================================================= From 5bef9f21187d4297253892a2220737ef222d2689 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 24 May 2022 11:36:13 -0600 Subject: [PATCH 21/53] [SymbolGraphGen] Add filename and module name to symbols' doc comments (#58857) * move symbol graph samples to the bottom of the file * add information about a doc comment's file and module rdar://81190369 * refactor: group file URI collection/serialization together * test for docComment.module to identify externally-inherited docs --- lib/SymbolGraphGen/Symbol.cpp | 73 +++- .../CursorInfo/cursor_info_multi_module.swift | 16 +- .../CursorInfo/cursor_symbol_graph_objc.swift | 32 +- .../Mixins/DocComment/BlockStyle.swift | 312 ++++++++++-------- .../Symbols/Mixins/DocComment/LineStyle.swift | 153 +++++---- .../Mixins/DocComment/SourceModule.swift | 96 ++++++ 6 files changed, 441 insertions(+), 241 deletions(-) create mode 100644 test/SymbolGraph/Symbols/Mixins/DocComment/SourceModule.swift diff --git a/lib/SymbolGraphGen/Symbol.cpp b/lib/SymbolGraphGen/Symbol.cpp index f411b6b60ac7a..44fa9f2a25883 100644 --- a/lib/SymbolGraphGen/Symbol.cpp +++ b/lib/SymbolGraphGen/Symbol.cpp @@ -197,6 +197,37 @@ const ValueDecl *Symbol::getDeclInheritingDocs() const { } } +namespace { + +StringRef getFileNameForDecl(const ValueDecl *VD) { + if (!VD) return StringRef{}; + + SourceLoc Loc = VD->getLoc(/*SerializedOK=*/true); + if (Loc.isInvalid()) return StringRef{}; + + SourceManager &SourceM = VD->getASTContext().SourceMgr; + return SourceM.getDisplayNameForLoc(Loc); +} + +StringRef getFileNameForDecl(const clang::Decl *ClangD) { + if (!ClangD) return StringRef{}; + + const clang::SourceManager &ClangSourceMgr = ClangD->getASTContext().getSourceManager(); + clang::PresumedLoc Loc = ClangSourceMgr.getPresumedLoc(ClangD->getLocation()); + if (Loc.isInvalid()) return StringRef{}; + + return StringRef(Loc.getFilename()); +} + +void serializeFileURI(llvm::json::OStream &OS, StringRef FileName) { + // FIXME: This can emit invalid URIs if the file name has a space in it (rdar://69242070) + SmallString<1024> FileURI("file://"); + FileURI.append(FileName); + OS.attribute("uri", FileURI.str()); +} + +} + void Symbol::serializeDocComment(llvm::json::OStream &OS) const { if (ClangNode ClangN = VD->getClangNode()) { if (!Graph->Walker.Options.IncludeClangDocs) @@ -221,6 +252,12 @@ void Symbol::serializeDocComment(llvm::json::OStream &OS) const { splitIntoLines(Text, Lines); OS.attributeObject("docComment", [&]() { + StringRef FileName = getFileNameForDecl(ClangD); + if (!FileName.empty()) + serializeFileURI(OS, FileName); + if (const auto *ModuleD = VD->getModuleContext()) { + OS.attribute("module", ModuleD->getNameStr()); + } OS.attributeArray("lines", [&]() { for (StringRef Line : Lines) { OS.object([&](){ @@ -247,6 +284,12 @@ void Symbol::serializeDocComment(llvm::json::OStream &OS) const { } OS.attributeObject("docComment", [&](){ + StringRef FileName = getFileNameForDecl(DocCommentProvidingDecl); + if (!FileName.empty()) + serializeFileURI(OS, FileName); + if (const auto *ModuleD = DocCommentProvidingDecl->getModuleContext()) { + OS.attribute("module", ModuleD->getNameStr()); + } auto LL = Graph->Ctx.getLineList(RC); StringRef FirstNonBlankLine; for (const auto &Line : LL.getLines()) { @@ -415,18 +458,13 @@ void Symbol::serializeLocationMixin(llvm::json::OStream &OS) const { return; if (auto *ClangD = ClangN.getAsDecl()) { - clang::SourceManager &ClangSM = - ClangD->getASTContext().getSourceManager(); - - clang::PresumedLoc Loc = ClangSM.getPresumedLoc(ClangD->getLocation()); - if (Loc.isValid()) { - // TODO: We should use a common function to fill in the location - // information for both cursor info and symbol graph gen, then also - // include position here. + StringRef FileName = getFileNameForDecl(ClangD); + if (!FileName.empty()) { OS.attributeObject("location", [&](){ - SmallString<1024> FileURI("file://"); - FileURI.append(Loc.getFilename()); - OS.attribute("uri", FileURI.str()); + // TODO: We should use a common function to fill in the location + // information for both cursor info and symbol graph gen, then also + // include position here. + serializeFileURI(OS, FileName); }); } } @@ -434,18 +472,17 @@ void Symbol::serializeLocationMixin(llvm::json::OStream &OS) const { return; } - auto Loc = VD->getLoc(/*SerializedOK=*/true); - if (Loc.isInvalid()) { + auto FileName = getFileNameForDecl(VD); + if (FileName.empty()) { return; } - auto FileName = VD->getASTContext().SourceMgr.getDisplayNameForLoc(Loc); - if (FileName.empty()) { + // TODO: Fold serializePosition into serializeFileURI so we don't need to load Loc twice? + auto Loc = VD->getLoc(/*SerializedOK=*/true); + if (Loc.isInvalid()) { return; } OS.attributeObject("location", [&](){ - SmallString<1024> FileURI("file://"); - FileURI.append(FileName); - OS.attribute("uri", FileURI.str()); + serializeFileURI(OS, FileName); serializePosition("position", Loc, Graph->M.getASTContext().SourceMgr, OS); }); } diff --git a/test/SourceKit/CursorInfo/cursor_info_multi_module.swift b/test/SourceKit/CursorInfo/cursor_info_multi_module.swift index 262bf4b24f3f3..9d4014f65eb48 100644 --- a/test/SourceKit/CursorInfo/cursor_info_multi_module.swift +++ b/test/SourceKit/CursorInfo/cursor_info_multi_module.swift @@ -58,7 +58,9 @@ func test() { // CHECK-NORMAL-NEXT: }, // CHECK-NORMAL-NEXT: "text": "Comment from A" // CHECK-NORMAL-NEXT: } -// CHECK-NORMAL-NEXT: ] +// CHECK-NORMAL-NEXT: ], +// CHECK-NORMAL-NEXT: "module": "somemod", +// CHECK-NORMAL-NEXT: "uri": "file://{{.*}}cursor_info_multi_module.swift" // CHECK-NORMAL-NEXT: }, // CHECK-NORMAL: "location": { // CHECK-NORMAL-NEXT: "position": { @@ -87,7 +89,9 @@ func test() { // CHECK-BEFORE-NEXT: }, // CHECK-BEFORE-NEXT: "text": "Comment from B" // CHECK-BEFORE-NEXT: } -// CHECK-BEFORE-NEXT: ] +// CHECK-BEFORE-NEXT: ], +// CHECK-BEFORE-NEXT: "module": "somemod", +// CHECK-BEFORE-NEXT: "uri": "file://{{.*}}cursor_info_multi_module.swift" // CHECK-BEFORE-NEXT: }, // CHECK-BEFORE: "location": { // CHECK-BEFORE-NEXT: "position": { @@ -117,7 +121,9 @@ func test() { // CHECK-IN-NEXT: }, // CHECK-IN-NEXT: "text": "Comment from #sourceLocation" // CHECK-IN-NEXT: } -// CHECK-IN-NEXT: ] +// CHECK-IN-NEXT: ], +// CHECK-IN-NEXT: "module": "somemod", +// CHECK-IN-NEXT: "uri": "file://doesnotexist.swift" // CHECK-IN-NEXT: }, // CHECK-IN: "location": { // CHECK-IN-NEXT: "position": { @@ -146,7 +152,9 @@ func test() { // CHECK-AFTER-NEXT: }, // CHECK-AFTER-NEXT: "text": "Comment from B" // CHECK-AFTER-NEXT: } -// CHECK-AFTER-NEXT: ] +// CHECK-AFTER-NEXT: ], +// CHECK-AFTER-NEXT: "module": "somemod", +// CHECK-AFTER-NEXT: "uri": "file://{{.*}}cursor_info_multi_module.swift" // CHECK-AFTER-NEXT: }, // CHECK-AFTER: "location": { // CHECK-AFTER-NEXT: "position": { diff --git a/test/SourceKit/CursorInfo/cursor_symbol_graph_objc.swift b/test/SourceKit/CursorInfo/cursor_symbol_graph_objc.swift index ca4a974a6d494..4c9055106bb67 100644 --- a/test/SourceKit/CursorInfo/cursor_symbol_graph_objc.swift +++ b/test/SourceKit/CursorInfo/cursor_symbol_graph_objc.swift @@ -89,7 +89,9 @@ func test(s: ObjCStruct) { // CHECK-FUNC: { // CHECK-FUNC: "text": "someFunc doc" // CHECK-FUNC: } -// CHECK-FUNC: ] +// CHECK-FUNC: ], +// CHECK-FUNC: "module": "MyMod", +// CHECK-FUNC: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-FUNC: }, // CHECK-FUNC: "functionSignature": { // CHECK-FUNC: "returns": [ @@ -164,7 +166,9 @@ struct ObjCStruct { // CHECK-SINGLE1-NEXT: { // CHECK-SINGLE1-NEXT: "text": "single line doc" // CHECK-SINGLE1-NEXT: } - // CHECK-SINGLE1-NEXT: ] + // CHECK-SINGLE1-NEXT: ], + // CHECK-SINGLE1-NEXT: "module": "MyMod", + // CHECK-SINGLE1-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-SINGLE1-NEXT: } //! single line doc @@ -174,7 +178,9 @@ struct ObjCStruct { // CHECK-SINGLE2-NEXT: { // CHECK-SINGLE2-NEXT: "text": "single line doc" // CHECK-SINGLE2-NEXT: } - // CHECK-SINGLE2-NEXT: ] + // CHECK-SINGLE2-NEXT: ], + // CHECK-SINGLE2-NEXT: "module": "MyMod", + // CHECK-SINGLE2-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-SINGLE2-NEXT: } /** single line block doc */ @@ -184,7 +190,9 @@ struct ObjCStruct { // CHECK-BLOCK1-NEXT: { // CHECK-BLOCK1-NEXT: "text": "single line block doc " // CHECK-BLOCK1-NEXT: } - // CHECK-BLOCK1-NEXT: ] + // CHECK-BLOCK1-NEXT: ], + // CHECK-BLOCK1-NEXT: "module": "MyMod", + // CHECK-BLOCK1-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-BLOCK1-NEXT: } /*! single line block doc */ @@ -194,7 +202,9 @@ struct ObjCStruct { // CHECK-BLOCK2-NEXT: { // CHECK-BLOCK2-NEXT: "text": "single line block doc " // CHECK-BLOCK2-NEXT: } - // CHECK-BLOCK2-NEXT: ] + // CHECK-BLOCK2-NEXT: ], + // CHECK-BLOCK2-NEXT: "module": "MyMod", + // CHECK-BLOCK2-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-BLOCK2-NEXT: } /** @@ -220,7 +230,9 @@ struct ObjCStruct { // DISABLED-CHECK-ART-NEXT: { // DISABLED-CHECK-ART-NEXT: "text": " " // DISABLED-CHECK-ART-NEXT: } - // DISABLED-CHECK-ART-NEXT: ] + // DISABLED-CHECK-ART-NEXT: ], + // DISABLED-CHECK-ART-NEXT: "module": "MyMod", + // DISABLED-CHECK-ART-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // DISABLED-CHECK-ART-NEXT: } /// doc1 @@ -237,7 +249,9 @@ struct ObjCStruct { // CHECK-MIXED-TYPE-NEXT: { // CHECK-MIXED-TYPE-NEXT: "text": "doc2 last" // CHECK-MIXED-TYPE-NEXT: } - // CHECK-MIXED-TYPE-NEXT: ] + // CHECK-MIXED-TYPE-NEXT: ], + // CHECK-MIXED-TYPE-NEXT: "module": "MyMod", + // CHECK-MIXED-TYPE-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // CHECK-MIXED-TYPE-NEXT: } /// doc1 @@ -274,7 +288,9 @@ struct ObjCStruct { // DISABLED-CHECK-MIXED-DOC-NEXT: { // DISABLED-CHECK-MIXED-DOC-NEXT: "text": "doc3" // DISABLED-CHECK-MIXED-DOC-NEXT: } - // DISABLED-CHECK-MIXED-DOC-NEXT: ] + // DISABLED-CHECK-MIXED-DOC-NEXT: ], + // DISABLED-CHECK-MIXED-DOC-NEXT: "module": "MyMod", + // DISABLED-CHECK-MIXED-DOC-NEXT: "uri": "file://{{.*}}mod{{\\\\|/}}M.h" // DISABLED-CHECK-MIXED-DOC-NEXT: } }; diff --git a/test/SymbolGraph/Symbols/Mixins/DocComment/BlockStyle.swift b/test/SymbolGraph/Symbols/Mixins/DocComment/BlockStyle.swift index e3b31f62ebd28..030c7f64bfe66 100644 --- a/test/SymbolGraph/Symbols/Mixins/DocComment/BlockStyle.swift +++ b/test/SymbolGraph/Symbols/Mixins/DocComment/BlockStyle.swift @@ -2,17 +2,94 @@ // Only add text to the bottom of this file // or you are going to have a bad time. +/** Single Same Line */ +public struct SingleSameLine {} + +/***/ +public struct Empty {} + +/** + */ +public struct EmptyWithNewLine {} + +/** + Single line. + */ +public struct SingleLine {} + +/** + * Single line with art. + */ +public struct SingleLineWithArt {} + +/** + Two + lines. + */ +public struct TwoLines {} + +/** + Large Indent + */ +public struct LargeIndent {} + +/** + Two lines + + Between Blank + */ +public struct TwoLinesBetweenBlank {} + +/** + + Leading Blank + */ +public struct LeadingBlank {} + +/** + Trailing Blank + + */ +public struct TrailingBlank {} + +/** + + Bound Blank + + */ +public struct BoundBlank {} + + /** + All indented. + */ + public struct AllIndented {} + +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name BlockStyle -emit-module-path %t/BlockStyle.swiftmodule +// RUN: %target-swift-symbolgraph-extract -module-name BlockStyle -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLESAMELINE +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=EMPTY +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=EMPTYWITHNEWLINE +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLELINE +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLELINEWITHART +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=LARGEINDENT +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=TWOLINESBETWEENBLANK +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=LEADINGBLANK +// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=TRAILINGBLANK + // SINGLESAMELINE-LABEL: "precise": "s:10BlockStyle14SingleSameLineV" // SINGLESAMELINE: "docComment": { +// SINGLESAMELINE-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// SINGLESAMELINE-NEXT: "module": "BlockStyle", // SINGLESAMELINE-NEXT: "lines": [ // SINGLESAMELINE-NEXT: { // SINGLESAMELINE-NEXT: "range": { // SINGLESAMELINE-NEXT: "start": { -// SINGLESAMELINE-NEXT: "line": 23, +// SINGLESAMELINE-NEXT: "line": 4, // SINGLESAMELINE-NEXT: "character": 4 // SINGLESAMELINE-NEXT: }, // SINGLESAMELINE-NEXT: "end": { -// SINGLESAMELINE-NEXT: "line": 23, +// SINGLESAMELINE-NEXT: "line": 4, // SINGLESAMELINE-NEXT: "character": 21 // SINGLESAMELINE-NEXT: } // SINGLESAMELINE-NEXT: }, @@ -21,51 +98,47 @@ // SINGLESAMELINE-NEXT: ] // SINGLESAMELINE-NEXT: }, -/** Single Same Line */ -public struct SingleSameLine {} - // EMPTY-LABEL: "precise": "s:10BlockStyle5EmptyV" // EMPTY: "docComment": { +// EMPTY-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// EMPTY-NEXT: "module": "BlockStyle", // EMPTY-NEXT: "lines": [] // EMPTY-NEXT: }, -/***/ -public struct Empty {} - // EMPTYWITHNEWLINE-LABEL: "precise": "s:10BlockStyle16EmptyWithNewLineV" -// EMPTHWITHNEWLINE: "docComment": { -// EMPTHWITHNEWLINE-NEXT: "lines": [ -// EMPTHWITHNEWLINE-NEXT: { -// EMPTHWITHNEWLINE-NEXT: "range": { -// EMPTHWITHNEWLINE-NEXT: "start": { -// EMPTHWITHNEWLINE-NEXT: "line": 54, -// EMPTHWITHNEWLINE-NEXT: "character": 1 -// EMPTHWITHNEWLINE-NEXT: }, -// EMPTHWITHNEWLINE-NEXT: "end": { -// EMPTHWITHNEWLINE-NEXT: "line": 54, -// EMPTHWITHNEWLINE-NEXT: "character": 1 -// EMPTHWITHNEWLINE-NEXT: } -// EMPTHWITHNEWLINE-NEXT: }, -// EMPTHWITHNEWLINE-NEXT: "text": "" -// EMPTHWITHNEWLINE-NEXT: } -// EMPTHWITHNEWLINE-NEXT: ] -// EMPTHWITHNEWLINE-NEXT: }, - -/** - */ -public struct EmptyWithNewLine {} +// EMPTYWITHNEWLINE: "docComment": { +// EMPTYWITHNEWLINE-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// EMPTYWITHNEWLINE-NEXT: "module": "BlockStyle", +// EMPTYWITHNEWLINE-NEXT: "lines": [ +// EMPTYWITHNEWLINE-NEXT: { +// EMPTYWITHNEWLINE-NEXT: "range": { +// EMPTYWITHNEWLINE-NEXT: "start": { +// EMPTYWITHNEWLINE-NEXT: "line": 11, +// EMPTYWITHNEWLINE-NEXT: "character": 1 +// EMPTYWITHNEWLINE-NEXT: }, +// EMPTYWITHNEWLINE-NEXT: "end": { +// EMPTYWITHNEWLINE-NEXT: "line": 11, +// EMPTYWITHNEWLINE-NEXT: "character": 1 +// EMPTYWITHNEWLINE-NEXT: } +// EMPTYWITHNEWLINE-NEXT: }, +// EMPTYWITHNEWLINE-NEXT: "text": "" +// EMPTYWITHNEWLINE-NEXT: } +// EMPTYWITHNEWLINE-NEXT: ] +// EMPTYWITHNEWLINE-NEXT: }, // SINGLELINE-LABEL: "precise": "s:10BlockStyle10SingleLineV" // SINGLELINE: "docComment": { +// SINGLELINE-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// SINGLELINE-NEXT: "module": "BlockStyle", // SINGLELINE-NEXT: "lines": [ // SINGLELINE-NEXT: { // SINGLELINE-NEXT: "range": { // SINGLELINE-NEXT: "start": { -// SINGLELINE-NEXT: "line": 90, +// SINGLELINE-NEXT: "line": 15, // SINGLELINE-NEXT: "character": 1 // SINGLELINE-NEXT: }, // SINGLELINE-NEXT: "end": { -// SINGLELINE-NEXT: "line": 90, +// SINGLELINE-NEXT: "line": 15, // SINGLELINE-NEXT: "character": 13 // SINGLELINE-NEXT: } // SINGLELINE-NEXT: }, @@ -74,11 +147,11 @@ public struct EmptyWithNewLine {} // SINGLELINE-NEXT: { // SINGLELINE-NEXT: "range": { // SINGLELINE-NEXT: "start": { -// SINGLELINE-NEXT: "line": 91, +// SINGLELINE-NEXT: "line": 16, // SINGLELINE-NEXT: "character": 1 // SINGLELINE-NEXT: }, // SINGLELINE-NEXT: "end": { -// SINGLELINE-NEXT: "line": 91, +// SINGLELINE-NEXT: "line": 16, // SINGLELINE-NEXT: "character": 1 // SINGLELINE-NEXT: } // SINGLELINE-NEXT: }, @@ -87,22 +160,19 @@ public struct EmptyWithNewLine {} // SINGLELINE-NEXT: ] // SINGLELINE-NEXT: }, -/** - Single line. - */ -public struct SingleLine {} - // SINGLELINEWITHART-LABEL: "precise": "s:10BlockStyle17SingleLineWithArtV" // SINGLELINEWITHART: "docComment": { +// SINGLELINEWITHART-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// SINGLELINEWITHART-NEXT: "module": "BlockStyle", // SINGLELINEWITHART-NEXT: "lines": [ // SINGLELINEWITHART-NEXT: { // SINGLELINEWITHART-NEXT: "range": { // SINGLELINEWITHART-NEXT: "start": { -// SINGLELINEWITHART-NEXT: "line": 127, +// SINGLELINEWITHART-NEXT: "line": 20, // SINGLELINEWITHART-NEXT: "character": 3 // SINGLELINEWITHART-NEXT: }, // SINGLELINEWITHART-NEXT: "end": { -// SINGLELINEWITHART-NEXT: "line": 127, +// SINGLELINEWITHART-NEXT: "line": 20, // SINGLELINEWITHART-NEXT: "character": 24 // SINGLELINEWITHART-NEXT: } // SINGLELINEWITHART-NEXT: }, @@ -111,11 +181,11 @@ public struct SingleLine {} // SINGLELINEWITHART-NEXT: { // SINGLELINEWITHART-NEXT: "range": { // SINGLELINEWITHART-NEXT: "start": { -// SINGLELINEWITHART-NEXT: "line": 128, +// SINGLELINEWITHART-NEXT: "line": 21, // SINGLELINEWITHART-NEXT: "character": 0 // SINGLELINEWITHART-NEXT: }, // SINGLELINEWITHART-NEXT: "end": { -// SINGLELINEWITHART-NEXT: "line": 128, +// SINGLELINEWITHART-NEXT: "line": 21, // SINGLELINEWITHART-NEXT: "character": 1 // SINGLELINEWITHART-NEXT: } // SINGLELINEWITHART-NEXT: }, @@ -124,22 +194,19 @@ public struct SingleLine {} // SINGLELINEWITHART-NEXT: ] // SINGLELINEWITHART-NEXT: }, -/** - * Single line with art. - */ -public struct SingleLineWithArt {} - // TWOLINES-LABEL: "precise": "s:10BlockStyle8TwoLinesV" // TWOLINES: "docComment": { +// TWOLINES-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// TWOLINES-NEXT: "module": "BlockStyle", // TWOLINES-NEXT: "lines": [ // TWOLINES-NEXT: { // TWOLINES-NEXT: "range": { // TWOLINES-NEXT: "start": { -// TWOLINES-NEXT: "line": 177, +// TWOLINES-NEXT: "line": 25, // TWOLINES-NEXT: "character": 1 // TWOLINES-NEXT: }, // TWOLINES-NEXT: "end": { -// TWOLINES-NEXT: "line": 177, +// TWOLINES-NEXT: "line": 25, // TWOLINES-NEXT: "character": 4 // TWOLINES-NEXT: } // TWOLINES-NEXT: }, @@ -148,11 +215,11 @@ public struct SingleLineWithArt {} // TWOLINES-NEXT: { // TWOLINES-NEXT: "range": { // TWOLINES-NEXT: "start": { -// TWOLINES-NEXT: "line": 178, +// TWOLINES-NEXT: "line": 26, // TWOLINES-NEXT: "character": 1 // TWOLINES-NEXT: }, // TWOLINES-NEXT: "end": { -// TWOLINES-NEXT: "line": 178, +// TWOLINES-NEXT: "line": 26, // TWOLINES-NEXT: "character": 7 // TWOLINES-NEXT: } // TWOLINES-NEXT: }, @@ -161,11 +228,11 @@ public struct SingleLineWithArt {} // TWOLINES-NEXT: { // TWOLINES-NEXT: "range": { // TWOLINES-NEXT: "start": { -// TWOLINES-NEXT: "line": 179, +// TWOLINES-NEXT: "line": 27, // TWOLINES-NEXT: "character": 1 // TWOLINES-NEXT: }, // TWOLINES-NEXT: "end": { -// TWOLINES-NEXT: "line": 179, +// TWOLINES-NEXT: "line": 27, // TWOLINES-NEXT: "character": 1 // TWOLINES-NEXT: } // TWOLINES-NEXT: }, @@ -174,23 +241,19 @@ public struct SingleLineWithArt {} // TWOLINES-NEXT: ] // TWOLINES-NEXT: }, -/** - Two - lines. - */ -public struct TwoLines {} - // LARGEINDENT-LABEL: "precise": "s:10BlockStyle11LargeIndentV" // LARGEINDENT: "docComment": { +// LARGEINDENT-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// LARGEINDENT-NEXT: "module": "BlockStyle", // LARGEINDENT-NEXT: "lines": [ // LARGEINDENT-NEXT: { // LARGEINDENT-NEXT: "range": { // LARGEINDENT-NEXT: "start": { -// LARGEINDENT-NEXT: "line": 215, +// LARGEINDENT-NEXT: "line": 31, // LARGEINDENT-NEXT: "character": 5 // LARGEINDENT-NEXT: }, // LARGEINDENT-NEXT: "end": { -// LARGEINDENT-NEXT: "line": 215, +// LARGEINDENT-NEXT: "line": 31, // LARGEINDENT-NEXT: "character": 17 // LARGEINDENT-NEXT: } // LARGEINDENT-NEXT: }, @@ -199,11 +262,11 @@ public struct TwoLines {} // LARGEINDENT-NEXT: { // LARGEINDENT-NEXT: "range": { // LARGEINDENT-NEXT: "start": { -// LARGEINDENT-NEXT: "line": 216, +// LARGEINDENT-NEXT: "line": 32, // LARGEINDENT-NEXT: "character": 1 // LARGEINDENT-NEXT: }, // LARGEINDENT-NEXT: "end": { -// LARGEINDENT-NEXT: "line": 216, +// LARGEINDENT-NEXT: "line": 32, // LARGEINDENT-NEXT: "character": 1 // LARGEINDENT-NEXT: } // LARGEINDENT-NEXT: }, @@ -212,22 +275,19 @@ public struct TwoLines {} // LARGEINDENT-NEXT: ] // LARGEINDENT-NEXT: } -/** - Large Indent - */ -public struct LargeIndent {} - // TWOLINESBETWEENBLANK-LABEL: "precise": "s:10BlockStyle20TwoLinesBetweenBlankV" // TWOLINESBETWEENBLANK: "docComment": { +// TWOLINESBETWEENBLANK-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// TWOLINESBETWEENBLANK-NEXT: "module": "BlockStyle", // TWOLINESBETWEENBLANK-NEXT: "lines": [ // TWOLINESBETWEENBLANK-NEXT: { // TWOLINESBETWEENBLANK-NEXT: "range": { // TWOLINESBETWEENBLANK-NEXT: "start": { -// TWOLINESBETWEENBLANK-NEXT: "line": 278, +// TWOLINESBETWEENBLANK-NEXT: "line": 36, // TWOLINESBETWEENBLANK-NEXT: "character": 1 // TWOLINESBETWEENBLANK-NEXT: }, // TWOLINESBETWEENBLANK-NEXT: "end": { -// TWOLINESBETWEENBLANK-NEXT: "line": 278, +// TWOLINESBETWEENBLANK-NEXT: "line": 36, // TWOLINESBETWEENBLANK-NEXT: "character": 10 // TWOLINESBETWEENBLANK-NEXT: } // TWOLINESBETWEENBLANK-NEXT: }, @@ -236,11 +296,11 @@ public struct LargeIndent {} // TWOLINESBETWEENBLANK-NEXT: { // TWOLINESBETWEENBLANK-NEXT: "range": { // TWOLINESBETWEENBLANK-NEXT: "start": { -// TWOLINESBETWEENBLANK-NEXT: "line": 279, +// TWOLINESBETWEENBLANK-NEXT: "line": 37, // TWOLINESBETWEENBLANK-NEXT: "character": 0 // TWOLINESBETWEENBLANK-NEXT: }, // TWOLINESBETWEENBLANK-NEXT: "end": { -// TWOLINESBETWEENBLANK-NEXT: "line": 279, +// TWOLINESBETWEENBLANK-NEXT: "line": 37, // TWOLINESBETWEENBLANK-NEXT: "character": 0 // TWOLINESBETWEENBLANK-NEXT: } // TWOLINESBETWEENBLANK-NEXT: }, @@ -249,11 +309,11 @@ public struct LargeIndent {} // TWOLINESBETWEENBLANK-NEXT: { // TWOLINESBETWEENBLANK-NEXT: "range": { // TWOLINESBETWEENBLANK-NEXT: "start": { -// TWOLINESBETWEENBLANK-NEXT: "line": 280, +// TWOLINESBETWEENBLANK-NEXT: "line": 38, // TWOLINESBETWEENBLANK-NEXT: "character": 1 // TWOLINESBETWEENBLANK-NEXT: }, // TWOLINESBETWEENBLANK-NEXT: "end": { -// TWOLINESBETWEENBLANK-NEXT: "line": 280, +// TWOLINESBETWEENBLANK-NEXT: "line": 38, // TWOLINESBETWEENBLANK-NEXT: "character": 14 // TWOLINESBETWEENBLANK-NEXT: } // TWOLINESBETWEENBLANK-NEXT: }, @@ -262,11 +322,11 @@ public struct LargeIndent {} // TWOLINESBETWEENBLANK-NEXT: { // TWOLINESBETWEENBLANK-NEXT: "range": { // TWOLINESBETWEENBLANK-NEXT: "start": { -// TWOLINESBETWEENBLANK-NEXT: "line": 281, +// TWOLINESBETWEENBLANK-NEXT: "line": 39, // TWOLINESBETWEENBLANK-NEXT: "character": 1 // TWOLINESBETWEENBLANK-NEXT: }, // TWOLINESBETWEENBLANK-NEXT: "end": { -// TWOLINESBETWEENBLANK-NEXT: "line": 281, +// TWOLINESBETWEENBLANK-NEXT: "line": 39, // TWOLINESBETWEENBLANK-NEXT: "character": 1 // TWOLINESBETWEENBLANK-NEXT: } // TWOLINESBETWEENBLANK-NEXT: }, @@ -275,24 +335,19 @@ public struct LargeIndent {} // TWOLINESBETWEENBLANK-NEXT: ] // TWOLINESBETWEENBLANK-NEXT: }, -/** - Two lines - - Between Blank - */ -public struct TwoLinesBetweenBlank {} - // LEADINGBLANK-LABEL: "precise": "s:10BlockStyle12LeadingBlankV" // LEADINGBLANK: "docComment": { +// LEADINGBLANK-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// LEADINGBLANK-NEXT: "module": "BlockStyle", // LEADINGBLANK-NEXT: "lines": [ // LEADINGBLANK-NEXT: { // LEADINGBLANK-NEXT: "range": { // LEADINGBLANK-NEXT: "start": { -// LEADINGBLANK-NEXT: "line": 330, +// LEADINGBLANK-NEXT: "line": 43, // LEADINGBLANK-NEXT: "character": 0 // LEADINGBLANK-NEXT: }, // LEADINGBLANK-NEXT: "end": { -// LEADINGBLANK-NEXT: "line": 330, +// LEADINGBLANK-NEXT: "line": 43, // LEADINGBLANK-NEXT: "character": 0 // LEADINGBLANK-NEXT: } // LEADINGBLANK-NEXT: }, @@ -301,11 +356,11 @@ public struct TwoLinesBetweenBlank {} // LEADINGBLANK-NEXT: { // LEADINGBLANK-NEXT: "range": { // LEADINGBLANK-NEXT: "start": { -// LEADINGBLANK-NEXT: "line": 331, +// LEADINGBLANK-NEXT: "line": 44, // LEADINGBLANK-NEXT: "character": 1 // LEADINGBLANK-NEXT: }, // LEADINGBLANK-NEXT: "end": { -// LEADINGBLANK-NEXT: "line": 331, +// LEADINGBLANK-NEXT: "line": 44, // LEADINGBLANK-NEXT: "character": 14 // LEADINGBLANK-NEXT: } // LEADINGBLANK-NEXT: }, @@ -314,11 +369,11 @@ public struct TwoLinesBetweenBlank {} // LEADINGBLANK-NEXT: { // LEADINGBLANK-NEXT: "range": { // LEADINGBLANK-NEXT: "start": { -// LEADINGBLANK-NEXT: "line": 332, +// LEADINGBLANK-NEXT: "line": 45, // LEADINGBLANK-NEXT: "character": 1 // LEADINGBLANK-NEXT: }, // LEADINGBLANK-NEXT: "end": { -// LEADINGBLANK-NEXT: "line": 332, +// LEADINGBLANK-NEXT: "line": 45, // LEADINGBLANK-NEXT: "character": 1 // LEADINGBLANK-NEXT: } // LEADINGBLANK-NEXT: }, @@ -327,23 +382,19 @@ public struct TwoLinesBetweenBlank {} // LEADINGBLANK-NEXT: ] // LEADINGBLANK-NEXT: }, -/** - - Leading Blank - */ -public struct LeadingBlank {} - // TRAILINGBLANK-LABEL: "precise": "s:10BlockStyle13TrailingBlankV" // TRAILINGBLANK: "docComment": { +// TRAILINGBLANK-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// TRAILINGBLANK-NEXT: "module": "BlockStyle", // TRAILINGBLANK-NEXT: "lines": [ // TRAILINGBLANK-NEXT: { // TRAILINGBLANK-NEXT: "range": { // TRAILINGBLANK-NEXT: "start": { -// TRAILINGBLANK-NEXT: "line": 381, +// TRAILINGBLANK-NEXT: "line": 49, // TRAILINGBLANK-NEXT: "character": 1 // TRAILINGBLANK-NEXT: }, // TRAILINGBLANK-NEXT: "end": { -// TRAILINGBLANK-NEXT: "line": 381, +// TRAILINGBLANK-NEXT: "line": 49, // TRAILINGBLANK-NEXT: "character": 15 // TRAILINGBLANK-NEXT: } // TRAILINGBLANK-NEXT: }, @@ -352,11 +403,11 @@ public struct LeadingBlank {} // TRAILINGBLANK-NEXT: { // TRAILINGBLANK-NEXT: "range": { // TRAILINGBLANK-NEXT: "start": { -// TRAILINGBLANK-NEXT: "line": 382, +// TRAILINGBLANK-NEXT: "line": 50, // TRAILINGBLANK-NEXT: "character": 0 // TRAILINGBLANK-NEXT: }, // TRAILINGBLANK-NEXT: "end": { -// TRAILINGBLANK-NEXT: "line": 382, +// TRAILINGBLANK-NEXT: "line": 50, // TRAILINGBLANK-NEXT: "character": 0 // TRAILINGBLANK-NEXT: } // TRAILINGBLANK-NEXT: }, @@ -365,11 +416,11 @@ public struct LeadingBlank {} // TRAILINGBLANK-NEXT: { // TRAILINGBLANK-NEXT: "range": { // TRAILINGBLANK-NEXT: "start": { -// TRAILINGBLANK-NEXT: "line": 383, +// TRAILINGBLANK-NEXT: "line": 51, // TRAILINGBLANK-NEXT: "character": 1 // TRAILINGBLANK-NEXT: }, // TRAILINGBLANK-NEXT: "end": { -// TRAILINGBLANK-NEXT: "line": 383, +// TRAILINGBLANK-NEXT: "line": 51, // TRAILINGBLANK-NEXT: "character": 1 // TRAILINGBLANK-NEXT: } // TRAILINGBLANK-NEXT: }, @@ -378,23 +429,19 @@ public struct LeadingBlank {} // TRAILINGBLANK-NEXT: ] // TRAILINGBLANK-NEXT: }, -/** - Trailing Blank - - */ -public struct TrailingBlank {} - // BOUNDBLANK-LABEL: "precise": "s:10BlockStyle10BoundBlankV" // BOUNDBLANK: "docComment": { +// BOUNDBLANK-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// BOUNDBLANK-NEXT: "module": "BlockStyle", // BOUNDBLANK-NEXT: "lines": [ // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 445, +// BOUNDBLANK-NEXT: "line": 55, // BOUNDBLANK-NEXT: "character": 0 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 445, +// BOUNDBLANK-NEXT: "line": 55, // BOUNDBLANK-NEXT: "character": 0 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -403,11 +450,11 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 446, +// BOUNDBLANK-NEXT: "line": 56, // BOUNDBLANK-NEXT: "character": 1 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 446, +// BOUNDBLANK-NEXT: "line": 56, // BOUNDBLANK-NEXT: "character": 12 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -416,11 +463,11 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 447, +// BOUNDBLANK-NEXT: "line": 57, // BOUNDBLANK-NEXT: "character": 0 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 447, +// BOUNDBLANK-NEXT: "line": 57, // BOUNDBLANK-NEXT: "character": 0 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -429,11 +476,11 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 448, +// BOUNDBLANK-NEXT: "line": 58, // BOUNDBLANK-NEXT: "character": 1 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 448, +// BOUNDBLANK-NEXT: "line": 58, // BOUNDBLANK-NEXT: "character": 1 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -442,24 +489,19 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: ] // BOUNDBLANK-NEXT: }, -/** - - Bound Blank - - */ -public struct BoundBlank {} - // ALLINDENTED-LABEL: "precise": "s:10BlockStyle11AllIndentedV" // ALLINDENTED: "docComment": { +// ALLINDENTED-NEXT: "uri": "file://{{.*}}BlockStyle.swift", +// ALLINDENTED-NEXT: "module": "BlockStyle", // ALLINDENTED-NEXT: "lines": [ // ALLINDENTED-NEXT: { // ALLINDENTED-NEXT: "range": { // ALLINDENTED-NEXT: "start": { -// ALLINDENTED-NEXT: "line": 484, +// ALLINDENTED-NEXT: "line": 62, // ALLINDENTED-NEXT: "character": 5 // ALLINDENTED-NEXT: }, // ALLINDENTED-NEXT: "end": { -// ALLINDENTED-NEXT: "line": 484, +// ALLINDENTED-NEXT: "line": 62, // ALLINDENTED-NEXT: "character": 18 // ALLINDENTED-NEXT: } // ALLINDENTED-NEXT: }, @@ -468,11 +510,11 @@ public struct BoundBlank {} // ALLINDENTED-NEXT: { // ALLINDENTED-NEXT: "range": { // ALLINDENTED-NEXT: "start": { -// ALLINDENTED-NEXT: "line": 485, +// ALLINDENTED-NEXT: "line": 63, // ALLINDENTED-NEXT: "character": 5 // ALLINDENTED-NEXT: }, // ALLINDENTED-NEXT: "end": { -// ALLINDENTED-NEXT: "line": 485, +// ALLINDENTED-NEXT: "line": 63, // ALLINDENTED-NEXT: "character": 5 // ALLINDENTED-NEXT: } // ALLINDENTED-NEXT: }, @@ -480,21 +522,3 @@ public struct BoundBlank {} // ALLINDENTED-NEXT: } // ALLINDENTED-NEXT: ] // ALLINDENTED-NEXT: }, - - /** - All indented. - */ - public struct AllIndented {} - -// RUN: %empty-directory(%t) -// RUN: %target-build-swift %s -module-name BlockStyle -emit-module-path %t/BlockStyle.swiftmodule -// RUN: %target-swift-symbolgraph-extract -module-name BlockStyle -I %t -pretty-print -output-dir %t -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLESAMELINE -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=EMPTY -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=EMPTYWITHNEWLINE -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLELINE -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=SINGLELINEWITHART -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=LARGEINDENT -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=TWOLINESBETWEENBLANK -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=LEADINGBLANK -// RUN: %FileCheck %s --input-file %t/BlockStyle.symbols.json --check-prefix=TRAILINGBLANK diff --git a/test/SymbolGraph/Symbols/Mixins/DocComment/LineStyle.swift b/test/SymbolGraph/Symbols/Mixins/DocComment/LineStyle.swift index e1ff66989f3aa..9b64e854f51d3 100644 --- a/test/SymbolGraph/Symbols/Mixins/DocComment/LineStyle.swift +++ b/test/SymbolGraph/Symbols/Mixins/DocComment/LineStyle.swift @@ -1,3 +1,39 @@ +// ATTN: The RUN lines and associated tests are at the bottom of the file, to +// keep the source locations stable. + +/// Single line. +public struct SingleLine {} + +/// Two +/// lines. +public struct TwoLines {} + +/// Two lines +/// +/// Around Blank +public struct TwoLinesAroundBlank {} + +/// +public struct Empty {} + +/// +/// +/// +public struct MultiEmpty {} + +/// +/// Leading Blank +public struct LeadingBlank {} + +/// Trailing Blank +/// +public struct TrailingBlank {} + +/// +/// Bound Blank +/// +public struct BoundBlank {} + // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -module-name LineStyle -emit-module-path %t/LineStyle.swiftmodule // RUN: %target-swift-symbolgraph-extract -module-name LineStyle -I %t -pretty-print -output-dir %t @@ -11,15 +47,17 @@ // SINGLELINE-LABEL: "precise": "s:9LineStyle06SingleA0V" // SINGLELINE: "docComment": { +// SINGLELINE-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// SINGLELINE-NEXT: "module": "LineStyle", // SINGLELINE-NEXT: "lines": [ // SINGLELINE-NEXT: { // SINGLELINE-NEXT: "range": { // SINGLELINE-NEXT: "start": { -// SINGLELINE-NEXT: "line": 30, +// SINGLELINE-NEXT: "line": 3, // SINGLELINE-NEXT: "character": 4 // SINGLELINE-NEXT: }, // SINGLELINE-NEXT: "end": { -// SINGLELINE-NEXT: "line": 30, +// SINGLELINE-NEXT: "line": 3, // SINGLELINE-NEXT: "character": 16 // SINGLELINE-NEXT: } // SINGLELINE-NEXT: }, @@ -28,20 +66,19 @@ // SINGLELINE-NEXT: ] // SINGLELINE-NEXT: } -/// Single line. -public struct SingleLine {} - // TWOLINES-LABEL: "precise": "s:9LineStyle8TwoLinesV" // TWOLINES: "docComment": { +// TWOLINES-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// TWOLINES-NEXT: "module": "LineStyle", // TWOLINES-NEXT: "lines": [ // TWOLINES-NEXT: { // TWOLINES-NEXT: "range": { // TWOLINES-NEXT: "start": { -// TWOLINES-NEXT: "line": 65, +// TWOLINES-NEXT: "line": 6, // TWOLINES-NEXT: "character": 4 // TWOLINES-NEXT: }, // TWOLINES-NEXT: "end": { -// TWOLINES-NEXT: "line": 65, +// TWOLINES-NEXT: "line": 6, // TWOLINES-NEXT: "character": 7 // TWOLINES-NEXT: } // TWOLINES-NEXT: }, @@ -50,11 +87,11 @@ public struct SingleLine {} // TWOLINES-NEXT: { // TWOLINES-NEXT: "range": { // TWOLINES-NEXT: "start": { -// TWOLINES-NEXT: "line": 66, +// TWOLINES-NEXT: "line": 7, // TWOLINES-NEXT: "character": 4 // TWOLINES-NEXT: }, // TWOLINES-NEXT: "end": { -// TWOLINES-NEXT: "line": 66, +// TWOLINES-NEXT: "line": 7, // TWOLINES-NEXT: "character": 10 // TWOLINES-NEXT: } // TWOLINES-NEXT: }, @@ -63,21 +100,19 @@ public struct SingleLine {} // TWOLINES-NEXT: ] // TWOLINES-NEXT: }, -/// Two -/// lines. -public struct TwoLines {} - // TWOLINESAROUNDBLANK-LABEL: "precise": "s:9LineStyle19TwoLinesAroundBlankV" // TWOLINESAROUNDBLANK: "docComment": { +// TWOLINESAROUNDBLANK-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// TWOLINESAROUNDBLANK-NEXT: "module": "LineStyle", // TWOLINESAROUNDBLANK-NEXT: "lines": [ // TWOLINESAROUNDBLANK-NEXT: { // TWOLINESAROUNDBLANK-NEXT: "range": { // TWOLINESAROUNDBLANK-NEXT: "start": { -// TWOLINESAROUNDBLANK-NEXT: "line": 114, +// TWOLINESAROUNDBLANK-NEXT: "line": 10, // TWOLINESAROUNDBLANK-NEXT: "character": 4 // TWOLINESAROUNDBLANK-NEXT: }, // TWOLINESAROUNDBLANK-NEXT: "end": { -// TWOLINESAROUNDBLANK-NEXT: "line": 114, +// TWOLINESAROUNDBLANK-NEXT: "line": 10, // TWOLINESAROUNDBLANK-NEXT: "character": 13 // TWOLINESAROUNDBLANK-NEXT: } // TWOLINESAROUNDBLANK-NEXT: }, @@ -86,11 +121,11 @@ public struct TwoLines {} // TWOLINESAROUNDBLANK-NEXT: { // TWOLINESAROUNDBLANK-NEXT: "range": { // TWOLINESAROUNDBLANK-NEXT: "start": { -// TWOLINESAROUNDBLANK-NEXT: "line": 115, +// TWOLINESAROUNDBLANK-NEXT: "line": 11, // TWOLINESAROUNDBLANK-NEXT: "character": 3 // TWOLINESAROUNDBLANK-NEXT: }, // TWOLINESAROUNDBLANK-NEXT: "end": { -// TWOLINESAROUNDBLANK-NEXT: "line": 115, +// TWOLINESAROUNDBLANK-NEXT: "line": 11, // TWOLINESAROUNDBLANK-NEXT: "character": 3 // TWOLINESAROUNDBLANK-NEXT: } // TWOLINESAROUNDBLANK-NEXT: }, @@ -99,11 +134,11 @@ public struct TwoLines {} // TWOLINESAROUNDBLANK-NEXT: { // TWOLINESAROUNDBLANK-NEXT: "range": { // TWOLINESAROUNDBLANK-NEXT: "start": { -// TWOLINESAROUNDBLANK-NEXT: "line": 116, +// TWOLINESAROUNDBLANK-NEXT: "line": 12, // TWOLINESAROUNDBLANK-NEXT: "character": 4 // TWOLINESAROUNDBLANK-NEXT: }, // TWOLINESAROUNDBLANK-NEXT: "end": { -// TWOLINESAROUNDBLANK-NEXT: "line": 116, +// TWOLINESAROUNDBLANK-NEXT: "line": 12, // TWOLINESAROUNDBLANK-NEXT: "character": 16 // TWOLINESAROUNDBLANK-NEXT: } // TWOLINESAROUNDBLANK-NEXT: }, @@ -112,22 +147,19 @@ public struct TwoLines {} // TWOLINESAROUNDBLANK-NEXT: ] // TWOLINESAROUNDBLANK-NEXT: } -/// Two lines -/// -/// Around Blank -public struct TwoLinesAroundBlank {} - // EMPTY-LABEL: "precise": "s:9LineStyle5EmptyV" // EMPTY: "docComment": { +// EMPTY-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// EMPTY-NEXT: "module": "LineStyle", // EMPTY-NEXT: "lines": [ // EMPTY-NEXT: { // EMPTY-NEXT: "range": { // EMPTY-NEXT: "start": { -// EMPTY-NEXT: "line": 138, +// EMPTY-NEXT: "line": 15, // EMPTY-NEXT: "character": 3 // EMPTY-NEXT: }, // EMPTY-NEXT: "end": { -// EMPTY-NEXT: "line": 138, +// EMPTY-NEXT: "line": 15, // EMPTY-NEXT: "character": 3 // EMPTY-NEXT: } // EMPTY-NEXT: }, @@ -136,20 +168,19 @@ public struct TwoLinesAroundBlank {} // EMPTY-NEXT: ] // EMPTY-NEXT: }, -/// -public struct Empty {} - // MULTIEMPTY-LABEL: "precise": "s:9LineStyle10MultiEmptyV" // MULTIEMPTY: "docComment": { +// MULTIEMPTY-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// MULTIEMPTY-NEXT: "module": "LineStyle", // MULTIEMPTY-NEXT: "lines": [ // MULTIEMPTY-NEXT: { // MULTIEMPTY-NEXT: "range": { // MULTIEMPTY-NEXT: "start": { -// MULTIEMPTY-NEXT: "line": 186, +// MULTIEMPTY-NEXT: "line": 18, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: }, // MULTIEMPTY-NEXT: "end": { -// MULTIEMPTY-NEXT: "line": 186, +// MULTIEMPTY-NEXT: "line": 18, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: } // MULTIEMPTY-NEXT: }, @@ -158,11 +189,11 @@ public struct Empty {} // MULTIEMPTY-NEXT: { // MULTIEMPTY-NEXT: "range": { // MULTIEMPTY-NEXT: "start": { -// MULTIEMPTY-NEXT: "line": 187, +// MULTIEMPTY-NEXT: "line": 19, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: }, // MULTIEMPTY-NEXT: "end": { -// MULTIEMPTY-NEXT: "line": 187, +// MULTIEMPTY-NEXT: "line": 19, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: } // MULTIEMPTY-NEXT: }, @@ -171,11 +202,11 @@ public struct Empty {} // MULTIEMPTY-NEXT: { // MULTIEMPTY-NEXT: "range": { // MULTIEMPTY-NEXT: "start": { -// MULTIEMPTY-NEXT: "line": 188, +// MULTIEMPTY-NEXT: "line": 20, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: }, // MULTIEMPTY-NEXT: "end": { -// MULTIEMPTY-NEXT: "line": 188, +// MULTIEMPTY-NEXT: "line": 20, // MULTIEMPTY-NEXT: "character": 3 // MULTIEMPTY-NEXT: } // MULTIEMPTY-NEXT: }, @@ -184,22 +215,19 @@ public struct Empty {} // MULTIEMPTY-NEXT: ] // MULTIEMPTY-NEXT: }, -/// -/// -/// -public struct MultiEmpty {} - // LEADINGBLANK-LABEL: "precise": "s:9LineStyle12LeadingBlankV", // LEADINGBLANK: "docComment": { +// LEADINGBLANK-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// LEADINGBLANK-NEXT: "module": "LineStyle", // LEADINGBLANK-NEXT: "lines": [ // LEADINGBLANK-NEXT: { // LEADINGBLANK-NEXT: "range": { // LEADINGBLANK-NEXT: "start": { -// LEADINGBLANK-NEXT: "line": 223, +// LEADINGBLANK-NEXT: "line": 23, // LEADINGBLANK-NEXT: "character": 3 // LEADINGBLANK-NEXT: }, // LEADINGBLANK-NEXT: "end": { -// LEADINGBLANK-NEXT: "line": 223, +// LEADINGBLANK-NEXT: "line": 23, // LEADINGBLANK-NEXT: "character": 3 // LEADINGBLANK-NEXT: } // LEADINGBLANK-NEXT: }, @@ -208,11 +236,11 @@ public struct MultiEmpty {} // LEADINGBLANK-NEXT: { // LEADINGBLANK-NEXT: "range": { // LEADINGBLANK-NEXT: "start": { -// LEADINGBLANK-NEXT: "line": 224, +// LEADINGBLANK-NEXT: "line": 24, // LEADINGBLANK-NEXT: "character": 4 // LEADINGBLANK-NEXT: }, // LEADINGBLANK-NEXT: "end": { -// LEADINGBLANK-NEXT: "line": 224, +// LEADINGBLANK-NEXT: "line": 24, // LEADINGBLANK-NEXT: "character": 17 // LEADINGBLANK-NEXT: } // LEADINGBLANK-NEXT: }, @@ -221,21 +249,19 @@ public struct MultiEmpty {} // LEADINGBLANK-NEXT: ] // LEADINGBLANK-NEXT: } -/// -/// Leading Blank -public struct LeadingBlank {} - // TRAILINGBLANK-LABEL: "precise": "s:9LineStyle13TrailingBlankV" // TRAILINGBLANK: "docComment": { +// TRAILINGBLANK-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// TRAILINGBLANK-NEXT: "module": "LineStyle", // TRAILINGBLANK-NEXT: "lines": [ // TRAILINGBLANK-NEXT: { // TRAILINGBLANK-NEXT: "range": { // TRAILINGBLANK-NEXT: "start": { -// TRAILINGBLANK-NEXT: "line": 259, +// TRAILINGBLANK-NEXT: "line": 27, // TRAILINGBLANK-NEXT: "character": 4 // TRAILINGBLANK-NEXT: }, // TRAILINGBLANK-NEXT: "end": { -// TRAILINGBLANK-NEXT: "line": 259, +// TRAILINGBLANK-NEXT: "line": 27, // TRAILINGBLANK-NEXT: "character": 18 // TRAILINGBLANK-NEXT: } // TRAILINGBLANK-NEXT: }, @@ -244,11 +270,11 @@ public struct LeadingBlank {} // TRAILINGBLANK-NEXT: { // TRAILINGBLANK-NEXT: "range": { // TRAILINGBLANK-NEXT: "start": { -// TRAILINGBLANK-NEXT: "line": 260, +// TRAILINGBLANK-NEXT: "line": 28, // TRAILINGBLANK-NEXT: "character": 3 // TRAILINGBLANK-NEXT: }, // TRAILINGBLANK-NEXT: "end": { -// TRAILINGBLANK-NEXT: "line": 260, +// TRAILINGBLANK-NEXT: "line": 28, // TRAILINGBLANK-NEXT: "character": 3 // TRAILINGBLANK-NEXT: } // TRAILINGBLANK-NEXT: }, @@ -257,21 +283,19 @@ public struct LeadingBlank {} // TRAILINGBLANK-NEXT: ] // TRAILINGBLANK-NEXT: }, -/// Trailing Blank -/// -public struct TrailingBlank {} - // BOUNDBLANK-LABEL: "precise": "s:9LineStyle10BoundBlankV" // BOUNDBLANK: "docComment": { +// BOUNDBLANK-NEXT: "uri": "file://{{.*}}LineStyle.swift", +// BOUNDBLANK-NEXT: "module": "LineStyle", // BOUNDBLANK-NEXT: "lines": [ // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 308, +// BOUNDBLANK-NEXT: "line": 31, // BOUNDBLANK-NEXT: "character": 3 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 308, +// BOUNDBLANK-NEXT: "line": 31, // BOUNDBLANK-NEXT: "character": 3 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -280,11 +304,11 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 309, +// BOUNDBLANK-NEXT: "line": 32, // BOUNDBLANK-NEXT: "character": 3 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 309, +// BOUNDBLANK-NEXT: "line": 32, // BOUNDBLANK-NEXT: "character": 15 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -293,11 +317,11 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: { // BOUNDBLANK-NEXT: "range": { // BOUNDBLANK-NEXT: "start": { -// BOUNDBLANK-NEXT: "line": 310, +// BOUNDBLANK-NEXT: "line": 33, // BOUNDBLANK-NEXT: "character": 3 // BOUNDBLANK-NEXT: }, // BOUNDBLANK-NEXT: "end": { -// BOUNDBLANK-NEXT: "line": 310, +// BOUNDBLANK-NEXT: "line": 33, // BOUNDBLANK-NEXT: "character": 3 // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: }, @@ -305,8 +329,3 @@ public struct TrailingBlank {} // BOUNDBLANK-NEXT: } // BOUNDBLANK-NEXT: ] // BOUNDBLANK-NEXT: }, - -/// -/// Bound Blank -/// -public struct BoundBlank {} diff --git a/test/SymbolGraph/Symbols/Mixins/DocComment/SourceModule.swift b/test/SymbolGraph/Symbols/Mixins/DocComment/SourceModule.swift new file mode 100644 index 0000000000000..a0833dc807219 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DocComment/SourceModule.swift @@ -0,0 +1,96 @@ +// FYI: The lit commands and FileCheck statements are at the bottom of the file, to be resilient +// against changes to the doc comment format. + +public protocol P { + /// same module doc + func something() +} + +public struct NoDocOverride: Hashable, P { + public func hash(into: inout Hasher) {} + public func something() {} +} + +public struct Override: Hashable, P { + /// override of doc from Swift + public func hash(into: inout Hasher) {} + /// override of doc from same module symbol + public func something() {} +} + +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name SourceModule -emit-module-path %t/SourceModule.swiftmodule +// RUN: %target-swift-symbolgraph-extract -module-name SourceModule -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/SourceModule.symbols.json --check-prefix=NO-OVERRIDE-SAME +// RUN: %FileCheck %s --input-file %t/SourceModule.symbols.json --check-prefix=NO-OVERRIDE-OTHER +// RUN: %FileCheck %s --input-file %t/SourceModule.symbols.json --check-prefix=OVERRIDE-SAME +// RUN: %FileCheck %s --input-file %t/SourceModule.symbols.json --check-prefix=OVERRIDE-OTHER + +// NO-OVERRIDE-SAME-LABEL: "precise": "s:12SourceModule13NoDocOverrideV9somethingyyF" +// NO-OVERRIDE-SAME: "docComment": { +// NO-OVERRIDE-SAME-NEXT: "uri": "file://{{.*}}SourceModule.swift", +// NO-OVERRIDE-SAME-NEXT: "module": "SourceModule", +// NO-OVERRIDE-SAME-NEXT: "lines": [ +// NO-OVERRIDE-SAME-NEXT: { +// NO-OVERRIDE-SAME-NEXT: "range": { +// NO-OVERRIDE-SAME-NEXT: "start": { +// NO-OVERRIDE-SAME-NEXT: "line": 4, +// NO-OVERRIDE-SAME-NEXT: "character": 7 +// NO-OVERRIDE-SAME-NEXT: }, +// NO-OVERRIDE-SAME-NEXT: "end": { +// NO-OVERRIDE-SAME-NEXT: "line": 4, +// NO-OVERRIDE-SAME-NEXT: "character": 22 +// NO-OVERRIDE-SAME-NEXT: } +// NO-OVERRIDE-SAME-NEXT: }, +// NO-OVERRIDE-SAME-NEXT: "text": "same module doc" +// NO-OVERRIDE-SAME-NEXT: } +// NO-OVERRIDE-SAME-NEXT: ] +// NO-OVERRIDE-SAME-NEXT: } + +// NO-OVERRIDE-OTHER-LABEL: "precise": "s:12SourceModule13NoDocOverrideV4hash4intoys6HasherVz_tF" +// NO-OVERRIDE-OTHER: "docComment": { +// NO-OVERRIDE-OTHER-NEXT: "module": "Swift", +// NO-OVERRIDE-OTHER-NEXT: "lines": [ +// actual doc comment lines skipped because they're from the stdlib + +// OVERRIDE-SAME-LABEL: "precise": "s:12SourceModule8OverrideV9somethingyyF", +// OVERRIDE-SAME: "docComment": { +// OVERRIDE-SAME-NEXT: "uri": "file://{{.*}}SourceModule.swift", +// OVERRIDE-SAME-NEXT: "module": "SourceModule", +// OVERRIDE-SAME-NEXT: "lines": [ +// OVERRIDE-SAME-NEXT: { +// OVERRIDE-SAME-NEXT: "range": { +// OVERRIDE-SAME-NEXT: "start": { +// OVERRIDE-SAME-NEXT: "line": 16, +// OVERRIDE-SAME-NEXT: "character": 7 +// OVERRIDE-SAME-NEXT: }, +// OVERRIDE-SAME-NEXT: "end": { +// OVERRIDE-SAME-NEXT: "line": 16, +// OVERRIDE-SAME-NEXT: "character": 46 +// OVERRIDE-SAME-NEXT: } +// OVERRIDE-SAME-NEXT: }, +// OVERRIDE-SAME-NEXT: "text": "override of doc from same module symbol" +// OVERRIDE-SAME-NEXT: } +// OVERRIDE-SAME-NEXT: ] +// OVERRIDE-SAME-NEXT: } + +// OVERRIDE-OTHER-LABEL: "precise": "s:12SourceModule8OverrideV4hash4intoys6HasherVz_tF", +// OVERRIDE-OTHER: "docComment": { +// OVERRIDE-OTHER-NEXT: "uri": "file://{{.*}}SourceModule.swift", +// OVERRIDE-OTHER-NEXT: "module": "SourceModule", +// OVERRIDE-OTHER-NEXT: "lines": [ +// OVERRIDE-OTHER-NEXT: { +// OVERRIDE-OTHER-NEXT: "range": { +// OVERRIDE-OTHER-NEXT: "start": { +// OVERRIDE-OTHER-NEXT: "line": 14, +// OVERRIDE-OTHER-NEXT: "character": 7 +// OVERRIDE-OTHER-NEXT: }, +// OVERRIDE-OTHER-NEXT: "end": { +// OVERRIDE-OTHER-NEXT: "line": 14, +// OVERRIDE-OTHER-NEXT: "character": 33 +// OVERRIDE-OTHER-NEXT: } +// OVERRIDE-OTHER-NEXT: }, +// OVERRIDE-OTHER-NEXT: "text": "override of doc from Swift" +// OVERRIDE-OTHER-NEXT: } +// OVERRIDE-OTHER-NEXT: ] +// OVERRIDE-OTHER-NEXT: }, From 1d500723d634ba245c52caad741049ee6f6c8e4f Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 24 May 2022 18:59:31 +0100 Subject: [PATCH 22/53] Set `SWIFT_ABI_WASM32_LEAST_VALID_POINTER` to 4096 --- stdlib/public/SwiftShims/System.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/SwiftShims/System.h b/stdlib/public/SwiftShims/System.h index 2acfdd417ee03..34174bebe8963 100644 --- a/stdlib/public/SwiftShims/System.h +++ b/stdlib/public/SwiftShims/System.h @@ -213,6 +213,6 @@ // the pointer representation, runtime performance and memory footprint are // worse. So assume that compiler driver uses wasm-ld and --global-base=1024 to // reserve low 1KB. -#define SWIFT_ABI_WASM32_LEAST_VALID_POINTER 1024 +#define SWIFT_ABI_WASM32_LEAST_VALID_POINTER 4096 #endif // SWIFT_STDLIB_SHIMS_ABI_SYSTEM_H From 8775148f7b66bfed6c71fcfee50beffe241823c5 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Tue, 24 May 2022 13:30:33 -0700 Subject: [PATCH 23/53] [SILOpt] Used SetVector for fast contains check. IterableBackwardReachability just requires an iterable list of gens. ShrinkBorrowScope, LexicalDestroyHoisting, and SSADestroyHoisting all need to be able to check whether a given instruction is scope ending quickly. Use a SmallSetVector rather than a SmallVector for the gens in all three. --- include/swift/SILOptimizer/Analysis/Reachability.h | 2 +- lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp | 11 ++++------- lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp | 8 ++++---- lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp | 8 ++++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/include/swift/SILOptimizer/Analysis/Reachability.h b/include/swift/SILOptimizer/Analysis/Reachability.h index e98f9d2901123..1eef74d1d83c3 100644 --- a/include/swift/SILOptimizer/Analysis/Reachability.h +++ b/include/swift/SILOptimizer/Analysis/Reachability.h @@ -149,7 +149,7 @@ class BackwardReachability { /// Effect effectForPhi(SILBasicBlock *); /// /// /// The uses from which reachability will begin. -/// ArrayRef gens(); +/// iterable gens(); /// } template class IterativeBackwardReachability final { diff --git a/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp b/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp index df81319a3d424..8e02d310f56c3 100644 --- a/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp +++ b/lib/SILOptimizer/Transforms/SSADestroyHoisting.cpp @@ -111,7 +111,7 @@ struct KnownStorageUses : UniqueStorageUseVisitor { bool preserveDebugInfo; SmallPtrSet storageUsers; - SmallVector originalDestroys; + SmallSetVector originalDestroys; SmallPtrSet debugInsts; KnownStorageUses(AccessStorage storage, SILFunction *function) @@ -158,7 +158,7 @@ struct KnownStorageUses : UniqueStorageUseVisitor { bool visitStore(Operand *use) override { return recordUser(use->getUser()); } bool visitDestroy(Operand *use) override { - originalDestroys.push_back(use->getUser()); + originalDestroys.insert(use->getUser()); return true; } @@ -283,9 +283,7 @@ class DeinitBarriers final { /// IterativeBackwardReachability::Effects /// VisitBarrierAccessScopes::Effects - ArrayRef gens() { - return result.knownUses.originalDestroys; - } + auto gens() { return result.knownUses.originalDestroys; } Effect effectForInstruction(SILInstruction *instruction); @@ -366,8 +364,7 @@ bool DeinitBarriers::classificationIsBarrier(Classification classification) { DeinitBarriers::DestroyReachability::Effect DeinitBarriers::DestroyReachability::effectForInstruction( SILInstruction *instruction) { - if (llvm::find(result.knownUses.originalDestroys, instruction) != - result.knownUses.originalDestroys.end()) + if (result.knownUses.originalDestroys.contains(instruction)) return Effect::Gen(); auto classification = result.classifyInstruction(instruction); if (recordDeadUsers && classification == Classification::DeadUser) diff --git a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp index 254008483c0a5..91a1374b245a2 100644 --- a/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp +++ b/lib/SILOptimizer/Utils/LexicalDestroyHoisting.cpp @@ -67,7 +67,7 @@ struct Usage final { /// Instructions which are users of the simple (i.e. not reborrowed) value. SmallPtrSet users; // The instructions from which the hoisting starts, the destroy_values. - llvm::SmallVector ends; + llvm::SmallSetVector ends; Usage(){}; Usage(Usage const &) = delete; @@ -89,7 +89,7 @@ bool findUsage(Context const &context, Usage &usage) { // flow and determine whether any were reused. They aren't uses over which // we can't hoist though. if (isa(use->getUser())) { - usage.ends.push_back(use->getUser()); + usage.ends.insert(use->getUser()); } else { usage.users.insert(use->getUser()); } @@ -155,7 +155,7 @@ class Dataflow final { /// IterativeBackwardReachability::Effects /// VisitBarrierAccessScopes::Effects - ArrayRef gens() { return uses.ends; } + auto gens() { return uses.ends; } Effect effectForInstruction(SILInstruction *); Effect effectForPhi(SILBasicBlock *); @@ -211,7 +211,7 @@ bool Dataflow::classificationIsBarrier(Classification classification) { } Dataflow::Effect Dataflow::effectForInstruction(SILInstruction *instruction) { - if (llvm::find(uses.ends, instruction) != uses.ends.end()) + if (uses.ends.contains(instruction)) return Effect::Gen(); auto classification = classifyInstruction(instruction); return classificationIsBarrier(classification) ? Effect::Kill() diff --git a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp index 064eb410dab55..da994b085e4c0 100644 --- a/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp +++ b/lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp @@ -79,7 +79,7 @@ struct Usage final { SmallPtrSet users; // The instructions from which the shrinking starts, the scope ending // instructions. - llvm::SmallVector ends; + llvm::SmallSetVector ends; Usage(){}; Usage(Usage const &) = delete; @@ -99,7 +99,7 @@ bool findUsage(Context const &context, Usage &usage) { // If a scope ending instruction is not an end_borrow, bail out. if (!isa(instruction)) return false; - usage.ends.push_back(instruction); + usage.ends.insert(instruction); } SmallVector uses; @@ -181,7 +181,7 @@ class Dataflow final { /// IterativeBackwardReachability::Effects /// VisitBarrierAccessScopes::Effects - ArrayRef gens() { return uses.ends; } + auto gens() { return uses.ends; } Effect effectForInstruction(SILInstruction *); @@ -262,7 +262,7 @@ bool Dataflow::classificationIsBarrier(Classification classification) { } Dataflow::Effect Dataflow::effectForInstruction(SILInstruction *instruction) { - if (llvm::find(uses.ends, instruction) != uses.ends.end()) + if (uses.ends.contains(instruction)) return Effect::Gen(); auto classification = classifyInstruction(instruction); if (recordCopies && classification == Classification::Copy) From 4e9992c26108886a03089030e4496ea9b434cb54 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 24 May 2022 14:20:42 -0700 Subject: [PATCH 24/53] [CSClosure] Fix crash in `fallthrough` statement checking `fallthrough` requires both source and destination `case` "preambles" be type-checked before it could be validated, which means that solution application for `case` statements in a `switch` has to be split in two - preamble first and bodies afterwards. Resolves: https://github.com/apple/swift/issues/59035 Resolves: rdar://93796211 --- lib/Sema/CSClosure.cpp | 19 ++++++++++++++++--- test/expr/closure/multi_statement.swift | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSClosure.cpp b/lib/Sema/CSClosure.cpp index 42373fffe9d8f..6e1a3035a0c08 100644 --- a/lib/Sema/CSClosure.cpp +++ b/lib/Sema/CSClosure.cpp @@ -1409,7 +1409,15 @@ class SyntacticElementSolutionApplication } auto caseStmt = cast(rawCase.get()); - visitCaseStmt(caseStmt); + // Body of the `case` statement can contain a `fallthrough` + // statement that requires both source and destination + // `case` preambles to be type-checked, so bodies of `case` + // statements should be visited after preambles. + visitCaseStmtPreamble(caseStmt); + } + + for (auto *caseStmt : switchStmt->getCases()) { + visitCaseStmtBody(caseStmt); // Check restrictions on '@unknown'. if (caseStmt->hasUnknownAttr()) { @@ -1436,7 +1444,7 @@ class SyntacticElementSolutionApplication return doStmt; } - ASTNode visitCaseStmt(CaseStmt *caseStmt) { + void visitCaseStmtPreamble(CaseStmt *caseStmt) { // Translate the patterns and guard expressions for each case label item. for (auto &caseItem : caseStmt->getMutableCaseLabelItems()) { SolutionApplicationTarget caseTarget(&caseItem, @@ -1453,11 +1461,16 @@ class SyntacticElementSolutionApplication solution.getType(prev)->mapTypeOutOfContext()); expected->setInterfaceType(type); } + } - // Translate the body. + void visitCaseStmtBody(CaseStmt *caseStmt) { auto *newBody = visit(caseStmt->getBody()).get(); caseStmt->setBody(cast(newBody)); + } + ASTNode visitCaseStmt(CaseStmt *caseStmt) { + visitCaseStmtPreamble(caseStmt); + visitCaseStmtBody(caseStmt); return caseStmt; } diff --git a/test/expr/closure/multi_statement.swift b/test/expr/closure/multi_statement.swift index 1b9f25761c68e..90bf7b58bce65 100644 --- a/test/expr/closure/multi_statement.swift +++ b/test/expr/closure/multi_statement.swift @@ -404,3 +404,23 @@ func test_type_finder_doesnt_walk_into_inner_closures() { return x } } + +// rdar://93796211 (issue#59035) - crash during solution application to fallthrough statement +func test_fallthrough_stmt() { + { + var collector: [Void] = [] + for _: Void in [] { + switch (() as Void?, ()) { + case (let a?, let b): + // expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}} + // expected-note@-2 {{add an explicit type annotation to silence this warning}} + collector.append(a) + fallthrough + case (nil, let b): + // expected-warning@-1 {{constant 'b' inferred to have type '()', which may be unexpected}} + // expected-note@-2 {{add an explicit type annotation to silence this warning}} + collector.append(b) + } + } + }() +} From d95cd977030c9f82f790903791f2be0daa1ccdf7 Mon Sep 17 00:00:00 2001 From: Luciano Almeida Date: Wed, 27 Apr 2022 11:03:58 -0300 Subject: [PATCH 25/53] [Sema] Improving implicit closure capture diagnostic wording --- include/swift/AST/DiagnosticsSema.def | 9 +++ lib/Sema/TypeCheckConcurrency.cpp | 78 +++++++++++++++---- .../concurrent_value_checking.swift | 4 +- test/Concurrency/sr15049.swift | 27 ++++--- .../distributed_protocol_isolation.swift | 1 + 5 files changed, 93 insertions(+), 26 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2100ac8db0c01..2ca207d5b7ce0 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1965,6 +1965,9 @@ NOTE(non_sendable_nominal,none, NOTE(add_nominal_sendable_conformance,none, "consider making %0 %1 conform to the 'Sendable' protocol", (DescriptiveDeclKind, DeclName)) +NOTE(add_generic_parameter_sendable_conformance,none, + "consider making generic parameter %0 conform to the 'Sendable' protocol", + (Type)) REMARK(add_predates_concurrency_import,none, "add '@preconcurrency' to %select{suppress|treat}0 " "'Sendable'-related %select{warnings|errors}0 from module %1" @@ -4570,6 +4573,12 @@ ERROR(concurrent_access_of_inout_param,none, ERROR(non_sendable_capture,none, "capture of %1 with non-sendable type %0 in a `@Sendable` closure", (Type, DeclName)) +ERROR(implicit_async_let_non_sendable_capture,none, + "capture of %1 with non-sendable type %0 in 'async let' binding", + (Type, DeclName)) +ERROR(implicit_non_sendable_capture,none, + "implicit capture of %1 requires that %0 conforms to `Sendable`", + (Type, DeclName)) NOTE(actor_isolated_sync_func,none, "calls to %0 %1 from outside of its actor context are " diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index ea8de940caf68..0c6eda3231b63 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -569,18 +569,27 @@ static void addSendableFixIt( const NominalTypeDecl *nominal, InFlightDiagnostic &diag, bool unchecked) { if (nominal->getInherited().empty()) { SourceLoc fixItLoc = nominal->getBraces().Start; - if (unchecked) - diag.fixItInsert(fixItLoc, ": @unchecked Sendable"); - else - diag.fixItInsert(fixItLoc, ": Sendable"); + diag.fixItInsert(fixItLoc, + unchecked ? ": @unchecked Sendable" : ": Sendable"); } else { - ASTContext &ctx = nominal->getASTContext(); - SourceLoc fixItLoc = nominal->getInherited().back().getSourceRange().End; - fixItLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, fixItLoc); - if (unchecked) - diag.fixItInsert(fixItLoc, ", @unchecked Sendable"); - else - diag.fixItInsert(fixItLoc, ", Sendable"); + auto fixItLoc = nominal->getInherited().back().getLoc(); + diag.fixItInsertAfter(fixItLoc, + unchecked ? ", @unchecked Sendable" : ", Sendable"); + } +} + +/// Add Fix-It text for the given generic param declaration type to adopt +/// Sendable. +static void addSendableFixIt(const GenericTypeParamDecl *genericArgument, + InFlightDiagnostic &diag, bool unchecked) { + if (genericArgument->getInherited().empty()) { + auto fixItLoc = genericArgument->getLoc(); + diag.fixItInsertAfter(fixItLoc, + unchecked ? ": @unchecked Sendable" : ": Sendable"); + } else { + auto fixItLoc = genericArgument->getInherited().back().getLoc(); + diag.fixItInsertAfter(fixItLoc, + unchecked ? ", @unchecked Sendable" : ", Sendable"); } } @@ -874,6 +883,18 @@ static bool diagnoseSingleNonSendableType( nominal->diagnose( diag::non_sendable_nominal, nominal->getDescriptiveKind(), nominal->getName()); + } else if (auto genericArchetype = type->getAs()) { + auto interfaceType = genericArchetype->getInterfaceType(); + if (auto genericParamType = + interfaceType->getAs()) { + auto *genericParamTypeDecl = genericParamType->getDecl(); + if (genericParamTypeDecl && + genericParamTypeDecl->getModuleContext() == module) { + auto diag = genericParamTypeDecl->diagnose( + diag::add_generic_parameter_sendable_conformance, type); + addSendableFixIt(genericParamTypeDecl, diag, /*unchecked=*/false); + } + } } return false; @@ -1527,6 +1548,7 @@ namespace { SmallVector contextStack; SmallVector applyStack; SmallVector, 4> opaqueValues; + SmallVector patternBindingStack; /// Keeps track of the capture context of variables that have been /// explicitly captured in closures. @@ -1539,6 +1561,10 @@ namespace { using MutableVarParent = llvm::PointerUnion; + const PatternBindingDecl *getTopPatternBindingDecl() const { + return patternBindingStack.empty() ? nullptr : patternBindingStack.back(); + } + /// Mapping from mutable variable reference exprs, or inout expressions, /// to the parent expression, when that parent is either a load or /// an inout expr. @@ -1694,9 +1720,24 @@ namespace { Type type = getDeclContext() ->mapTypeIntoContext(decl->getInterfaceType()) ->getReferenceStorageReferent(); - diagnoseNonSendableTypes( - type, getDeclContext(), capture.getLoc(), - diag::non_sendable_capture, decl->getName()); + + if (closure->isImplicit()) { + auto *patternBindingDecl = getTopPatternBindingDecl(); + if (patternBindingDecl && patternBindingDecl->isAsyncLet()) { + diagnoseNonSendableTypes( + type, getDeclContext(), capture.getLoc(), + diag::implicit_async_let_non_sendable_capture, decl->getName()); + } else { + // Fallback to a generic implicit capture missing sendable + // conformance diagnostic. + diagnoseNonSendableTypes(type, getDeclContext(), capture.getLoc(), + diag::implicit_non_sendable_capture, + decl->getName()); + } + } else { + diagnoseNonSendableTypes(type, getDeclContext(), capture.getLoc(), + diag::non_sendable_capture, decl->getName()); + } } } @@ -1759,6 +1800,10 @@ namespace { contextStack.push_back(func); } + if (auto *PBD = dyn_cast(decl)) { + patternBindingStack.push_back(PBD); + } + return true; } @@ -1768,6 +1813,11 @@ namespace { contextStack.pop_back(); } + if (auto *PBD = dyn_cast(decl)) { + assert(patternBindingStack.back() == PBD); + patternBindingStack.pop_back(); + } + return true; } diff --git a/test/Concurrency/concurrent_value_checking.swift b/test/Concurrency/concurrent_value_checking.swift index b59358496b1aa..e7f6dfd2de7b2 100644 --- a/test/Concurrency/concurrent_value_checking.swift +++ b/test/Concurrency/concurrent_value_checking.swift @@ -255,7 +255,7 @@ var concurrentFuncVar: (@Sendable (NotConcurrent) -> Void)? = nil // ---------------------------------------------------------------------- func acceptConcurrentUnary(_: @Sendable (T) -> T) { } -func concurrentClosures(_: T) { +func concurrentClosures(_: T) { // expected-note{{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{26-26=: Sendable}} acceptConcurrentUnary { (x: T) in _ = x // ok acceptConcurrentUnary { _ in x } // expected-warning{{capture of 'x' with non-sendable type 'T' in a `@Sendable` closure}} @@ -269,7 +269,7 @@ struct S1: Sendable { var nc: NotConcurrent // expected-warning{{stored property 'nc' of 'Sendable'-conforming struct 'S1' has non-sendable type 'NotConcurrent'}} } -struct S2: Sendable { +struct S2: Sendable { // expected-note{{consider making generic parameter 'T' conform to the 'Sendable' protocol}} {{12-12=: Sendable}} var nc: T // expected-warning{{stored property 'nc' of 'Sendable'-conforming generic struct 'S2' has non-sendable type 'T'}} } diff --git a/test/Concurrency/sr15049.swift b/test/Concurrency/sr15049.swift index aa1fe89afe9ee..2092d86e94fd4 100644 --- a/test/Concurrency/sr15049.swift +++ b/test/Concurrency/sr15049.swift @@ -19,26 +19,33 @@ func testAsyncSequence1Sendable(_ seq: Seq) async throws whe async let _ = seq.reduce(0) { $0 + $1 } // OK } -// TODO(diagnostics) [SR-16092]: Add a tailored wording for implicit autoclosure captures in sendable warnings, because -// from user perspective there is no closure capture, so diagnostic can be confusing. -func testAsyncSequenceTypedPattern(_ seq: Seq) async throws where Seq.Element == Int { +func testAsyncSequenceTypedPattern(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{54-54=, Sendable}} async let result: Int = seq.reduce(0) { $0 + $1 } // OK // expected-warning@-1{{immutable value 'result' was never used; consider replacing with '_' or removing it}} - // expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in a `@Sendable` closure}} + // expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} } -func testAsyncSequenceTypedPattern1(_ seq: Seq) async throws where Seq.Element == Int { +func testAsyncSequenceTypedPattern1(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{55-55=, Sendable}} async let _: Int = seq.reduce(0) { $0 + $1 } // OK - // expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in a `@Sendable` closure}} + // expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} } -func testAsyncSequence(_ seq: Seq) async throws where Seq.Element == Int { +func testAsyncSequence(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{42-42=, Sendable}} async let result = seq.reduce(0) { $0 + $1 } // OK // expected-warning@-1{{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}} - // expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in a `@Sendable` closure}} + // expected-warning@-2{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} } -func testAsyncSequence1(_ seq: Seq) async throws where Seq.Element == Int { +func testAsyncSequence1(_ seq: Seq) async throws where Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{43-43=, Sendable}} async let _ = seq.reduce(0) { $0 + $1 } // OK - // expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in a `@Sendable` closure}} + // expected-warning@-1{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} +} + +func testAsyncSequence3(_ seq: Seq) async throws where Seq: AsyncSequence, Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{28-28=: Sendable}} + async let result = seq // expected-warning{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} + //expected-warning@-1{{initialization of immutable value 'result' was never used; consider replacing with assignment to '_' or removing it}} +} + +func testAsyncSequence4(_ seq: Seq) async throws where Seq: AsyncSequence, Seq.Element == Int { // expected-note{{consider making generic parameter 'Seq' conform to the 'Sendable' protocol}} {{28-28=: Sendable}} + async let _ = seq // expected-warning{{capture of 'seq' with non-sendable type 'Seq' in 'async let' binding}} } diff --git a/test/Distributed/distributed_protocol_isolation.swift b/test/Distributed/distributed_protocol_isolation.swift index c1075f76bd812..5c7e86bfd3a36 100644 --- a/test/Distributed/distributed_protocol_isolation.swift +++ b/test/Distributed/distributed_protocol_isolation.swift @@ -127,6 +127,7 @@ protocol Server { func send(message: Message) async throws -> String } actor MyServer : Server { + // expected-note@+1{{consider making generic parameter 'Message' conform to the 'Sendable' protocol}} {{29-29=, Sendable}} func send(message: Message) throws -> String { "" } // expected-warning{{non-sendable type 'Message' in parameter of actor-isolated instance method 'send(message:)' satisfying non-isolated protocol requirement cannot cross actor boundary}} } From 7e40114a3d0799a3332e311bc3af6e18631b48aa Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Tue, 24 May 2022 17:02:30 -0700 Subject: [PATCH 26/53] Sema: Downgrade diagnostics about inheritance from a less available type when `-target-min-inlining-version min` is specified. As a concession to source compatibility for API libraries, downgrade diagnostics about inheritance from a less available type when the following conditions are met: 1. The inherited type is only potentially unavailable before the deployment target. 2. The inheriting type is `@usableFromInline`. Resolves rdar://92747826 --- lib/Sema/TypeCheckAccess.cpp | 16 ++++++++++++++-- test/attr/attr_inlinable_available.swift | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp index 31dfc556efc61..64e537f3b4056 100644 --- a/lib/Sema/TypeCheckAccess.cpp +++ b/lib/Sema/TypeCheckAccess.cpp @@ -1746,10 +1746,22 @@ class DeclAvailabilityChecker : public DeclVisitor { void visitNominalTypeDecl(const NominalTypeDecl *nominal) { checkGenericParams(nominal, nominal); + DeclAvailabilityFlags flags = + DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol; + + // As a concession to source compatibility for API libraries, downgrade + // diagnostics about inheritance from a less available type when the + // following conditions are met: + // 1. The inherited type is only potentially unavailable before the + // deployment target. + // 2. The inheriting type is `@usableFromInline`. + if (nominal->getAttrs().hasAttribute()) + flags |= DeclAvailabilityFlag:: + WarnForPotentialUnavailabilityBeforeDeploymentTarget; + llvm::for_each(nominal->getInherited(), [&](TypeLoc inherited) { checkType(inherited.getType(), inherited.getTypeRepr(), nominal, - ExportabilityReason::General, - DeclAvailabilityFlag::AllowPotentiallyUnavailableProtocol); + ExportabilityReason::General, flags); }); } diff --git a/test/attr/attr_inlinable_available.swift b/test/attr/attr_inlinable_available.swift index 85edb1d1ffa74..19250fad6cca9 100644 --- a/test/attr/attr_inlinable_available.swift +++ b/test/attr/attr_inlinable_available.swift @@ -1290,6 +1290,11 @@ public enum NoAvailableEnumWithClasses { public class InheritsBetweenTargets: BetweenTargetsClass {} // expected-error {{'BetweenTargetsClass' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note 2 {{add @available attribute to enclosing class}} public class InheritsAtDeploymentTarget: AtDeploymentTargetClass {} // expected-error {{'AtDeploymentTargetClass' is only available in macOS 10.15 or newer; clients of 'Test' may have a lower deployment target}} expected-note 2 {{add @available attribute to enclosing class}} public class InheritsAfterDeploymentTarget: AfterDeploymentTargetClass {} // expected-error {{'AfterDeploymentTargetClass' is only available in macOS 11 or newer}} expected-note 2 {{add @available attribute to enclosing class}} + + // As a special case, downgrade the less available superclasses diagnostic for + // `@usableFromInline` classes. + @usableFromInline + class UFIInheritsBetweenTargets: BetweenTargetsClass {} // expected-warning {{'BetweenTargetsClass' is only available in macOS 10.14.5 or newer; clients of 'Test' may have a lower deployment target}} expected-note 2 {{add @available attribute to enclosing class}} } @_spi(Private) From baa4123bd778aa13a7c7159c94640da4991bdec2 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Tue, 24 May 2022 18:29:14 -0600 Subject: [PATCH 27/53] use getConformingProtocols when printing opaque generic types (#58991) * use getConformingProtocols when printing opaque generic types rdar://93610106 --- lib/AST/ASTPrinter.cpp | 13 +- .../Full/SomeProtocol.swift | 131 ++++++++++++++++++ 2 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Full/SomeProtocol.swift diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 62a75827ff45a..1a99e633e1f0a 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -57,6 +57,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" @@ -6397,10 +6398,16 @@ class TypePrinter : public TypeVisitor { // Print based on the type. Printer << "some "; - if (auto inheritedType = decl->getInherited().front().getType()) - inheritedType->print(Printer, Options); - else + if (!decl->getConformingProtocols().empty()) { + llvm::interleave(decl->getConformingProtocols(), Printer, [&](ProtocolDecl *proto){ + if (auto printType = proto->getDeclaredType()) + printType->print(Printer, Options); + else + Printer << proto->getNameStr(); + }, " & "); + } else { Printer << "Any"; + } return; } diff --git a/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Full/SomeProtocol.swift b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Full/SomeProtocol.swift new file mode 100644 index 0000000000000..60462d57867a4 --- /dev/null +++ b/test/SymbolGraph/Symbols/Mixins/DeclarationFragments/Full/SomeProtocol.swift @@ -0,0 +1,131 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name SomeProtocol -emit-module -emit-module-path %t/ +// RUN: %target-swift-symbolgraph-extract -module-name SomeProtocol -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/SomeProtocol.symbols.json +// RUN: %FileCheck %s --input-file %t/SomeProtocol.symbols.json --check-prefix MULTI + +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -module-name SomeProtocol -emit-module -emit-module-path %t/SomeProtocol.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ +// RUN: %{python} -m json.tool %t/SomeProtocol.symbols.json %t/SomeProtocol.formatted.symbols.json +// RUN: %FileCheck %s --input-file %t/SomeProtocol.formatted.symbols.json +// RUN: %FileCheck %s --input-file %t/SomeProtocol.formatted.symbols.json --check-prefix MULTI + +// Make sure that `some MyProtocol` parameters don't crash swift-symbolgraph-extract, and that it +// properly renders `some MyProtocol & OtherProtocol` parameters with multiple protocols listed. + +public protocol SomeProtocol {} + +public func doSomething(with param: some SomeProtocol) {} + +public protocol OtherProtocol {} + +public func doSomethingElse(with param: some SomeProtocol & OtherProtocol) {} + +// CHECK-LABEL: "precise": "s:12SomeProtocol11doSomething4withyx_tA2ARzlF", + +// the functionSignature fragments come before the full fragments, so skip those +// CHECK: "functionSignature": { +// CHECK: "declarationFragments": [ + +// CHECK: "declarationFragments": [ +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "keyword", +// CHECK-NEXT: "spelling": "func" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "text", +// CHECK-NEXT: "spelling": " " +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "identifier", +// CHECK-NEXT: "spelling": "doSomething" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "text", +// CHECK-NEXT: "spelling": "(" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "externalParam", +// CHECK-NEXT: "spelling": "with" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "text", +// CHECK-NEXT: "spelling": " " +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "internalParam", +// CHECK-NEXT: "spelling": "param" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "text", +// CHECK-NEXT: "spelling": ": some " +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "typeIdentifier", +// CHECK-NEXT: "spelling": "SomeProtocol", +// CHECK-NEXT: "preciseIdentifier": "s:12SomeProtocolAAP" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "kind": "text", +// CHECK-NEXT: "spelling": ")" +// CHECK-NEXT: } +// CHECK-NEXT: ], + +// MULTI-LABEL: "precise": "s:12SomeProtocol15doSomethingElse4withyx_tAA05OtherB0RzA2ARzlF", + +// the functionSignature fragments come before the full fragments, so skip those +// MULTI: "functionSignature": { +// MULTI: "declarationFragments": [ + +// MULTI: "declarationFragments": [ +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "keyword", +// MULTI-NEXT: "spelling": "func" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": " " +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "identifier", +// MULTI-NEXT: "spelling": "doSomethingElse" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": "(" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "externalParam", +// MULTI-NEXT: "spelling": "with" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": " " +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "internalParam", +// MULTI-NEXT: "spelling": "param" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": ": some " +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "typeIdentifier", +// MULTI-NEXT: "spelling": "OtherProtocol", +// MULTI-NEXT: "preciseIdentifier": "s:12SomeProtocol05OtherB0P" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": " & " +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "typeIdentifier", +// MULTI-NEXT: "spelling": "SomeProtocol", +// MULTI-NEXT: "preciseIdentifier": "s:12SomeProtocolAAP" +// MULTI-NEXT: }, +// MULTI-NEXT: { +// MULTI-NEXT: "kind": "text", +// MULTI-NEXT: "spelling": ")" +// MULTI-NEXT: } +// MULTI-NEXT: ], From c74cbce95a552767037f47a3c04b5c1434199a39 Mon Sep 17 00:00:00 2001 From: Philip Turner Date: Tue, 24 May 2022 23:32:04 -0700 Subject: [PATCH 28/53] Fix incorrect derivative (#41423) --- .../Differentiation/FloatingPointDifferentiation.swift.gyb | 2 +- test/AutoDiff/stdlib/floating_point.swift.gyb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb index 627dbd07863bb..3414fd8a51004 100644 --- a/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb +++ b/stdlib/public/Differentiation/FloatingPointDifferentiation.swift.gyb @@ -268,7 +268,7 @@ where func _vjpAddingProduct( _ lhs: Self, _ rhs: Self ) -> (value: Self, pullback: (Self) -> (Self, Self, Self)) { - return (addingProduct(lhs, rhs), { _ in (1, rhs, lhs) }) + return (addingProduct(lhs, rhs), { v in (v, v * rhs, v * lhs) }) } @inlinable // FIXME(sil-serialize-all) diff --git a/test/AutoDiff/stdlib/floating_point.swift.gyb b/test/AutoDiff/stdlib/floating_point.swift.gyb index de94184c4f62f..d9e398bb0f0ab 100644 --- a/test/AutoDiff/stdlib/floating_point.swift.gyb +++ b/test/AutoDiff/stdlib/floating_point.swift.gyb @@ -81,6 +81,7 @@ FloatingPointDerivativeTests.test("${Self}.squareRoot") { FloatingPointDerivativeTests.test("${Self}.addingProduct") { expectEqual((1, 2, 3), gradient(at: ${Self}(10), 3, 2, of: { $0.addingProduct($1, $2) })) + expectEqual((2, 4, 6), pullback(at: ${Self}(10), 3, 2, of: { $0.addingProduct($1, $2) })(2)) } FloatingPointDerivativeTests.test("${Self}.minimum") { From e75c56b6663dfa4366875992c14ef1ca46ed677a Mon Sep 17 00:00:00 2001 From: Alex Hoppen Date: Wed, 25 May 2022 15:02:52 +0200 Subject: [PATCH 29/53] [SwiftSyntax] Fix assertion failure if regex literal was not terminated at the end of the file Fixes a SwiftSyntax parsing assertion failure if there is a regex literal at the end of the file. I.e. either a single line regex literal in a file without a trailing newline or a multi-line regex literal. This does not crash in non-assert builds. --- lib/Parse/SyntaxRegexFallbackLexing.cpp | 2 +- test/Syntax/Parser/unterminated_multiline_regex.swift | 6 ++++++ test/Syntax/Parser/unterminated_regex.swift | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/Syntax/Parser/unterminated_multiline_regex.swift create mode 100644 test/Syntax/Parser/unterminated_regex.swift diff --git a/lib/Parse/SyntaxRegexFallbackLexing.cpp b/lib/Parse/SyntaxRegexFallbackLexing.cpp index 49da5deb8addf..7a0077665fddf 100644 --- a/lib/Parse/SyntaxRegexFallbackLexing.cpp +++ b/lib/Parse/SyntaxRegexFallbackLexing.cpp @@ -114,7 +114,7 @@ bool syntaxparse_lexRegexLiteral( case '\0': { if (Ptr - 1 == BufferEnd) { // Reached to EOF. - diagnose(BridgedDiagEngine, Ptr, diag::lex_regex_literal_unterminated); + diagnose(BridgedDiagEngine, Ptr - 1, diag::lex_regex_literal_unterminated); // In multi-line mode, we don't want to skip over what is likely // otherwise valid Swift code, so resume from the first newline. *InputPtr = firstNewline ? firstNewline : (Ptr - 1); diff --git a/test/Syntax/Parser/unterminated_multiline_regex.swift b/test/Syntax/Parser/unterminated_multiline_regex.swift new file mode 100644 index 0000000000000..b083f28d64c55 --- /dev/null +++ b/test/Syntax/Parser/unterminated_multiline_regex.swift @@ -0,0 +1,6 @@ +// RUN: %swift-syntax-parser-test -dump-diags %s | %FileCheck %s +// CHECK: 7:1 Error: unterminated regex literal +// CHECK: 1 error(s) 0 warnings(s) 0 note(s) + +#/ +unterminatedLiteral diff --git a/test/Syntax/Parser/unterminated_regex.swift b/test/Syntax/Parser/unterminated_regex.swift new file mode 100644 index 0000000000000..041ac86bc08d8 --- /dev/null +++ b/test/Syntax/Parser/unterminated_regex.swift @@ -0,0 +1,6 @@ +// RUN: %swift-syntax-parser-test -dump-diags %s | %FileCheck %s +// CHECK: 6:21 Error: unterminated regex literal +// CHECK: 1 error(s) 0 warnings(s) 0 note(s) + +// IMPORTANT: This file must not contain a trailing newline +/unterminatedLiteral \ No newline at end of file From ccbef09a709c7dd08a5343e5f6d1d05ead4aa069 Mon Sep 17 00:00:00 2001 From: Philippe Hausler Date: Wed, 25 May 2022 08:57:10 -0700 Subject: [PATCH 30/53] Add release notes for SE-0329: Clock, Instant, and Duration --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad496e0758840..3d69a27e10c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ _**Note:** This is in reverse chronological order, so newer entries are added to ## Swift 5.7 +* [SE-0329][]: + New types representing time and clocks were introduced. This includes a protocol `Clock` defining clocks which allow for defining a concept of now and a way to wake up after a given instant. Additionally a new protocol `InstantProtocol` for defining instants in time was added. Furthermore a new protocol `DurationProtocol` was added to define an elapsed duration between two given `InstantProtocol` types. Most commonly the `Clock` types for general use are the `SuspendingClock` and `ContinuousClock` which represent the most fundamental clocks for the system. The `SuspendingClock` type does not progress while the machine is suspended whereas the `ContinuousClock` progresses no matter the state of the machine. + + ```swift + func delayedHello() async throws { + try await Task.sleep(until: .now + .milliseconds(123), clock: .continuous) + print("hello delayed world") + } + ``` + + `Clock` also has methods to measure the elapsed duration of the execution of work. In the case of the `SuspendingClock` and `ContinuousClock` this measures with high resolution and is suitable for benchmarks. + + ```swift + let clock = ContinuousClock() + let elapsed = clock.measure { + someLongRunningWork() + } + ``` + * References to `optional` methods on a protocol metatype, as well as references to dynamically looked up methods on the `AnyObject` metatype are now supported. These references always have the type of a function that accepts a single argument and returns an optional value of function type: ```swift @@ -9257,6 +9276,7 @@ Swift 1.0 [SE-0326]: [SE-0327]: [SE-0328]: +[SE-0329]: [SE-0331]: [SE-0333]: [SE-0334]: From 663722d892cdbdce2f909f3ab04e35f5aa17cd62 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 25 May 2022 09:50:33 -0700 Subject: [PATCH 31/53] Parameterized Existential Types Are Enabled By Default See https://forums.swift.org/t/accepted-se-0353-constrained-existential-types/57560 --- include/swift/Basic/LangOptions.h | 4 ---- include/swift/Option/FrontendOptions.td | 4 ---- lib/Frontend/CompilerInvocation.cpp | 3 --- lib/Sema/TypeCheckType.cpp | 2 +- lib/Sema/TypeCheckType.h | 8 ++------ .../Constraints/parameterized_existential_metatypes.swift | 2 +- test/IRGen/existential_shape_metadata.swift | 2 +- test/Interpreter/parameterized_existentials.swift | 2 +- test/RemoteAST/parameterized_existentials.swift | 2 +- test/SILGen/parameterized_existentials.swift | 2 +- .../cast_folding_parameterized_protocol.swift | 2 +- test/Sema/availability_parameterized_existential.swift | 6 +++--- test/Serialization/parameterized_protocol.swift | 4 ++-- test/type/opaque_parameterized_existential.swift | 2 +- test/type/parameterized_existential.swift | 2 +- .../unsupported_recursive_opaque_conformance.swift | 2 +- 16 files changed, 17 insertions(+), 32 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index d4525251bbc6f..279fc24b5d599 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -326,10 +326,6 @@ namespace swift { /// in calls to generic functions. bool EnableOpenedExistentialTypes = false; - /// Enable support for parameterized protocol types in existential - /// position. - bool EnableParameterizedExistentialTypes = false; - /// Enable experimental flow-sensitive concurrent captures. bool EnableExperimentalFlowSensitiveConcurrentCaptures = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 8266445f281aa..d13464e850cf1 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -543,10 +543,6 @@ def enable_explicit_existential_types : Flag<["-"], "enable-explicit-existential-types">, HelpText<"Enable experimental support for explicit existential types">; -def enable_parameterized_existential_types : - Flag<["-"], "enable-parameterized-existential-types">, - HelpText<"Enable experimental support for parameterized existential types">; - def enable_experimental_opened_existential_types : Flag<["-"], "enable-experimental-opened-existential-types">, HelpText<"Enable experimental support for implicitly opened existentials">; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 47abf96b9be15..c670b510e792d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -456,9 +456,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.EnableExperimentalNamedOpaqueTypes |= Args.hasArg(OPT_enable_experimental_named_opaque_types); - Opts.EnableParameterizedExistentialTypes |= - Args.hasArg(OPT_enable_parameterized_existential_types); - Opts.EnableOpenedExistentialTypes = Args.hasFlag(OPT_enable_experimental_opened_existential_types, OPT_disable_experimental_opened_existential_types, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index d769f9747288f..26fa0748611ea 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -632,7 +632,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution, // Build ParameterizedProtocolType if the protocol has a primary associated // type and we're in a supported context (for now just generic requirements, // inheritance clause, extension binding). - if (!resolution.getOptions().isParameterizedProtocolSupported(ctx.LangOpts)) { + if (!resolution.getOptions().isParameterizedProtocolSupported()) { diags.diagnose(loc, diag::parameterized_protocol_not_supported); return ErrorType::get(ctx); } diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index 334d6f1f77f5e..376fd56ab6053 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -284,18 +284,14 @@ class TypeResolutionOptions { } /// Whether parameterized protocol types are supported in this context. - /// - /// FIXME: Remove LangOptions parameter once EnableParameterizedExistentialTypes - /// staging flag is gone. - bool isParameterizedProtocolSupported(const LangOptions &opts) const { + bool isParameterizedProtocolSupported() const { switch (context) { case Context::Inherited: case Context::ExtensionBinding: case Context::GenericRequirement: - return true; case Context::ExistentialConstraint: case Context::MetatypeBase: - return opts.EnableParameterizedExistentialTypes; + return true; case Context::None: case Context::TypeAliasDecl: case Context::GenericTypeAliasDecl: diff --git a/test/Constraints/parameterized_existential_metatypes.swift b/test/Constraints/parameterized_existential_metatypes.swift index be2e6d092b015..5271c9543b11b 100644 --- a/test/Constraints/parameterized_existential_metatypes.swift +++ b/test/Constraints/parameterized_existential_metatypes.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -enable-parameterized-existential-types -disable-availability-checking +// RUN: %target-typecheck-verify-swift -disable-availability-checking // // FIXME: Merge this file with existential_metatypes.swift once -enable-parameterized-existential-types becomes the default diff --git a/test/IRGen/existential_shape_metadata.swift b/test/IRGen/existential_shape_metadata.swift index cbf602e661e54..694bc8d679761 100644 --- a/test/IRGen/existential_shape_metadata.swift +++ b/test/IRGen/existential_shape_metadata.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -disable-availability-checking -enable-parameterized-existential-types | %IRGenFileCheck %s +// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -disable-availability-checking | %IRGenFileCheck %s // CHECK-LABEL: @"$sl26existential_shape_metadata2Q0_pyxXPXGMq" = linkonce_odr hidden constant // CHECK-SAME: { i32 {{.*}}sub ([[INT]] ptrtoint (i8** @{{[0-9]+}} to [[INT]]) diff --git a/test/Interpreter/parameterized_existentials.swift b/test/Interpreter/parameterized_existentials.swift index 01fd712328cd2..d8039fc2d9462 100644 --- a/test/Interpreter/parameterized_existentials.swift +++ b/test/Interpreter/parameterized_existentials.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift(-Xfrontend -enable-parameterized-existential-types -Xfrontend -disable-availability-checking) +// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking) // REQUIRES: executable_test // This test requires the new existential shape metadata accessors which are diff --git a/test/RemoteAST/parameterized_existentials.swift b/test/RemoteAST/parameterized_existentials.swift index 89973c9146ff9..ef1b558c66b28 100644 --- a/test/RemoteAST/parameterized_existentials.swift +++ b/test/RemoteAST/parameterized_existentials.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-remoteast-test -enable-parameterized-existential-types -disable-availability-checking %s | %FileCheck %s +// RUN: %target-swift-remoteast-test -disable-availability-checking %s | %FileCheck %s // REQUIRES: swift-remoteast-test diff --git a/test/SILGen/parameterized_existentials.swift b/test/SILGen/parameterized_existentials.swift index b6b3db9a02292..c36dc22695537 100644 --- a/test/SILGen/parameterized_existentials.swift +++ b/test/SILGen/parameterized_existentials.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen -module-name parameterized -enable-parameterized-existential-types -disable-availability-checking %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -module-name parameterized -disable-availability-checking %s | %FileCheck %s protocol P { associatedtype T diff --git a/test/SILOptimizer/cast_folding_parameterized_protocol.swift b/test/SILOptimizer/cast_folding_parameterized_protocol.swift index 1d8cfe92d141a..aab2fa9b18497 100644 --- a/test/SILOptimizer/cast_folding_parameterized_protocol.swift +++ b/test/SILOptimizer/cast_folding_parameterized_protocol.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend %s -emit-sil -enable-parameterized-existential-types -disable-availability-checking -O -o - | %FileCheck %s +// RUN: %target-swift-frontend %s -emit-sil -disable-availability-checking -O -o - | %FileCheck %s public protocol P { associatedtype T diff --git a/test/Sema/availability_parameterized_existential.swift b/test/Sema/availability_parameterized_existential.swift index 23b63c65f6fcb..ab5318522140b 100644 --- a/test/Sema/availability_parameterized_existential.swift +++ b/test/Sema/availability_parameterized_existential.swift @@ -1,8 +1,8 @@ -// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types -// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types -typecheck %s 2>&1 | %FileCheck %s '--implicit-check-not=:0' +// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module +// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -disable-objc-attr-requires-foundation-module -typecheck %s 2>&1 | %FileCheck %s '--implicit-check-not=:0' // Make sure we do not emit availability errors or warnings when -disable-availability-checking is passed -// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -typecheck -disable-objc-attr-requires-foundation-module -enable-parameterized-existential-types -disable-availability-checking %s 2>&1 | %FileCheck %s '--implicit-check-not=error:' +// RUN: not %target-swift-frontend -target %target-cpu-apple-macosx10.50 -typecheck -disable-objc-attr-requires-foundation-module -disable-availability-checking %s 2>&1 | %FileCheck %s '--implicit-check-not=error:' // REQUIRES: OS=macosx diff --git a/test/Serialization/parameterized_protocol.swift b/test/Serialization/parameterized_protocol.swift index a7212a272a787..1b352a417641e 100644 --- a/test/Serialization/parameterized_protocol.swift +++ b/test/Serialization/parameterized_protocol.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -enable-parameterized-existential-types -emit-module %S/Inputs/parameterized_protocol_other.swift -emit-module-path %t/parameterized_protocol_other.swiftmodule -// RUN: %target-typecheck-verify-swift -enable-parameterized-existential-types -I%t +// RUN: %target-swift-frontend -emit-module %S/Inputs/parameterized_protocol_other.swift -emit-module-path %t/parameterized_protocol_other.swiftmodule +// RUN: %target-typecheck-verify-swift -I%t import parameterized_protocol_other diff --git a/test/type/opaque_parameterized_existential.swift b/test/type/opaque_parameterized_existential.swift index 6714cc5dce09d..ced21b9029ac3 100644 --- a/test/type/opaque_parameterized_existential.swift +++ b/test/type/opaque_parameterized_existential.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-parameterized-existential-types -disable-availability-checking -typecheck -verify %s +// RUN: %target-swift-frontend -disable-availability-checking -typecheck -verify %s // I do not like nested some type params, // I do not like them Σam-i-am diff --git a/test/type/parameterized_existential.swift b/test/type/parameterized_existential.swift index 345774b31f5d2..51152068060d4 100644 --- a/test/type/parameterized_existential.swift +++ b/test/type/parameterized_existential.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -enable-parameterized-existential-types +// RUN: %target-typecheck-verify-swift -disable-availability-checking protocol Sequence { associatedtype Element diff --git a/validation-test/compiler_crashers_2_fixed/unsupported_recursive_opaque_conformance.swift b/validation-test/compiler_crashers_2_fixed/unsupported_recursive_opaque_conformance.swift index 9660050fca9c3..2aa6f773a3984 100644 --- a/validation-test/compiler_crashers_2_fixed/unsupported_recursive_opaque_conformance.swift +++ b/validation-test/compiler_crashers_2_fixed/unsupported_recursive_opaque_conformance.swift @@ -1,4 +1,4 @@ -// RUN: not %target-swift-frontend -disable-availability-checking -emit-ir -enable-parameterized-existential-types %s +// RUN: not %target-swift-frontend -disable-availability-checking -emit-ir %s protocol P { associatedtype X : P From 1ec678ef100ee750ae047f04fb1b7117004e3881 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 25 May 2022 10:00:57 -0700 Subject: [PATCH 32/53] Update CHANGELOG --- CHANGELOG.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 699a37a3941f6..042331e080146 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,10 +72,26 @@ _**Note:** This is in reverse chronological order, so newer entries are added to * [SE-0353][]: - Further generalizing the above, protocol-constrained types can also be used with `any`: + Protocols with primary associated types can now be used in existential types, + enabling same-type constraints on those associated types. + + ``` + let strings: any Collection = [ "Hello" ] + ``` + + Note that language features requiring runtime support like dynamic casts + (`is`, `as?`, `as!`), as well as generic usages of parameterized existentials + in generic types (e.g. `Array>`) involve additional + availability checks to use. Back-deploying usages in generic position can be + worked around with a generic type-erasing wrapper struct, which is now much + simpler to implement: ```swift - func findBestGraph(_: [any Graph]) -> any Graph {...} + struct AnyCollection { + var wrapped: any Collection + } + + let arrayOfCollections: [AnyCollection] = [ /**/ ] ``` * [SE-0358][]: From 3c76bd845fee10181fcd791403cf8713998e26fa Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 25 May 2022 10:04:30 -0700 Subject: [PATCH 33/53] Merge Two Tests --- test/Constraints/existential_metatypes.swift | 30 ++++++++++++++++++ .../parameterized_existential_metatypes.swift | 31 ------------------- 2 files changed, 30 insertions(+), 31 deletions(-) delete mode 100644 test/Constraints/parameterized_existential_metatypes.swift diff --git a/test/Constraints/existential_metatypes.swift b/test/Constraints/existential_metatypes.swift index 962fcd30d5eb2..45bb7365f2f4a 100644 --- a/test/Constraints/existential_metatypes.swift +++ b/test/Constraints/existential_metatypes.swift @@ -90,3 +90,33 @@ func testP3(_ p: P3, something: Something) { func testIUOToAny(_ t: AnyObject.Type!) { let _: Any = t } + +protocol P4 { + associatedtype T +} + +protocol Q4 { + associatedtype T +} + +protocol PP4: P4 { + associatedtype U: P4 +} + +func parameterizedExistentials() { + var qp: (any Q4).Type + var pp: (any P4).Type = qp // expected-error{{cannot convert value of type '(any Q4).Type' to specified type '(any P4).Type'}} + + var qt: any Q4.Type + qt = qp // expected-error{{cannot assign value of type '(any Q4).Type' to type 'any Q4.Type'}} + qp = qt // expected-error{{cannot assign value of type 'any Q4.Type' to type '(any Q4).Type'}} + var pt: any P4.Type = qt // expected-error{{cannot convert value of type 'any Q4.Type' to specified type 'any P4.Type'}} + pt = pp // expected-error{{cannot assign value of type '(any P4).Type' to type 'any P4.Type'}} + pp = pt // expected-error{{cannot assign value of type 'any P4.Type' to type '(any P4).Type'}} + + var ppp: (any PP4).Type + pp = ppp // expected-error{{cannot assign value of type '(any PP4).Type' to type '(any P4).Type'}} + + var ppt: any PP4.Type + pt = ppt +} diff --git a/test/Constraints/parameterized_existential_metatypes.swift b/test/Constraints/parameterized_existential_metatypes.swift deleted file mode 100644 index 5271c9543b11b..0000000000000 --- a/test/Constraints/parameterized_existential_metatypes.swift +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking -// -// FIXME: Merge this file with existential_metatypes.swift once -enable-parameterized-existential-types becomes the default - -protocol P { - associatedtype T -} - -protocol Q { - associatedtype T -} - -protocol PP: P { - associatedtype U: P -} - -var qp: (any Q).Type -var pp: (any P).Type = qp // expected-error{{cannot convert value of type '(any Q).Type' to specified type '(any P).Type'}} - -var qt: any Q.Type -qt = qp // expected-error{{cannot assign value of type '(any Q).Type' to type 'any Q.Type'}} -qp = qt // expected-error{{cannot assign value of type 'any Q.Type' to type '(any Q).Type'}} -var pt: any P.Type = qt // expected-error{{cannot convert value of type 'any Q.Type' to specified type 'any P.Type'}} -pt = pp // expected-error{{cannot assign value of type '(any P).Type' to type 'any P.Type'}} -pp = pt // expected-error{{cannot assign value of type 'any P.Type' to type '(any P).Type'}} - -var ppp: (any PP).Type -pp = ppp // expected-error{{cannot assign value of type '(any PP).Type' to type '(any P).Type'}} - -var ppt: any PP.Type -pt = ppt From b278d7436c2b49fac9f13284902f90c1f5967d7c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 25 May 2022 10:48:20 -0700 Subject: [PATCH 34/53] Update Tests --- test/type/parameterized_protocol.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/type/parameterized_protocol.swift b/test/type/parameterized_protocol.swift index 24e39ce8398fa..947ce3cd697c6 100644 --- a/test/type/parameterized_protocol.swift +++ b/test/type/parameterized_protocol.swift @@ -29,7 +29,7 @@ protocol Invalid5 { /// Test semantics -protocol Sequence { +protocol Sequence { // expected-note {{'Sequence' declared here}} associatedtype Element // expected-note@-1 {{protocol requires nested type 'Element'; do you want to add it?}} } @@ -189,17 +189,17 @@ func returnsSequenceOfInt1() -> Sequence {} // expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}} func takesSequenceOfInt2(_: any Sequence) {} -// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}} func returnsSequenceOfInt2() -> any Sequence {} -// expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}} func typeExpr() { _ = Sequence.self // expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}} _ = any Sequence.self - // expected-error@-1 {{protocol type with type arguments can only be used as a generic constraint}} + // expected-error@-1 {{'self' is not a member type of protocol 'parameterized_protocol.Sequence'}} + + _ = (any Sequence).self } /// Not supported as a protocol composition term for now From a7053e458fff5677272d0313db2a5e46048693a5 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 25 May 2022 12:26:25 -0700 Subject: [PATCH 35/53] [interop][swiftToCxx] emit empty skeleton C++ classes for Swift struct decls --- lib/PrintAsClang/CMakeLists.txt | 3 +- lib/PrintAsClang/DeclAndTypePrinter.cpp | 9 +++++ lib/PrintAsClang/ModuleContentsWriter.cpp | 9 +++++ lib/PrintAsClang/PrintClangValueType.cpp | 33 ++++++++++++++++ lib/PrintAsClang/PrintClangValueType.h | 39 +++++++++++++++++++ .../structs/swift-struct-in-cxx.swift | 20 ++++++++++ 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 lib/PrintAsClang/PrintClangValueType.cpp create mode 100644 lib/PrintAsClang/PrintClangValueType.h create mode 100644 test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift diff --git a/lib/PrintAsClang/CMakeLists.txt b/lib/PrintAsClang/CMakeLists.txt index 7cde5669e33b1..7c283683e1b16 100644 --- a/lib/PrintAsClang/CMakeLists.txt +++ b/lib/PrintAsClang/CMakeLists.txt @@ -5,7 +5,8 @@ add_swift_host_library(swiftPrintAsClang STATIC ModuleContentsWriter.cpp PrimitiveTypeMapping.cpp PrintAsClang.cpp - PrintClangFunction.cpp) + PrintClangFunction.cpp + PrintClangValueType.cpp) target_link_libraries(swiftPrintAsClang PRIVATE swiftAST swiftClangImporter diff --git a/lib/PrintAsClang/DeclAndTypePrinter.cpp b/lib/PrintAsClang/DeclAndTypePrinter.cpp index 598cfe2ba9be1..68fe29479a5ca 100644 --- a/lib/PrintAsClang/DeclAndTypePrinter.cpp +++ b/lib/PrintAsClang/DeclAndTypePrinter.cpp @@ -14,6 +14,7 @@ #include "ClangSyntaxPrinter.h" #include "PrimitiveTypeMapping.h" #include "PrintClangFunction.h" +#include "PrintClangValueType.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" @@ -327,6 +328,14 @@ class DeclAndTypePrinter::Implementation os << "@end\n"; } + void visitStructDecl(StructDecl *SD) { + if (outputLang != OutputLanguageMode::Cxx) + return; + // FIXME: Print struct's availability. + ClangValueTypePrinter printer(os); + printer.printStructDecl(SD); + } + void visitExtensionDecl(ExtensionDecl *ED) { if (isEmptyExtensionDecl(ED)) return; diff --git a/lib/PrintAsClang/ModuleContentsWriter.cpp b/lib/PrintAsClang/ModuleContentsWriter.cpp index fea9e0338367f..9424afb5bc0e8 100644 --- a/lib/PrintAsClang/ModuleContentsWriter.cpp +++ b/lib/PrintAsClang/ModuleContentsWriter.cpp @@ -409,6 +409,13 @@ class ModuleWriter { return true; } + bool writeStruct(const StructDecl *SD) { + if (addImport(SD)) + return true; + printer.print(SD); + return true; + } + bool writeProtocol(const ProtocolDecl *PD) { if (addImport(PD)) return true; @@ -584,6 +591,8 @@ class ModuleWriter { if (outputLangMode == OutputLanguageMode::Cxx) { if (auto FD = dyn_cast(D)) success = writeFunc(FD); + if (auto SD = dyn_cast(D)) + success = writeStruct(SD); // FIXME: Warn on unsupported exported decl. } else if (isa(D)) { if (auto CD = dyn_cast(D)) diff --git a/lib/PrintAsClang/PrintClangValueType.cpp b/lib/PrintAsClang/PrintClangValueType.cpp new file mode 100644 index 0000000000000..c52ebe70d2cbc --- /dev/null +++ b/lib/PrintAsClang/PrintClangValueType.cpp @@ -0,0 +1,33 @@ +//===--- PrintClangValueType.cpp - Printer for C/C++ value types *- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2022 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 +// +//===----------------------------------------------------------------------===// + +#include "PrintClangValueType.h" +#include "ClangSyntaxPrinter.h" +#include "DeclAndTypePrinter.h" +#include "OutputLanguageMode.h" +#include "PrimitiveTypeMapping.h" +#include "swift/AST/Decl.h" +#include "swift/AST/ParameterList.h" +#include "swift/AST/Type.h" +#include "swift/AST/TypeVisitor.h" +#include "swift/ClangImporter/ClangImporter.h" +#include "llvm/ADT/STLExtras.h" + +using namespace swift; + +void ClangValueTypePrinter::printStructDecl(const StructDecl *SD) { + os << "class "; + ClangSyntaxPrinter(os).printIdentifier(SD->getName().str()); + os << " final {\n"; + // FIXME: Print the members of the struct. + os << "};\n"; +} diff --git a/lib/PrintAsClang/PrintClangValueType.h b/lib/PrintAsClang/PrintClangValueType.h new file mode 100644 index 0000000000000..eeb267608b552 --- /dev/null +++ b/lib/PrintAsClang/PrintClangValueType.h @@ -0,0 +1,39 @@ +//===--- PrintClangValueType.h - Printer for C/C++ value types --*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2022 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_PRINTASCLANG_PRINTCLANGVALUETYPE_H +#define SWIFT_PRINTASCLANG_PRINTCLANGVALUETYPE_H + +#include "swift/Basic/LLVM.h" +#include "llvm/Support/raw_ostream.h" + +namespace swift { + +class StructDecl; + +/// Responsible for printing a Swift struct or enum decl or in C or C++ mode, to +/// be included in a Swift module's generated clang header. +class ClangValueTypePrinter { +public: + ClangValueTypePrinter(raw_ostream &os) : os(os) {} + + /// Print the C struct thunk or the C++ class definition that + /// corresponds to the given structure declaration. + void printStructDecl(const StructDecl *SD); + +private: + raw_ostream &os; +}; + +} // end namespace swift + +#endif diff --git a/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift new file mode 100644 index 0000000000000..78f279e6d9669 --- /dev/null +++ b/test/Interop/SwiftToCxx/structs/swift-struct-in-cxx.swift @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -typecheck -module-name Structs -clang-header-expose-public-decls -emit-clang-header-path %t/structs.h +// RUN: %FileCheck %s < %t/structs.h + +// RUN: %check-interop-cxx-header-in-clang(%t/structs.h) + +// CHECK: namespace Structs { + +// CHECK: class StructWithIntField final { +// CHECK-NEXT: }; +struct StructWithIntField { + let field: Int +} + +// Special name gets renamed in C++. +// CHECK: class register_ final { +struct register { +} + +// CHECK: } // namespace Structs From 1bbf180e8abc9397593be04d0d84839091b74a74 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 25 May 2022 15:50:36 -0400 Subject: [PATCH 36/53] Add cursory release note for Regex. --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index acb27dbd3466c..4425ab02971ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,31 @@ _**Note:** This is in reverse chronological order, so newer entries are added to ## Swift 5.7 +* [SE-0350][]: + + The standard library has a new `Regex` type. + + This type represents an _extended regular expression_, allowing more fluent + string processing operations. A `Regex` may be created by + [initialization from a string][SE-0355]: + ``` + let pattern = "a[bc]+" // matches "a" followed by one or more instances + // of either "b" or "c" + let regex = try! Regex(pattern) + ``` + Or via a [regex literal][SE-0354]: + ``` + let regex = #/a[bc]+/# + ``` + In Swift 6, `/` will also be supported as a delimiter for `Regex` literals. + You can enable this mode in Swift 5.7 with the `-enable-bare-slash-regex` + flag. Doing so will cause some existing expressions that use `/` as an + operator to no longer compile; you can add parentheses or line breaks as a + workaround. + + There are [new string-processing algorithms][SE-0357] that support + `String`, `Regex` and arbitrary `Collection` types. + * [SE-0329][]: New types representing time and clocks were introduced. This includes a protocol `Clock` defining clocks which allow for defining a concept of now and a way to wake up after a given instant. Additionally a new protocol `InstantProtocol` for defining instants in time was added. Furthermore a new protocol `DurationProtocol` was added to define an elapsed duration between two given `InstantProtocol` types. Most commonly the `Clock` types for general use are the `SuspendingClock` and `ContinuousClock` which represent the most fundamental clocks for the system. The `SuspendingClock` type does not progress while the machine is suspended whereas the `ContinuousClock` progresses no matter the state of the machine. @@ -9387,8 +9412,12 @@ Swift 1.0 [SE-0346]: [SE-0347]: [SE-0349]: +[SE-0350]: [SE-0352]: [SE-0353]: +[SE-0354]: +[SE-0355]: +[SE-0357]: [SE-0358]: [SR-75]: From 405a02810926222c98e345985708f4b182a44bc1 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 24 May 2022 14:32:45 -0700 Subject: [PATCH 37/53] [Isolation] Factor out the "not a value" check from "okay across actors". --- lib/Sema/TypeCheckConcurrency.cpp | 56 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 0c6eda3231b63..5f889e25f9f91 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -4886,9 +4886,8 @@ bool swift::isThrowsDecl(ConcreteDeclRef declRef) { return false; } -bool swift::isAccessibleAcrossActors( - ValueDecl *value, const ActorIsolation &isolation, - const DeclContext *fromDC, Optional actorInstance) { +/// Determine whether a reference to this value isn't actually a value. +static bool isNonValueReference(const ValueDecl *value) { switch (value->getKind()) { case DeclKind::AssociatedType: case DeclKind::Class: @@ -4899,13 +4898,7 @@ bool swift::isAccessibleAcrossActors( case DeclKind::Protocol: case DeclKind::Struct: case DeclKind::TypeAlias: - return true; - case DeclKind::EnumCase: - case DeclKind::EnumElement: - // Type-level entities are always accessible across actors. - return true; - case DeclKind::IfConfig: case DeclKind::Import: case DeclKind::InfixOperator: @@ -4917,16 +4910,26 @@ bool swift::isAccessibleAcrossActors( case DeclKind::PrecedenceGroup: case DeclKind::PrefixOperator: case DeclKind::TopLevelCode: - // Non-value entities are always accessible across actors. - return true; - case DeclKind::Destructor: - // Destructors are always accessible across actors. return true; + case DeclKind::EnumElement: case DeclKind::Constructor: - // Initializers are accessible across actors unless they are global-actor - // qualified. + case DeclKind::Param: + case DeclKind::Var: + case DeclKind::Accessor: + case DeclKind::Func: + case DeclKind::Subscript: + return false; + } +} + +bool swift::isAccessibleAcrossActors( + ValueDecl *value, const ActorIsolation &isolation, + const DeclContext *fromDC, Optional actorInstance) { + // Initializers and enum elements are accessible across actors unless they + // are global-actor qualified. + if (isa(value) || isa(value)) { switch (isolation) { case ActorIsolation::ActorInstance: case ActorIsolation::Independent: @@ -4937,19 +4940,15 @@ bool swift::isAccessibleAcrossActors( case ActorIsolation::GlobalActor: return false; } + } - case DeclKind::Param: - case DeclKind::Var: - // 'let' declarations are immutable, so some of them can be accessed across - // actors. - return varIsSafeAcrossActors( - fromDC->getParentModule(), cast(value), isolation); - - case DeclKind::Accessor: - case DeclKind::Func: - case DeclKind::Subscript: - return false; + // 'let' declarations are immutable, so some of them can be accessed across + // actors. + if (auto var = dyn_cast(value)) { + return varIsSafeAcrossActors(fromDC->getParentModule(), var, isolation); } + + return false; } ActorReferenceResult ActorReferenceResult::forSameConcurrencyDomain( @@ -4998,6 +4997,11 @@ ActorReferenceResult ActorReferenceResult::forReference( declIsolation = declIsolation.subst(declRef.getSubstitutions()); } + // If the entity we are referencing is not a value, we're in thesame + // concurrency domain. + if (isNonValueReference(declRef.getDecl())) + return forSameConcurrencyDomain(declIsolation); + // Compute the isolation of the context, if not provided. ActorIsolation contextIsolation = ActorIsolation::forUnspecified(); if (knownContextIsolation) { From a8e16297a927abb2dc7db7649d029f38c11033c6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 24 May 2022 22:21:53 -0700 Subject: [PATCH 38/53] Sendable checking for overrides. When an override means crossing an actor boundary, check Sendability of parameters and results. --- include/swift/AST/DiagnosticsSema.def | 10 ++++--- lib/Sema/TypeCheckConcurrency.cpp | 24 ++++++++++------ lib/Sema/TypeCheckConcurrency.h | 3 ++ .../concurrent_value_checking.swift | 4 +-- .../sendable_conformance_checking.swift | 16 +++++------ .../sendable_override_checking.swift | 28 +++++++++++++++++++ .../distributed_protocol_isolation.swift | 2 +- 7 files changed, 63 insertions(+), 24 deletions(-) create mode 100644 test/Concurrency/sendable_override_checking.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2ca207d5b7ce0..f5316ba4de420 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4658,8 +4658,8 @@ ERROR(isolated_parameter_not_actor,none, WARNING(non_sendable_param_type,none, "non-sendable type %0 %select{passed in call to %4 %2 %3|" "passed in implicitly asynchronous call to %4 %2 %3|" - "in parameter of %4 %2 %3 satisfying non-isolated protocol " - "requirement|" + "in parameter of %4 %2 %3 satisfying protocol requirement|" + "in parameter of %4 overriding %2 %3|" "in parameter of %4 '@objc' %2 %3}1 cannot cross actor boundary", (Type, unsigned, DescriptiveDeclKind, DeclName, ActorIsolation)) WARNING(non_sendable_call_param_type,none, @@ -4669,7 +4669,8 @@ WARNING(non_sendable_call_param_type,none, WARNING(non_sendable_result_type,none, "non-sendable type %0 returned by %select{call to %4 %2 %3|" "implicitly asynchronous call to %4 %2 %3|" - "%4 %2 %3 satisfying non-isolated protocol requirement|" + "%4 %2 %3 satisfying protocol requirement|" + "%4 overriding %2 %3|" "%4 '@objc' %2 %3}1 cannot cross actor boundary", (Type, unsigned, DescriptiveDeclKind, DeclName, ActorIsolation)) WARNING(non_sendable_call_result_type,none, @@ -4680,7 +4681,8 @@ WARNING(non_sendable_property_type,none, "non-sendable type %0 in %select{" "%select{asynchronous access to %5 %1 %2|" "implicitly asynchronous access to %5 %1 %2|" - "conformance of %5 %1 %2 to non-isolated protocol requirement|" + "conformance of %5 %1 %2 to protocol requirement|" + "%5 overriding %1 %2|" "%5 '@objc' %1 %2}4|captured local %1 %2}3 cannot " "cross %select{actor|task}3 boundary", (Type, DescriptiveDeclKind, DeclName, bool, unsigned, ActorIsolation)) diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 5f889e25f9f91..d2453cf17ac81 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -3539,6 +3539,16 @@ static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) { return isolation.subst(subs); } +static ConcreteDeclRef getDeclRefInContext(ValueDecl *value) { + auto declContext = value->getInnermostDeclContext(); + if (auto genericEnv = declContext->getGenericEnvironmentOfContext()) { + return ConcreteDeclRef( + value, genericEnv->getForwardingSubstitutionMap()); + } + + return ConcreteDeclRef(value); +} + /// Generally speaking, the isolation of the decl that overrides /// must match the overridden decl. But there are a number of exceptions, /// e.g., the decl that overrides can be nonisolated. @@ -3546,12 +3556,8 @@ static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) { static OverrideIsolationResult validOverrideIsolation( ValueDecl *value, ActorIsolation isolation, ValueDecl *overridden, ActorIsolation overriddenIsolation) { - ConcreteDeclRef valueRef(value); + ConcreteDeclRef valueRef = getDeclRefInContext(value); auto declContext = value->getInnermostDeclContext(); - if (auto genericEnv = declContext->getGenericEnvironmentOfContext()) { - valueRef = ConcreteDeclRef( - value, genericEnv->getForwardingSubstitutionMap()); - } auto refResult = ActorReferenceResult::forReference( valueRef, SourceLoc(), declContext, None, None, @@ -3570,9 +3576,7 @@ static OverrideIsolationResult validOverrideIsolation( if (isAsyncDecl(overridden) || isAccessibleAcrossActors( overridden, refResult.isolation, declContext)) { - // FIXME: Perform Sendable checking here because we're entering an - // actor. - return OverrideIsolationResult::Allowed; + return OverrideIsolationResult::Sendable; } // If the overridden declaration is from Objective-C with no actor @@ -3948,7 +3952,9 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) { return; case OverrideIsolationResult::Sendable: - // FIXME: Do the Sendable check. + diagnoseNonSendableTypesInReference( + getDeclRefInContext(value), value->getInnermostDeclContext(), + value->getLoc(), SendableCheckReason::Override); return; case OverrideIsolationResult::Disallowed: diff --git a/lib/Sema/TypeCheckConcurrency.h b/lib/Sema/TypeCheckConcurrency.h index 413998f976dad..f728e7dd1a954 100644 --- a/lib/Sema/TypeCheckConcurrency.h +++ b/lib/Sema/TypeCheckConcurrency.h @@ -83,6 +83,9 @@ enum class SendableCheckReason { /// actor isolation. Conformance, + /// An override of a function. + Override, + /// The declaration is being exposed to Objective-C. ObjC, }; diff --git a/test/Concurrency/concurrent_value_checking.swift b/test/Concurrency/concurrent_value_checking.swift index e7f6dfd2de7b2..fab8179829e3c 100644 --- a/test/Concurrency/concurrent_value_checking.swift +++ b/test/Concurrency/concurrent_value_checking.swift @@ -223,7 +223,7 @@ protocol AsyncProto { } extension A1: AsyncProto { - func asyncMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of actor-isolated instance method 'asyncMethod' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func asyncMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of actor-isolated instance method 'asyncMethod' satisfying protocol requirement cannot cross actor boundary}} } protocol MainActorProto { @@ -232,7 +232,7 @@ protocol MainActorProto { class SomeClass: MainActorProto { @SomeGlobalActor - func asyncMainMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of global actor 'SomeGlobalActor'-isolated instance method 'asyncMainMethod' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func asyncMainMethod(_: NotConcurrent) async { } // expected-warning{{non-sendable type 'NotConcurrent' in parameter of global actor 'SomeGlobalActor'-isolated instance method 'asyncMainMethod' satisfying protocol requirement cannot cross actor boundary}} } // ---------------------------------------------------------------------- diff --git a/test/Concurrency/sendable_conformance_checking.swift b/test/Concurrency/sendable_conformance_checking.swift index 51041332ab284..32b26df7ecf77 100644 --- a/test/Concurrency/sendable_conformance_checking.swift +++ b/test/Concurrency/sendable_conformance_checking.swift @@ -40,9 +40,9 @@ protocol AsyncProtocolWithNotSendable { // actor's domain. @available(SwiftStdlib 5.1, *) actor A3: AsyncProtocolWithNotSendable { - func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}} - var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to non-isolated protocol requirement cannot cross actor boundary}} + var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}} get async { NotSendable() } @@ -53,9 +53,9 @@ actor A3: AsyncProtocolWithNotSendable { // actor's domain. @available(SwiftStdlib 5.1, *) actor A4: AsyncProtocolWithNotSendable { - func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}} - var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to non-isolated protocol requirement cannot cross actor boundary}} + var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}} get { NotSendable() } @@ -98,9 +98,9 @@ protocol AsyncThrowingProtocolWithNotSendable { // actor's domain. @available(SwiftStdlib 5.1, *) actor A7: AsyncThrowingProtocolWithNotSendable { - func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func f() async -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}} - var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to non-isolated protocol requirement cannot cross actor boundary}} + var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}} get async { NotSendable() } @@ -111,9 +111,9 @@ actor A7: AsyncThrowingProtocolWithNotSendable { // actor's domain. @available(SwiftStdlib 5.1, *) actor A8: AsyncThrowingProtocolWithNotSendable { - func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func f() -> NotSendable { NotSendable() } // expected-warning{{non-sendable type 'NotSendable' returned by actor-isolated instance method 'f()' satisfying protocol requirement cannot cross actor boundary}} - var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to non-isolated protocol requirement cannot cross actor boundary}} + var prop: NotSendable { // expected-warning{{non-sendable type 'NotSendable' in conformance of actor-isolated property 'prop' to protocol requirement cannot cross actor boundary}} get { NotSendable() } diff --git a/test/Concurrency/sendable_override_checking.swift b/test/Concurrency/sendable_override_checking.swift new file mode 100644 index 0000000000000..b3e4c2b02f751 --- /dev/null +++ b/test/Concurrency/sendable_override_checking.swift @@ -0,0 +1,28 @@ +// RUN: %target-typecheck-verify-swift +// REQUIRES: concurrency + +@available(SwiftStdlib 5.1, *) +class NotSendable { // expected-note 2{{class 'NotSendable' does not conform to the 'Sendable' protocol}} +} + +@available(SwiftStdlib 5.1, *) +@available(*, unavailable) +extension NotSendable: Sendable { } + +@available(SwiftStdlib 5.1, *) +class Super { + func f(_: NotSendable) async { } + @MainActor func g1(_: NotSendable) { } + @MainActor func g2(_: NotSendable) async { } +} + +@available(SwiftStdlib 5.1, *) +class Sub: Super { + @MainActor override func f(_: NotSendable) async { } + // expected-warning@-1{{non-sendable type 'NotSendable' in parameter of main actor-isolated overriding instance method 'f' cannot cross actor boundary}} + + nonisolated override func g1(_: NotSendable) { } // okay, synchronous + + nonisolated override func g2(_: NotSendable) async { } + // expected-warning@-1{{non-sendable type 'NotSendable' in parameter of nonisolated overriding instance method 'g2' cannot cross actor boundary}} +} diff --git a/test/Distributed/distributed_protocol_isolation.swift b/test/Distributed/distributed_protocol_isolation.swift index 5c7e86bfd3a36..3c07421c265c1 100644 --- a/test/Distributed/distributed_protocol_isolation.swift +++ b/test/Distributed/distributed_protocol_isolation.swift @@ -128,7 +128,7 @@ protocol Server { } actor MyServer : Server { // expected-note@+1{{consider making generic parameter 'Message' conform to the 'Sendable' protocol}} {{29-29=, Sendable}} - func send(message: Message) throws -> String { "" } // expected-warning{{non-sendable type 'Message' in parameter of actor-isolated instance method 'send(message:)' satisfying non-isolated protocol requirement cannot cross actor boundary}} + func send(message: Message) throws -> String { "" } // expected-warning{{non-sendable type 'Message' in parameter of actor-isolated instance method 'send(message:)' satisfying protocol requirement cannot cross actor boundary}} } protocol AsyncThrowsAll { From 717da76ec2270bdf37a49165afd17ba4a69bae95 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 25 May 2022 08:26:19 -0700 Subject: [PATCH 39/53] [SE-0338] Perform Sendable checking when exiting an actor via conformance. When a requirement is actor-isolated and asynchronous but its witness is non-isolated, perform Sendable checking on the requirement's type. --- lib/Sema/TypeCheckProtocol.cpp | 11 ++++++----- test/Concurrency/sendable_conformance_checking.swift | 8 +++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 2d37c9b919048..d29c31d3c4aa5 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2955,6 +2955,10 @@ bool ConformanceChecker::checkActorIsolation( requirementIsolation = requirementIsolation.subst(subs); } + SourceLoc loc = witness->getLoc(); + if (loc.isInvalid()) + loc = Conformance->getLoc(); + auto refResult = ActorReferenceResult::forReference( getConcreteWitness(), witness->getLoc(), DC, None, None, None, requirementIsolation); @@ -2972,7 +2976,8 @@ bool ConformanceChecker::checkActorIsolation( return false; case ActorReferenceResult::ExitsActorToNonisolated: - // FIXME: SE-0338 would diagnose this. + diagnoseNonSendableTypesInReference( + getConcreteWitness(), DC, loc, SendableCheckReason::Conformance); return false; case ActorReferenceResult::EntersActor: @@ -3016,10 +3021,6 @@ bool ConformanceChecker::checkActorIsolation( // If we aren't missing anything, do a Sendable check and move on. if (!missingOptions) { - SourceLoc loc = witness->getLoc(); - if (loc.isInvalid()) - loc = Conformance->getLoc(); - // FIXME: Disable Sendable checking when the witness is an initializer // that is explicitly marked nonisolated. if (isa(witness) && diff --git a/test/Concurrency/sendable_conformance_checking.swift b/test/Concurrency/sendable_conformance_checking.swift index 32b26df7ecf77..08a602aaa1a34 100644 --- a/test/Concurrency/sendable_conformance_checking.swift +++ b/test/Concurrency/sendable_conformance_checking.swift @@ -2,7 +2,7 @@ // REQUIRES: concurrency @available(SwiftStdlib 5.1, *) -class NotSendable { // expected-note 8{{class 'NotSendable' does not conform to the 'Sendable' protocol}} +class NotSendable { // expected-note 9{{class 'NotSendable' does not conform to the 'Sendable' protocol}} } @available(SwiftStdlib 5.1, *) @@ -13,6 +13,8 @@ extension NotSendable: Sendable { } protocol IsolatedWithNotSendableRequirements: Actor { func f() -> NotSendable var prop: NotSendable { get } + + func fAsync() async -> NotSendable } // Okay, everything is isolated the same way @@ -20,6 +22,7 @@ protocol IsolatedWithNotSendableRequirements: Actor { actor A1: IsolatedWithNotSendableRequirements { func f() -> NotSendable { NotSendable() } var prop: NotSendable { NotSendable() } + func fAsync() async -> NotSendable { NotSendable() } } // Okay, sendable checking occurs when calling through the protocol @@ -28,6 +31,9 @@ actor A1: IsolatedWithNotSendableRequirements { actor A2: IsolatedWithNotSendableRequirements { nonisolated func f() -> NotSendable { NotSendable() } nonisolated var prop: NotSendable { NotSendable() } + + nonisolated func fAsync() async -> NotSendable { NotSendable() } + // expected-warning@-1{{non-sendable type 'NotSendable' returned by nonisolated instance method 'fAsync()' satisfying protocol requirement cannot cross actor boundary}} } @available(SwiftStdlib 5.1, *) From 3faf8c34276cb85b344b32f9b2762766e8ac2c59 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 25 May 2022 14:03:09 -0700 Subject: [PATCH 40/53] [SE-0338] Diagnose Sendable when leaving an actor to call nonisolated async code --- include/swift/AST/DiagnosticsSema.def | 3 +++ lib/Sema/TypeCheckConcurrency.cpp | 27 +++++++++++++------ lib/Sema/TypeCheckConcurrency.h | 6 ++++- test/Concurrency/sendable_checking.swift | 12 +++++++++ .../Concurrency/unsafe_inherit_executor.swift | 4 +-- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index f5316ba4de420..c51f41f9ef8be 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4657,6 +4657,7 @@ ERROR(isolated_parameter_not_actor,none, WARNING(non_sendable_param_type,none, "non-sendable type %0 %select{passed in call to %4 %2 %3|" + "exiting %4 context in call to non-isolated %2 %3|" "passed in implicitly asynchronous call to %4 %2 %3|" "in parameter of %4 %2 %3 satisfying protocol requirement|" "in parameter of %4 overriding %2 %3|" @@ -4668,6 +4669,7 @@ WARNING(non_sendable_call_param_type,none, (Type, bool, ActorIsolation)) WARNING(non_sendable_result_type,none, "non-sendable type %0 returned by %select{call to %4 %2 %3|" + "call from %4 context to non-isolated %2 %3|" "implicitly asynchronous call to %4 %2 %3|" "%4 %2 %3 satisfying protocol requirement|" "%4 overriding %2 %3|" @@ -4680,6 +4682,7 @@ WARNING(non_sendable_call_result_type,none, WARNING(non_sendable_property_type,none, "non-sendable type %0 in %select{" "%select{asynchronous access to %5 %1 %2|" + "asynchronous access from %5 context to non-isolated %1 %2|" "implicitly asynchronous access to %5 %1 %2|" "conformance of %5 %1 %2 to protocol requirement|" "%5 overriding %1 %2|" diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index d2453cf17ac81..7fb6ff24173e5 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -934,7 +934,16 @@ bool swift::diagnoseNonSendableTypes( bool swift::diagnoseNonSendableTypesInReference( ConcreteDeclRef declRef, const DeclContext *fromDC, SourceLoc loc, - SendableCheckReason reason) { + SendableCheckReason reason, Optional knownIsolation) { + + // Retrieve the actor isolation to use in diagnostics. + auto getActorIsolation = [&] { + if (knownIsolation) + return *knownIsolation; + + return swift::getActorIsolation(declRef.getDecl()); + }; + // For functions, check the parameter and result types. SubstitutionMap subs = declRef.getSubstitutions(); if (auto function = dyn_cast(declRef.getDecl())) { @@ -943,7 +952,7 @@ bool swift::diagnoseNonSendableTypesInReference( if (diagnoseNonSendableTypes( paramType, fromDC, loc, diag::non_sendable_param_type, (unsigned)reason, function->getDescriptiveKind(), - function->getName(), getActorIsolation(function))) + function->getName(), getActorIsolation())) return true; } @@ -953,7 +962,7 @@ bool swift::diagnoseNonSendableTypesInReference( if (diagnoseNonSendableTypes( resultType, fromDC, loc, diag::non_sendable_result_type, (unsigned)reason, func->getDescriptiveKind(), func->getName(), - getActorIsolation(func))) + getActorIsolation())) return true; } @@ -970,7 +979,7 @@ bool swift::diagnoseNonSendableTypesInReference( var->getDescriptiveKind(), var->getName(), var->isLocalCapture(), (unsigned)reason, - getActorIsolation(var))) + getActorIsolation())) return true; } @@ -980,7 +989,7 @@ bool swift::diagnoseNonSendableTypesInReference( if (diagnoseNonSendableTypes( paramType, fromDC, loc, diag::non_sendable_param_type, (unsigned)reason, subscript->getDescriptiveKind(), - subscript->getName(), getActorIsolation(subscript))) + subscript->getName(), getActorIsolation())) return true; } @@ -989,7 +998,7 @@ bool swift::diagnoseNonSendableTypesInReference( if (diagnoseNonSendableTypes( resultType, fromDC, loc, diag::non_sendable_result_type, (unsigned)reason, subscript->getDescriptiveKind(), - subscript->getName(), getActorIsolation(subscript))) + subscript->getName(), getActorIsolation())) return true; return false; @@ -2772,8 +2781,10 @@ namespace { if (diagnoseReferenceToUnsafeGlobal(decl, loc)) return true; - // FIXME: SE-0338 would trigger Sendable checks here. - return false; + return diagnoseNonSendableTypesInReference( + declRef, getDeclContext(), loc, + SendableCheckReason::ExitingActor, + result.isolation); case ActorReferenceResult::EntersActor: // Handle all of the checking below. diff --git a/lib/Sema/TypeCheckConcurrency.h b/lib/Sema/TypeCheckConcurrency.h index f728e7dd1a954..0c0a6da141100 100644 --- a/lib/Sema/TypeCheckConcurrency.h +++ b/lib/Sema/TypeCheckConcurrency.h @@ -75,6 +75,9 @@ enum class SendableCheckReason { /// A reference to an actor from outside that actor. CrossActor, + /// Exiting an actor to non-isolated async code. + ExitingActor, + /// A synchronous operation that was "promoted" to an asynchronous one /// because it was out of the actor's domain. SynchronousAsAsync, @@ -271,7 +274,8 @@ struct ActorReferenceResult { /// \returns true if an problem was detected, false otherwise. bool diagnoseNonSendableTypesInReference( ConcreteDeclRef declRef, const DeclContext *fromDC, SourceLoc loc, - SendableCheckReason refKind); + SendableCheckReason refKind, + Optional knownIsolation = None); /// Produce a diagnostic for a missing conformance to Sendable. void diagnoseMissingSendableConformance( diff --git a/test/Concurrency/sendable_checking.swift b/test/Concurrency/sendable_checking.swift index 269ecd597a212..c2714efa40edc 100644 --- a/test/Concurrency/sendable_checking.swift +++ b/test/Concurrency/sendable_checking.swift @@ -4,6 +4,7 @@ @available(SwiftStdlib 5.1, *) struct NS1 { } +// expected-note@-1 2{{consider making struct 'NS1' conform to the 'Sendable' protocol}} @available(SwiftStdlib 5.1, *) @available(*, unavailable) @@ -68,10 +69,21 @@ public protocol MyProto { func foo(aFoo: F) async where F: Sendable } +@available(SwiftStdlib 5.1, *) +func nonisolatedAsyncFunc1(_: NS1) async { } + +@available(SwiftStdlib 5.1, *) +func nonisolatedAsyncFunc2() async -> NS1 { NS1() } + @available(SwiftStdlib 5.1, *) public actor MyActor: MyProto { public func foo(aFoo: F) async where F: Sendable { } public func bar(aBar: B) async where B: Sendable { } + + func g(ns1: NS1) async { + await nonisolatedAsyncFunc1(ns1) // expected-warning{{non-sendable type 'NS1' exiting actor-isolated context in call to non-isolated global function 'nonisolatedAsyncFunc1' cannot cross actor boundary}} + _ = await nonisolatedAsyncFunc2() // expected-warning{{non-sendable type 'NS1' returned by call from actor-isolated context to non-isolated global function 'nonisolatedAsyncFunc2()' cannot cross actor boundary}} + } } // rdar://82452688 - make sure sendable checking doesn't fire for a capture diff --git a/test/Concurrency/unsafe_inherit_executor.swift b/test/Concurrency/unsafe_inherit_executor.swift index f14c88deb92ad..8512232491f89 100644 --- a/test/Concurrency/unsafe_inherit_executor.swift +++ b/test/Concurrency/unsafe_inherit_executor.swift @@ -21,7 +21,7 @@ struct A { } -class NonSendableObject { +class NonSendableObject { // expected-note{{class 'NonSendableObject' does not conform to the 'Sendable' protocol}} var property = 0 } @@ -31,7 +31,7 @@ func useNonSendable(object: NonSendableObject) async {} actor MyActor { var object = NonSendableObject() func foo() async { - // This should not be diagnosed when we implement SE-0338 checking. + // expected-warning@+1{{non-sendable type 'NonSendableObject' exiting actor-isolated context in call to non-isolated global function 'useNonSendable(object:)' cannot cross actor boundary}} await useNonSendable(object: self.object) } } From 3d30527529abd988d9502f94485ff45d4e6a283f Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 24 May 2022 13:03:57 -0700 Subject: [PATCH 41/53] [Autolink Extract] Filter out common Swift libraries from being linked more than once A partial solution to #58380 --- lib/DriverTool/autolink_extract_main.cpp | 46 +++++++++++++++++++----- test/AutolinkExtract/import.swift | 5 +++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/lib/DriverTool/autolink_extract_main.cpp b/lib/DriverTool/autolink_extract_main.cpp index 8d00c791589cb..7e2f178071df8 100644 --- a/lib/DriverTool/autolink_extract_main.cpp +++ b/lib/DriverTool/autolink_extract_main.cpp @@ -113,6 +113,7 @@ class AutolinkExtractInvocation { static bool extractLinkerFlagsFromObjectFile(const llvm::object::ObjectFile *ObjectFile, std::vector &LinkerFlags, + std::unordered_map &SwiftRuntimeLibraries, CompilerInstance &Instance) { // Search for the section we hold autolink entries in for (auto &Section : ObjectFile->sections()) { @@ -140,8 +141,13 @@ extractLinkerFlagsFromObjectFile(const llvm::object::ObjectFile *ObjectFile, llvm::SmallVector SplitFlags; SectionData->split(SplitFlags, llvm::StringRef("\0", 1), -1, /*KeepEmpty=*/false); - for (const auto &Flag : SplitFlags) - LinkerFlags.push_back(Flag.str()); + for (const auto &Flag : SplitFlags) { + auto RuntimeLibEntry = SwiftRuntimeLibraries.find(Flag.str()); + if (RuntimeLibEntry == SwiftRuntimeLibraries.end()) + LinkerFlags.emplace_back(Flag.str()); + else + RuntimeLibEntry->second = true; + } } } return false; @@ -153,6 +159,7 @@ extractLinkerFlagsFromObjectFile(const llvm::object::ObjectFile *ObjectFile, static bool extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, std::vector &LinkerFlags, + std::unordered_map &SwiftRuntimeLibraries, CompilerInstance &Instance) { // Search for the data segment we hold autolink entries in for (const llvm::object::WasmSegment &Segment : ObjectFile->dataSegments()) { @@ -164,8 +171,13 @@ extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, llvm::SmallVector SplitFlags; SegmentData.split(SplitFlags, llvm::StringRef("\0", 1), -1, /*KeepEmpty=*/false); - for (const auto &Flag : SplitFlags) - LinkerFlags.push_back(Flag.str()); + for (const auto &Flag : SplitFlags) { + auto RuntimeLibEntry = SwiftRuntimeLibraries.find(Flag.str()); + if (RuntimeLibEntry == SwiftRuntimeLibraries.end()) + LinkerFlags.emplace_back(Flag.str()); + else + RuntimeLibEntry->second = true; + } } } return false; @@ -178,12 +190,13 @@ extractLinkerFlagsFromObjectFile(const llvm::object::WasmObjectFile *ObjectFile, static bool extractLinkerFlags(const llvm::object::Binary *Bin, CompilerInstance &Instance, StringRef BinaryFileName, - std::vector &LinkerFlags) { + std::vector &LinkerFlags, + std::unordered_map &SwiftRuntimeLibraries) { if (auto *ObjectFile = llvm::dyn_cast(Bin)) { - return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, Instance); + return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, SwiftRuntimeLibraries, Instance); } else if (auto *ObjectFile = llvm::dyn_cast(Bin)) { - return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, Instance); + return extractLinkerFlagsFromObjectFile(ObjectFile, LinkerFlags, SwiftRuntimeLibraries, Instance); } else if (auto *Archive = llvm::dyn_cast(Bin)) { llvm::Error Error = llvm::Error::success(); for (const auto &Child : Archive->children(Error)) { @@ -197,7 +210,7 @@ static bool extractLinkerFlags(const llvm::object::Binary *Bin, return true; } if (extractLinkerFlags(ChildBinary->get(), Instance, BinaryFileName, - LinkerFlags)) { + LinkerFlags, SwiftRuntimeLibraries)) { return true; } } @@ -229,6 +242,15 @@ int autolink_extract_main(ArrayRef Args, const char *Argv0, std::vector LinkerFlags; + // Keep track of whether we've already added the common + // Swift libraries that ususally have autolink directives + // in most object fiels + std::unordered_map SwiftRuntimeLibraries = { + {"-lswiftSwiftOnoneSupport", false}, + {"-lswiftCore", false}, + {"-lswift_Concurrency", false}, + }; + // Extract the linker flags from the objects. for (const auto &BinaryFileName : Invocation.getInputFilenames()) { auto BinaryOwner = llvm::object::createBinary(BinaryFileName); @@ -245,7 +267,7 @@ int autolink_extract_main(ArrayRef Args, const char *Argv0, } if (extractLinkerFlags(BinaryOwner->getBinary(), Instance, BinaryFileName, - LinkerFlags)) { + LinkerFlags, SwiftRuntimeLibraries)) { return 1; } } @@ -264,5 +286,11 @@ int autolink_extract_main(ArrayRef Args, const char *Argv0, OutOS << Flag << '\n'; } + for (const auto &RuntimeLib : SwiftRuntimeLibraries) { + if (RuntimeLib.second) + OutOS << RuntimeLib.first << '\n'; + } + + return 0; } diff --git a/test/AutolinkExtract/import.swift b/test/AutolinkExtract/import.swift index ae8b929c7e132..7969fc32a88b3 100644 --- a/test/AutolinkExtract/import.swift +++ b/test/AutolinkExtract/import.swift @@ -2,9 +2,14 @@ // RUN: %target-swiftc_driver -emit-module -emit-module-path %t/empty.swiftmodule -module-name empty -module-link-name empty %S/empty.swift // RUN: %target-swiftc_driver -c %s -I %t -o %t/import_experimental.o // RUN: %target-swift-autolink-extract %t/import_experimental.o -o - | %FileCheck --check-prefix CHECK-%target-object-format %s +// RUN: %target-swiftc_driver -c %s -I %t -o %t/import_experimental_again.o +// RUN: %target-swift-autolink-extract %t/import_experimental.o %t/import_experimental_again.o -o - | %FileCheck --check-prefix CHECK-%target-object-format %s +// RUN: %target-swift-autolink-extract %t/import_experimental.o %t/import_experimental_again.o -o - | %FileCheck --check-prefix UNIQUE %s // REQUIRES: autolink-extract +// UNIQUE-COUNT-1: -lswiftCore + // CHECK-elf-DAG: -lswiftCore // CHECK-elf-DAG: -lempty From 882e1f85cef096fe163956a961389ca195f1b8b6 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 25 May 2022 14:04:13 -0700 Subject: [PATCH 42/53] Add SE-0338 to the ChangeLog now that it's implemented --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8b2551b614ec..62ddd4a071cac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,39 @@ _**Note:** This is in reverse chronological order, so newer entries are added to ## Swift 5.7 +* [SE-0338][]: + + Non-isolated async functions now always execute on the global concurrent pool, + so calling a non-isolated async function from actor-isolated code will leave + the actor. For example: + + ```swift + class C { } + + func f(_: C) async { /* always executes on the global concurrent pool */ } + + actor A { + func g(c: C) async { + /* always executes on the actor */ + print("on the actor") + + await f(c) + } + } + ``` + + Prior to this change, the call from `f` to `g` might have started execution of + `g` on the actor, which could lead to actors being busy longer than strictly + necessary. Now, the non-isolated async function will always hop to the global + cooperative pool, not run on the actor. This can result in a behavior change + for programs that assumed that a non-isolated async function called from a + `@MainActor` context will be executed on the main actor, although such + programs were already technically incorrect. + + Additionally, when leaving an actor to execution on the global cooperative + pool, `Sendable` checking will be performed, so the compiler will emit a + diagnostic in the call to `f` if `c` is not of `Sendable` type. + * [SE-0350][]: The standard library has a new `Regex` type. @@ -9421,6 +9454,7 @@ Swift 1.0 [SE-0335]: [SE-0336]: [SE-0337]: +[SE-0338]: [SE-0340]: [SE-0341]: [SE-0343]: From 49ac2f999e710f4560cdabd3ff5a40cd86361d3d Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Tue, 24 May 2022 14:35:29 -0700 Subject: [PATCH 43/53] CI: add support to skip testing selectively on full builds This adds the ability to selectively skip the tests for various pieces (e.g. foundation or xctest) to give us better control for CI for some projects. --- utils/build-windows-toolchain.bat | 142 +++++++++++++++++++----------- 1 file changed, 93 insertions(+), 49 deletions(-) diff --git a/utils/build-windows-toolchain.bat b/utils/build-windows-toolchain.bat index a53f7acb20ef6..0dad9819aa645 100644 --- a/utils/build-windows-toolchain.bat +++ b/utils/build-windows-toolchain.bat @@ -709,17 +709,99 @@ move %PackageRoot%\installer\installer.exe %BuildRoot%\artifacts || (exit /b) :: TODO(compnerd) test LLVM +SET SKIP_TEST=0 +FOR %%T IN (%SKIP_TESTS%) DO (IF /I %%T==swift SET SKIP_TEST=1) +IF "%SKIP_TEST%"=="0" call :TestSwift + +SET SKIP_TEST=0 +FOR %%T IN (%SKIP_TESTS%) DO (IF /I %T==dispatch SET SKIP_TEST=1) +IF "%SKIP_TEST%"=="0" call :TestDispatch + +SET SKIP_TEST=0 +FOR %%T IN (%SKIP_TESTS%) DO (IF /I %T==foundation SET SKIP_TEST=1) +IF "%SKIP_TEST%"=="0" call :TestFoundation + +SET SKIP_TEST=0 +FOR %%T IN (%SKIP_TESTS%) DO (IF /I %T==xctest SET SKIP_TEST=1) +IF "%SKIP_TEST%"=="0" call :TestXCTest + +:: Clean up the module cache +rd /s /q %LocalAppData%\clang\ModuleCache + +goto :end +endlocal + +:CloneRepositories +setlocal enableextensions enabledelayedexpansion + +if defined SKIP_UPDATE_CHECKOUT goto :eof + +if defined REPO_SCHEME set "args=--scheme %REPO_SCHEME%" + +:: Always enable symbolic links +git config --global core.symlink true + +:: Ensure that we have the files in the original line endings, the swift tests +:: depend on this being the case. +git -C "%SourceRoot%\swift" config --local core.autocrlf input +git -C "%SourceRoot%\swift" checkout-index --force --all + +set "args=%args% --skip-repository swift" +set "args=%args% --skip-repository ninja" +set "args=%args% --skip-repository icu" +set "args=%args% --skip-repository swift-integration-tests" +set "args=%args% --skip-repository swift-stress-tester" +set "args=%args% --skip-repository swift-xcode-playground-support" + +call "%SourceRoot%\swift\utils\update-checkout.cmd" %args% --clone --skip-history --github-comment "%ghprbCommentBody%" + +goto :eof +endlocal + +:CloneDependencies +setlocal enableextensions enabledelayedexpansion + +:: Always enable symbolic links +git config --global core.symlink true + +:: FIXME(compnerd) avoid the fresh clone +rd /s /q zlib libxml2 sqlite icu curl + +git clone --quiet --no-tags --depth 1 --branch v1.2.11 https://github.com/madler/zlib +git clone --quiet --no-tags --depth 1 --branch v2.9.12 https://github.com/gnome/libxml2 +git clone --quiet --no-tags --depth 1 --branch version-3.36.0 https://github.com/sqlite/sqlite +git clone --quiet --no-tags --depth 1 --branch maint/maint-69 https://github.com/unicode-org/icu +git clone --quiet --no-tags --depth 1 --branch curl-7_77_0 https://github.com/curl/curl + +goto :eof +endlocal + +:TestSwift +setlocal enableextensions enabledelayedexpansion + :: Test Swift :: TODO(compnerd) make lit adjust the path properly path %BuildRoot%\3;%BuildRoot%\1\bin;%PATH%;%SystemDrive%\Program Files\Git\usr\bin cmake --build %BuildRoot%\1 --target check-swift || (exit /b) +goto :eof +endlocal + +:TestDispatch +setlocal enableextensions enabledelayedexpansion + :: Test dispatch cmake --build %BuildRoot%\3 --target ExperimentalTest || (exit /b) +goto :eof +endlocal + +:TestFoundation +setlocal enableextensions enabledelayedexpansion + :: NOTE(compnerd) update the path *before* the build because the tests are :: executed to shard the test suite. -path %BuildRoot%\5;%BuildRoot%\4\bin;%PATH% +path %BuildRoot%\5;%BuildRoot%\4\bin;%BuildRoot%\3;%BuildRoot%\1\bin;%PATH%;%SystemDrive%\Program Files\Git\usr\bin :: Rebuild Foundation (w/ testing) cmake ^ @@ -760,6 +842,16 @@ cmake --build %BuildRoot%\4 || (exit /b) set CTEST_OUTPUT_ON_FAILURE=1 cmake --build %BuildRoot%\4 --target test || (exit /b) +goto :eof +endlocal + +:TestXCTest +setlocal enableextensions enabledelayedexpansion + +:: NOTE(compnerd) update the path *before* the build because the tests are +:: executed to shard the test suite. +path %BuildRoot%\5;%BuildRoot%\4\bin;%BuildRoot%\3;%BuildRoot%\1\bin;%PATH%;%SystemDrive%\Program Files\Git\usr\bin + :: Rebuild XCTest (w/ testing) cmake ^ -B %BuildRoot%\5 ^ @@ -791,54 +883,6 @@ cmake --build %BuildRoot%\5 || (exit /b) :: Test XCTest cmake --build %BuildRoot%\5 --target check-xctest || (exit /b) -:: Clean up the module cache -rd /s /q %LocalAppData%\clang\ModuleCache - -goto :end -endlocal - -:CloneRepositories -setlocal enableextensions enabledelayedexpansion - -if defined SKIP_UPDATE_CHECKOUT goto :eof - -if defined REPO_SCHEME set "args=--scheme %REPO_SCHEME%" - -:: Always enable symbolic links -git config --global core.symlink true - -:: Ensure that we have the files in the original line endings, the swift tests -:: depend on this being the case. -git -C "%SourceRoot%\swift" config --local core.autocrlf input -git -C "%SourceRoot%\swift" checkout-index --force --all - -set "args=%args% --skip-repository swift" -set "args=%args% --skip-repository ninja" -set "args=%args% --skip-repository icu" -set "args=%args% --skip-repository swift-integration-tests" -set "args=%args% --skip-repository swift-stress-tester" -set "args=%args% --skip-repository swift-xcode-playground-support" - -call "%SourceRoot%\swift\utils\update-checkout.cmd" %args% --clone --skip-history --github-comment "%ghprbCommentBody%" - -goto :eof -endlocal - -:CloneDependencies -setlocal enableextensions enabledelayedexpansion - -:: Always enable symbolic links -git config --global core.symlink true - -:: FIXME(compnerd) avoid the fresh clone -rd /s /q zlib libxml2 sqlite icu curl - -git clone --quiet --no-tags --depth 1 --branch v1.2.11 https://github.com/madler/zlib -git clone --quiet --no-tags --depth 1 --branch v2.9.12 https://github.com/gnome/libxml2 -git clone --quiet --no-tags --depth 1 --branch version-3.36.0 https://github.com/sqlite/sqlite -git clone --quiet --no-tags --depth 1 --branch maint/maint-69 https://github.com/unicode-org/icu -git clone --quiet --no-tags --depth 1 --branch curl-7_77_0 https://github.com/curl/curl - goto :eof endlocal From 133dbe499ebbf9a9607b627ee88ab0fb2bff1e0e Mon Sep 17 00:00:00 2001 From: Ben Barham Date: Wed, 25 May 2022 15:41:02 -0700 Subject: [PATCH 44/53] [Test] Do not load string processing when recovery is disabled This test specifically disables serialization recovery, but that can cause issues when loading the experimental string processing library. We don't use it in the test, so just disable it for now. --- test/Index/skip-loaded-internal.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Index/skip-loaded-internal.swift b/test/Index/skip-loaded-internal.swift index 2e9211f968e96..4538def8360a9 100644 --- a/test/Index/skip-loaded-internal.swift +++ b/test/Index/skip-loaded-internal.swift @@ -3,10 +3,10 @@ // RUN: mkdir -p %t/Frameworks/lib2.framework/Modules/lib2.swiftmodule // RUN: split-file %s %t -// RUN: %target-swift-frontend -emit-module -emit-module-source-info -module-name lib2 -o %t/Frameworks/lib2.framework/Modules/lib2.swiftmodule/%module-target-triple.swiftmodule %t/lib2.swift -// RUN: %target-swift-frontend -emit-module -emit-module-source-info -module-name lib -o %t/Frameworks/lib.framework/Modules/lib.swiftmodule/%module-target-triple.swiftmodule %t/lib.swift -Fsystem %t/Frameworks +// RUN: %target-swift-frontend -emit-module -emit-module-source-info -module-name lib2 -o %t/Frameworks/lib2.framework/Modules/lib2.swiftmodule/%module-target-triple.swiftmodule %t/lib2.swift -disable-experimental-string-processing +// RUN: %target-swift-frontend -emit-module -emit-module-source-info -module-name lib -o %t/Frameworks/lib.framework/Modules/lib.swiftmodule/%module-target-triple.swiftmodule %t/lib.swift -Fsystem %t/Frameworks -disable-experimental-string-processing -// RUN: %target-swift-frontend -typecheck -index-system-modules -index-ignore-stdlib -index-store-path %t/idx -Fsystem %t/Frameworks %t/main.swift -disable-deserialization-recovery +// RUN: %target-swift-frontend -typecheck -index-system-modules -index-ignore-stdlib -index-store-path %t/idx -Fsystem %t/Frameworks %t/main.swift -disable-deserialization-recovery -disable-experimental-string-processing //--- main.swift import lib From 174bbd2586f63e328e740ca63e492a760cf314ac Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 25 May 2022 16:12:03 -0700 Subject: [PATCH 45/53] Handle ParamDecls and VarDecls in Argument Matching Diagnostics These don't produce meaningful ParameterLists for this analysis to consider. Bail instead of crashing. rdar://93922410 --- lib/Sema/CSSimplify.cpp | 10 +++++++--- test/Constraints/argument_matching.swift | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d416cd065fd3f..6b1f3ed9f86c0 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4896,9 +4896,13 @@ bool ConstraintSystem::repairFailures( if (!(overload && overload->choice.isDecl())) return true; - if (!getParameterList(overload->choice.getDecl()) - ->get(applyLoc->getParamIdx()) - ->getTypeOfDefaultExpr()) + // Ignore decls that don't have meaningful parameter lists - this + // matches variables and parameters with function types. + auto *paramList = getParameterList(overload->choice.getDecl()); + if (!paramList) + return true; + + if (!paramList->get(applyLoc->getParamIdx())->getTypeOfDefaultExpr()) return true; } } diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index 291d2cd95ca9a..c3ff7d144c50b 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -1782,3 +1782,10 @@ func testExtraTrailingClosure() { func qux(x: () -> Void, y: () -> Void, z: () -> Void) {} // expected-note {{'qux(x:y:z:)' declared here}} qux() {} m: {} y: {} n: {} z: {} o: {} // expected-error@:6 {{extra trailing closures at positions #2, #4, #6 in call}} } + +// rdar://93922410 - argument-to-parameter doesn't handle applies of ParamDecls +func rdar93922410(_ completion: (Int?) -> Void) { // expected-note {{'completion' declared here}} + _ = { + return completion() // expected-error {{missing argument for parameter #1 in call}} + } +} From 9aaea55cf7b26809f7add5735965eada8d012042 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sun, 13 Mar 2022 23:52:14 -0400 Subject: [PATCH 46/53] Sema: Simplify logic for building extension generic signature --- lib/Sema/TypeCheckGeneric.cpp | 118 +++++------------- test/Generics/conditional_conformances.swift | 3 + .../doc_swift_module.swift.response | 13 +- .../doc_swift_module1.swift.response | 16 ++- ...wift_module_class_extension.swift.response | 17 ++- ...c_system_module_underscored.swift.response | 33 ++++- 6 files changed, 93 insertions(+), 107 deletions(-) diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 0b3ab22a79bd1..07ec072ff3c5f 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -468,15 +468,11 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) { /// Generic types /// -/// Form the interface type of an extension from the raw type and the -/// extension's list of generic parameters. -static Type formExtensionInterfaceType( - ExtensionDecl *ext, Type type, - const GenericParamList *genericParams, - SmallVectorImpl &sameTypeReqs, - bool &mustInferRequirements) { +/// Collect additional requirements into \p sameTypeReqs. +static void collectAdditionalExtensionRequirements( + Type type, SmallVectorImpl &sameTypeReqs) { if (type->is()) - return type; + return; // Find the nominal type declaration and its parent type. if (type->is()) @@ -484,7 +480,7 @@ static Type formExtensionInterfaceType( // A parameterized protocol type is not a nominal. Unwrap it to get // the underlying nominal, and record a same-type requirement for - // the primary associated type. + // the primary associated types. if (auto *paramProtoTy = type->getAs()) { auto *protoTy = paramProtoTy->getBaseType(); type = protoTy; @@ -497,15 +493,9 @@ static Type formExtensionInterfaceType( Type parentType = type->getNominalParent(); GenericTypeDecl *genericDecl = type->getAnyGeneric(); - // Reconstruct the parent, if there is one. + // Visit the parent type, if there is one. if (parentType) { - // Build the nested extension type. - auto parentGenericParams = genericDecl->getGenericParams() - ? genericParams->getOuterParameters() - : genericParams; - parentType = - formExtensionInterfaceType(ext, parentType, parentGenericParams, - sameTypeReqs, mustInferRequirements); + collectAdditionalExtensionRequirements(parentType, sameTypeReqs); } // Find the nominal type. @@ -516,59 +506,26 @@ static Type formExtensionInterfaceType( nominal = type->getNominalOrBoundGenericNominal(); } - // Form the result. - Type resultType; - SmallVector genericArgs; - if (!nominal->isGeneric() || isa(nominal)) { - resultType = NominalType::get(nominal, parentType, - nominal->getASTContext()); - } else if (genericParams) { - auto currentBoundType = type->getAs(); - - // Form the bound generic type with the type parameters provided. - unsigned gpIndex = 0; - for (auto gp : *genericParams) { - SWIFT_DEFER { ++gpIndex; }; - + // If we have a bound generic type, add same-type requirements for each of + // its generic arguments. + if (auto currentBoundType = type->getAs()) { + auto *genericParams = currentBoundType->getDecl()->getGenericParams(); + for (unsigned gpIndex : indices(genericParams->getParams())) { + auto *gp = genericParams->getParams()[gpIndex]; auto gpType = gp->getDeclaredInterfaceType(); - genericArgs.push_back(gpType); - if (currentBoundType) { - sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, - currentBoundType->getGenericArgs()[gpIndex]); - } + sameTypeReqs.emplace_back(RequirementKind::SameType, gpType, + currentBoundType->getGenericArgs()[gpIndex]); } - - resultType = BoundGenericType::get(nominal, parentType, genericArgs); } - // If we have a typealias, try to form type sugar. + // If we have a passthrough typealias, add the requirements from its + // generic signature. if (typealias && TypeChecker::isPassThroughTypealias( typealias, typealias->getUnderlyingType(), nominal)) { - auto typealiasSig = typealias->getGenericSignature(); - SubstitutionMap subMap; - if (typealiasSig) { - subMap = typealiasSig->getIdentitySubstitutionMap(); - - mustInferRequirements = true; - } - - resultType = TypeAliasType::get(typealias, parentType, subMap, resultType); + for (auto req : typealias->getGenericSignature().getRequirements()) + sameTypeReqs.push_back(req); } - - - return resultType; -} - -/// Retrieve the generic parameter depth of the extended type. -static unsigned getExtendedTypeGenericDepth(ExtensionDecl *ext) { - auto nominal = ext->getSelfNominalTypeDecl(); - if (!nominal) return static_cast(-1); - - auto sig = nominal->getGenericSignatureOfContext(); - if (!sig) return static_cast(-1); - - return sig.getGenericParams().back()->getDepth(); } GenericSignature @@ -605,7 +562,7 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, } bool allowConcreteGenericParams = false; - const auto *genericParams = GC->getGenericParams(); + auto *genericParams = GC->getGenericParams(); const auto *where = GC->getTrailingWhereClause(); if (genericParams) { @@ -650,10 +607,12 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, return GC->getParentForLookup()->getGenericSignatureOfContext(); } - auto parentSig = GC->getParentForLookup()->getGenericSignatureOfContext(); + GenericSignature parentSig; SmallVector inferenceSources; SmallVector sameTypeReqs; if (auto VD = dyn_cast_or_null(GC->getAsDecl())) { + parentSig = GC->getParentForLookup()->getGenericSignatureOfContext(); + auto func = dyn_cast(VD); auto subscr = dyn_cast(VD); @@ -708,38 +667,23 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator, } } } else if (auto *ext = dyn_cast(GC)) { - // Form the interface type of the extension so we can use it as an inference - // source. - // - // FIXME: Push this into the "get interface type" request. - bool mustInferRequirements = false; - Type extInterfaceType = - formExtensionInterfaceType(ext, ext->getExtendedType(), - genericParams, sameTypeReqs, - mustInferRequirements); - - auto cannotReuseNominalSignature = [&]() -> bool { - const auto finalDepth = genericParams->getParams().back()->getDepth(); - return mustInferRequirements - || !sameTypeReqs.empty() - || ext->getTrailingWhereClause() - || (getExtendedTypeGenericDepth(ext) != finalDepth); - }; + parentSig = ext->getExtendedNominal()->getGenericSignatureOfContext(); + genericParams = nullptr; + + collectAdditionalExtensionRequirements(ext->getExtendedType(), sameTypeReqs); - // Re-use the signature of the type being extended by default. - if (!cannotReuseNominalSignature()) { - return ext->getSelfNominalTypeDecl()->getGenericSignatureOfContext(); + // Re-use the signature of the type being extended by default. + if (sameTypeReqs.empty() && !ext->getTrailingWhereClause()) { + return parentSig; } // Allow parameters to be equated with concrete types. allowConcreteGenericParams = true; - - inferenceSources.emplace_back(nullptr, extInterfaceType); } auto request = InferredGenericSignatureRequest{ parentSig.getPointer(), - GC->getGenericParams(), WhereClauseOwner(GC), + genericParams, WhereClauseOwner(GC), sameTypeReqs, inferenceSources, allowConcreteGenericParams}; auto sig = evaluateOrDefault(ctx.evaluator, request, diff --git a/test/Generics/conditional_conformances.swift b/test/Generics/conditional_conformances.swift index 196065c308cc4..dc7fe35f96866 100644 --- a/test/Generics/conditional_conformances.swift +++ b/test/Generics/conditional_conformances.swift @@ -49,6 +49,7 @@ struct RedundantSame {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSame // CHECK-NEXT: (normal_conformance type=RedundantSame protocol=P2) extension RedundantSame: P2 where T: P1 {} +// expected-warning@-1 {{redundant conformance constraint 'T' : 'P1'}} struct RedundantSuper {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundantSuper @@ -334,6 +335,8 @@ struct RedundancyOrderDependenceGood {} // CHECK-NEXT: (normal_conformance type=RedundancyOrderDependenceGood protocol=P2 // CHECK-NEXT: same_type: T U) extension RedundancyOrderDependenceGood: P2 where U: P1, T == U {} +// expected-warning@-1 {{redundant conformance constraint 'U' : 'P1'}} + struct RedundancyOrderDependenceBad {} // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad // CHECK-LABEL: ExtensionDecl line={{.*}} base=RedundancyOrderDependenceBad diff --git a/test/SourceKit/DocSupport/doc_swift_module.swift.response b/test/SourceKit/DocSupport/doc_swift_module.swift.response index f1fc0a593b5d3..15e86fbbbff16 100644 --- a/test/SourceKit/DocSupport/doc_swift_module.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module.swift.response @@ -1301,7 +1301,7 @@ func shouldPrintAnyAsKeyword(x x: Any) { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:4cake4ProtPAASi7ElementRtzrlE4Selfxmfp", + key.usr: "s:4cake4ProtP4Selfxmfp", key.offset: 1595, key.length: 4 }, @@ -1649,7 +1649,7 @@ func shouldPrintAnyAsKeyword(x x: Any) { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Wrapped", - key.usr: "s:4cake2S3VA2A2P6RzrlE7Wrappedxmfp", + key.usr: "s:4cake2S3V7Wrappedxmfp", key.offset: 2041, key.length: 7 }, @@ -2557,7 +2557,7 @@ func shouldPrintAnyAsKeyword(x x: Any) ], key.offset: 1574, key.length: 63, - key.fully_annotated_decl: "extension Prot where Self.Element == Int", + key.fully_annotated_decl: "extension Prot where Self.Element == Int", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "Prot", @@ -2758,6 +2758,11 @@ func shouldPrintAnyAsKeyword(x x: Any) }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "Wrapped" + } + ], key.generic_requirements: [ { key.description: "Wrapped : P6" @@ -2765,7 +2770,7 @@ func shouldPrintAnyAsKeyword(x x: Any) ], key.offset: 2022, key.length: 80, - key.fully_annotated_decl: "extension S3 where Wrapped : P6", + key.fully_annotated_decl: "extension S3 where Wrapped : P6", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "S3", diff --git a/test/SourceKit/DocSupport/doc_swift_module1.swift.response b/test/SourceKit/DocSupport/doc_swift_module1.swift.response index 662df987b140b..1cae78fc9741d 100644 --- a/test/SourceKit/DocSupport/doc_swift_module1.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module1.swift.response @@ -569,7 +569,7 @@ extension Dictionary.Keys where Key : cake1.P1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:5cake12P2PA2A2P3RzrlE4Selfxmfp", + key.usr: "s:5cake12P2P4Selfxmfp", key.offset: 670, key.length: 4 }, @@ -671,7 +671,7 @@ extension Dictionary.Keys where Key : cake1.P1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Key", - key.usr: "s:SD4KeysV5cake1AC2P1RzrlE3Keyxmfp", + key.usr: "s:SD3Keyxmfp", key.offset: 836, key.length: 3 }, @@ -1038,7 +1038,7 @@ extension Dictionary.Keys where Key : cake1.P1 { ], key.offset: 651, key.length: 64, - key.fully_annotated_decl: "extension P2 where Self : P3", + key.fully_annotated_decl: "extension P2 where Self : P3", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P2", @@ -1110,6 +1110,14 @@ extension Dictionary.Keys where Key : cake1.P1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "Key" + }, + { + key.name: "Value" + } + ], key.generic_requirements: [ { key.description: "Key : Hashable" @@ -1120,7 +1128,7 @@ extension Dictionary.Keys where Key : cake1.P1 { ], key.offset: 804, key.length: 66, - key.fully_annotated_decl: "extension Dictionary.Keys where Key : P1", + key.fully_annotated_decl: "extension Dictionary.Keys where Key : P1", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "Keys", diff --git a/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response b/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response index 7af1a0c5b29bb..87befec96d775 100644 --- a/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response +++ b/test/SourceKit/DocSupport/doc_swift_module_class_extension.swift.response @@ -129,7 +129,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:27module_with_class_extension1CCA2A1DCRbzlE1Txmfp", + key.usr: "s:27module_with_class_extension1CC1Txmfp", key.offset: 130, key.length: 1 }, @@ -344,7 +344,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:27module_with_class_extension2P8PA2A1DC1TRczrlE4Selfxmfp", + key.usr: "s:27module_with_class_extension2P8P4Selfxmfp", key.offset: 480, key.length: 4 }, @@ -397,7 +397,7 @@ extension P8 where Self.T : module_with_class_extension.E { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "Self", - key.usr: "s:27module_with_class_extension2P8PA2A1EC1TRczrlE4Selfxmfp", + key.usr: "s:27module_with_class_extension2P8P4Selfxmfp", key.offset: 559, key.length: 4 }, @@ -470,6 +470,11 @@ extension P8 where Self.T : module_with_class_extension.E { }, { key.kind: source.lang.swift.decl.extension.class, + key.generic_params: [ + { + key.name: "T" + } + ], key.generic_requirements: [ { key.description: "T : D" @@ -477,7 +482,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 112, key.length: 87, - key.fully_annotated_decl: "extension C where T : D", + key.fully_annotated_decl: "extension C where T : D", key.extends: { key.kind: source.lang.swift.ref.class, key.name: "C", @@ -630,7 +635,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 461, key.length: 77, - key.fully_annotated_decl: "extension P8 where Self.T : D", + key.fully_annotated_decl: "extension P8 where Self.T : D", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P8", @@ -656,7 +661,7 @@ extension P8 where Self.T : module_with_class_extension.E { ], key.offset: 540, key.length: 77, - key.fully_annotated_decl: "extension P8 where Self.T : E", + key.fully_annotated_decl: "extension P8 where Self.T : E", key.extends: { key.kind: source.lang.swift.ref.protocol, key.name: "P8", diff --git a/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response b/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response index 69b177d042cbb..f9293f870ddd7 100644 --- a/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response +++ b/test/SourceKit/DocSupport/doc_system_module_underscored.swift.response @@ -219,7 +219,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1AVAASSRszlE1Txmfp", + key.usr: "s:16UnderscoredProto1AV1Txmfp", key.offset: 227, key.length: 1 }, @@ -849,7 +849,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp", + key.usr: "s:16UnderscoredProto1DV1Txmfp", key.offset: 1411, key.length: 1 }, @@ -911,7 +911,7 @@ protocol Other1 { { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", - key.usr: "s:16UnderscoredProto1DVAASQRzrlE1Txmfp", + key.usr: "s:16UnderscoredProto1DV1Txmfp", key.offset: 1484, key.length: 1 }, @@ -1050,6 +1050,11 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + } + ], key.generic_requirements: [ { key.description: "T == String" @@ -1057,7 +1062,7 @@ protocol Other1 { ], key.offset: 209, key.length: 185, - key.fully_annotated_decl: "extension A : _UnderscoredProto2 where T == String", + key.fully_annotated_decl: "extension A : _UnderscoredProto2 where T == String", key.conforms: [ { key.kind: source.lang.swift.ref.protocol, @@ -1520,6 +1525,14 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + }, + { + key.name: "U" + } + ], key.generic_requirements: [ { key.description: "T : Equatable" @@ -1527,7 +1540,7 @@ protocol Other1 { ], key.offset: 1393, key.length: 59, - key.fully_annotated_decl: "extension D : _SomeProto where T : Equatable", + key.fully_annotated_decl: "extension D : _SomeProto where T : Equatable", key.conforms: [ { key.kind: source.lang.swift.ref.protocol, @@ -1560,6 +1573,14 @@ protocol Other1 { }, { key.kind: source.lang.swift.decl.extension.struct, + key.generic_params: [ + { + key.name: "T" + }, + { + key.name: "U" + } + ], key.generic_requirements: [ { key.description: "T : Other1" @@ -1570,7 +1591,7 @@ protocol Other1 { ], key.offset: 1454, key.length: 135, - key.fully_annotated_decl: "extension D where T : Other1, T : Equatable", + key.fully_annotated_decl: "extension D where T : Other1, T : Equatable", key.extends: { key.kind: source.lang.swift.ref.struct, key.name: "D", From 8f072d1c2919c82d839425135f26e842e1ac976b Mon Sep 17 00:00:00 2001 From: Mike Ash Date: Wed, 25 May 2022 20:21:09 -0400 Subject: [PATCH 47/53] [Runtime] Don't try to demangle unprefixed untrusted names. Remove operator new/delete hackery. The operator new/delete overrides aren't working out due to inconsistent inlining of std::string creation/deletion. We can end up creating one with the global new but destroying it with our local delete. If they aren't compatible, this crashes. Instead, avoid problematic new/delete activity coming from lookup of ObjC class names. Names passed to getObjCClassByMangledName must either have a standard mangled name prefix, start with a digit (for unprefixed mangled names) or use the convenience dot syntax. Check for those up front and immediately reject anything else. This has the added bonus of failing more quickly for non-Swift names. rdar://93863030 --- stdlib/public/runtime/Heap.cpp | 27 ------------------------ stdlib/public/runtime/MetadataLookup.cpp | 24 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/stdlib/public/runtime/Heap.cpp b/stdlib/public/runtime/Heap.cpp index 3a81ff9353dd3..4619145a77b8a 100644 --- a/stdlib/public/runtime/Heap.cpp +++ b/stdlib/public/runtime/Heap.cpp @@ -133,30 +133,3 @@ static void swift_slowDeallocImpl(void *ptr, size_t alignMask) { void swift::swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask) { swift_slowDeallocImpl(ptr, alignMask); } - -#if defined(__APPLE__) && defined(__MACH__) && SWIFT_STDLIB_HAS_DARWIN_LIBMALLOC -// On Darwin, define our own, hidden operator new/delete implementations. We -// don't want to pick up any overrides that come from other code, but we also -// don't want to expose our overrides to any other code. We can't do this -// directly in C++, as the compiler has an implicit prototype with default -// visibility. However, if we implement them as C functions using the C++ -// mangled names, the compiler accepts them without complaint, and the linker -// still links all internal uses with these overrides. - -__attribute__((visibility(("hidden")))) extern "C" void *_Znwm(size_t size) { - return swift_slowAlloc(size, MALLOC_ALIGN_MASK); -} - -__attribute__((visibility(("hidden")))) extern "C" void _ZdlPv(void *ptr) { - swift_slowDeallocImpl(ptr, MALLOC_ALIGN_MASK); -} - -__attribute__((visibility(("hidden")))) extern "C" void *_Znam(size_t size) { - return swift_slowAlloc(size, MALLOC_ALIGN_MASK); -} - -__attribute__((visibility(("hidden")))) extern "C" void _ZdaPv(void *ptr) { - swift_slowDeallocImpl(ptr, MALLOC_ALIGN_MASK); -} - -#endif diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 25b3069502784..aab427dc0bc58 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1930,7 +1930,7 @@ swift_stdlib_getTypeByMangledNameUntrusted(const char *typeNameStart, if (c >= '\x01' && c <= '\x1F') return nullptr; } - + return swift_getTypeByMangledName(MetadataState::Complete, typeName, nullptr, {}, {}).getType().getMetadata(); } @@ -2197,6 +2197,23 @@ swift_getOpaqueTypeConformance(const void * const *arguments, // Return the ObjC class for the given type name. // This gets installed as a callback from libobjc. +static bool validateObjCMangledName(const char *_Nonnull typeName) { + // Accept names with a mangling prefix. + if (getManglingPrefixLength(typeName)) + return true; + + // Accept names that start with a digit (unprefixed mangled names). + if (isdigit(typeName[0])) + return true; + + // Accept names that contain a dot. + if (strchr(typeName, '.')) + return true; + + // Reject anything else. + return false; +} + // FIXME: delete this #if and dlsym once we don't // need to build with older libobjc headers #if !OBJC_GETCLASSHOOK_DEFINED @@ -2232,8 +2249,9 @@ getObjCClassByMangledName(const char * _Nonnull typeName, [&](const Metadata *type, unsigned index) { return nullptr; } ).getType().getMetadata(); } else { - metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), - typeStr.size()); + if (validateObjCMangledName(typeName)) + metadata = swift_stdlib_getTypeByMangledNameUntrusted(typeStr.data(), + typeStr.size()); } if (metadata) { auto objcClass = From 0a5b3f07270828cd5d6b45eb4a74c5021cc2db1e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 24 May 2022 09:57:44 -0700 Subject: [PATCH 48/53] [TypeChecker] SE-0324: Extend Swift -> C pointer conversions to `inout` Fixes an oversight where `inout` -> C pointer conversion wasn't covered by implementation of new pointer conversion semantics proposed by SE-0324. Resolves: rdar://92583588 --- include/swift/Sema/Constraint.h | 6 ++- lib/Sema/CSApply.cpp | 5 ++- lib/Sema/CSDiagnostics.cpp | 1 + lib/Sema/CSSimplify.cpp | 40 ++++++++++++++++++- lib/Sema/Constraint.cpp | 2 + lib/Sema/ConstraintSystem.cpp | 3 +- .../Inputs/c_pointer_conversions.h | 5 +++ .../swift_to_c_pointer_conversions.swift.gyb | 27 +++++++++++++ 8 files changed, 83 insertions(+), 6 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 7e63e3f6fae49..2f4dc15bc2b78 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -263,6 +263,8 @@ enum class ConversionRestrictionKind { ProtocolMetatypeToProtocolClass, /// Inout-to-pointer conversion. InoutToPointer, + /// Converting from `inout` to a C pointer has `PointerToCPointer` semantics. + InoutToCPointer, /// Array-to-pointer conversion. ArrayToPointer, /// String-to-pointer conversion. @@ -302,8 +304,8 @@ enum class ConversionRestrictionKind { /// via an implicit Double initializer call passing a CGFloat value. CGFloatToDouble, /// Implicit conversion between Swift and C pointers: - // - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int> - // - Unsafe[Mutable]Pointer <-> Unsafe[Mutable]Pointer + /// - Unsafe[Mutable]RawPointer -> Unsafe[Mutable]Pointer<[U]Int> + /// - Unsafe[Mutable]Pointer <-> Unsafe[Mutable]Pointer PointerToCPointer, // Convert a pack into a type with an equivalent arity. // - If the arity of the pack is 1, drops the pack structure => T diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c7e16f4b3a5bc..1e8a9224d8619 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -6611,7 +6611,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, return buildCollectionUpcastExpr(expr, toType, /*bridged=*/false, locator); } - case ConversionRestrictionKind::InoutToPointer: { + case ConversionRestrictionKind::InoutToPointer: + case ConversionRestrictionKind::InoutToCPointer: { bool isOptional = false; Type unwrappedTy = toType; if (Type unwrapped = toType->getOptionalObjectType()) { @@ -6629,7 +6630,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, result = cs.cacheType(new (ctx) InjectIntoOptionalExpr(result, toType)); return result; } - + case ConversionRestrictionKind::ArrayToPointer: { bool isOptional = false; Type unwrappedTy = toType; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 142baee43af40..a2e54e4e99c3d 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -6895,6 +6895,7 @@ void NonEphemeralConversionFailure::emitSuggestionNotes() const { break; } case ConversionRestrictionKind::InoutToPointer: + case ConversionRestrictionKind::InoutToCPointer: // For an arbitrary inout-to-pointer, we can suggest // withUnsafe[Mutable][Bytes/Pointer]. if (auto alternative = getAlternativeKind()) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d416cd065fd3f..bb8a51a2b92bf 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6589,9 +6589,18 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, // Only try an inout-to-pointer conversion if we know it's not // an array being converted to a raw pointer type. Such // conversions can only use array-to-pointer. - if (!baseIsArray || !isRawPointerKind(pointerKind)) + if (!baseIsArray || !isRawPointerKind(pointerKind)) { conversionsOrFixes.push_back( ConversionRestrictionKind::InoutToPointer); + + // If regular inout-to-pointer conversion doesn't work, + // let's try C pointer conversion that has special semantics + // for imported declarations. + if (isArgumentOfImportedDecl(locator)) { + conversionsOrFixes.push_back( + ConversionRestrictionKind::InoutToCPointer); + } + } } } @@ -12222,6 +12231,35 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( case ConversionRestrictionKind::PointerToCPointer: return simplifyPointerToCPointerRestriction(type1, type2, flags, locator); + case ConversionRestrictionKind::InoutToCPointer: { + SmallVector optionals; + + auto ptr2 = + type2->getDesugaredType()->lookThroughAllOptionalTypes(optionals); + + increaseScore(SK_ValueToOptional, optionals.size()); + + PointerTypeKind pointerKind; + (void)ptr2->getAnyPointerElementType(pointerKind); + + auto baseType1 = type1->getInOutObjectType(); + + Type ptr1; + // The right-hand size is a raw pointer, so let's use `UnsafeMutablePointer` + // for the `inout` type. + if (pointerKind == PTK_UnsafeRawPointer || + pointerKind == PTK_UnsafeMutableRawPointer) { + ptr1 = BoundGenericType::get(Context.getUnsafeMutablePointerDecl(), + /*parent=*/nullptr, {baseType1}); + } else { + ptr1 = baseType1->wrapInPointer(pointerKind); + } + + assert(ptr1); + + return simplifyPointerToCPointerRestriction(ptr1, ptr2, flags, locator); + } + // T < U or T is bridged to V where V < U ===> Array case ConversionRestrictionKind::ArrayUpcast: { Type baseType1 = *isArrayType(type1); diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 6dddb57ae5213..d56143b63e256 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -612,6 +612,8 @@ StringRef swift::constraints::getName(ConversionRestrictionKind kind) { return "[string-to-pointer]"; case ConversionRestrictionKind::InoutToPointer: return "[inout-to-pointer]"; + case ConversionRestrictionKind::InoutToCPointer: + return "[inout-to-c-pointer]"; case ConversionRestrictionKind::PointerToPointer: return "[pointer-to-pointer]"; case ConversionRestrictionKind::PointerToCPointer: diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index aa4872bc76b35..1344cb71cdc51 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -5719,7 +5719,8 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion, case ConversionRestrictionKind::StringToPointer: // Always ephemeral. return ConversionEphemeralness::Ephemeral; - case ConversionRestrictionKind::InoutToPointer: { + case ConversionRestrictionKind::InoutToPointer: + case ConversionRestrictionKind::InoutToCPointer: { // Ephemeral, except if the expression is a reference to a global or // static stored variable, or a directly accessed stored property on such a diff --git a/test/Constraints/Inputs/c_pointer_conversions.h b/test/Constraints/Inputs/c_pointer_conversions.h index 52a0d2bd83b36..c0f4cabd21c19 100644 --- a/test/Constraints/Inputs/c_pointer_conversions.h +++ b/test/Constraints/Inputs/c_pointer_conversions.h @@ -2,6 +2,11 @@ #include "stdint.h" +void void_ptr_func(void * _Nonnull buffer); +void const_void_ptr_func(const void * _Nonnull buffer); +void opt_void_ptr_func(void * _Nullable buffer); +void const_opt_void_ptr_func(const void * _Nullable buffer); + void char_ptr_func(char * _Nonnull buffer); void const_char_ptr_func(const char * _Nonnull buffer); diff --git a/test/Constraints/swift_to_c_pointer_conversions.swift.gyb b/test/Constraints/swift_to_c_pointer_conversions.swift.gyb index d70a6497a86ab..b57cdbf364304 100644 --- a/test/Constraints/swift_to_c_pointer_conversions.swift.gyb +++ b/test/Constraints/swift_to_c_pointer_conversions.swift.gyb @@ -269,3 +269,30 @@ func test_tailored_diagnostic(ptr: UnsafeRawPointer, tptr: UnsafePointer) opt_arg_func(optrU8) // expected-error@-1 {{cannot convert value of type 'UnsafePointer?' to expected argument type 'UnsafePointer?' because local function 'opt_arg_func' was not imported from C header}} } + +func test_inout_to_pointer_conversion() { +% for Size in ['16', '32', '64']: + var x${Size}: Int${Size} = 0 + + void_ptr_func(&x${Size}) // Ok + const_void_ptr_func(&x${Size}) // Ok + opt_void_ptr_func(&x${Size}) // Ok + + char_ptr_func(&x${Size}) // Ok + opt_char_ptr_func(&x${Size}) // Ok + + const_char_ptr_func(&x${Size}) // Ok + const_opt_char_ptr_func(&x${Size}) // Ok + + int_${Size}_ptr_func(&x${Size}) // Ok + uint_${Size}_ptr_func(&x${Size}) // Ok + + opt_int_${Size}_ptr_func(&x${Size}) // Ok + opt_uint_${Size}_ptr_func(&x${Size}) // Ok + + const_int_${Size}_ptr_func(&x${Size}) // OK + const_uint_${Size}_ptr_func(&x${Size}) // OK + const_opt_int_${Size}_ptr_func(&x${Size}) // OK + const_opt_uint_${Size}_ptr_func(&x${Size}) // OK +% end +} From c5c1e286e0601b5d1c740ddf88a6d4c8cab09f87 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 25 May 2022 17:45:28 -0700 Subject: [PATCH 49/53] [AST Mangler] Don't mangle marker protocols in retroactive conformances. Fixes a crash in IR generation, where we would try to emit metadata referencing a marker protocol, rdar://92285294. --- lib/AST/ASTMangler.cpp | 7 +++++++ test/IRGen/marker_protocol.swift | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 18aa4ecb44d87..7674b4a70c7f9 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1637,6 +1637,10 @@ static bool isRetroactiveConformance(const RootProtocolConformance *root) { return false; // self-conformances are never retroactive. nor are builtin. } + // Don't consider marker protocols at all. + if (conformance->getProtocol()->isMarkerProtocol()) + return false; + return conformance->isRetroactive(); } @@ -1682,6 +1686,9 @@ void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap, unsigned numProtocolRequirements = 0; for (auto conformance : subMap.getConformances()) { + if (conformance.getRequirement()->isMarkerProtocol()) + continue; + SWIFT_DEFER { ++numProtocolRequirements; }; diff --git a/test/IRGen/marker_protocol.swift b/test/IRGen/marker_protocol.swift index ce2cecae693d3..4e1fda242a66e 100644 --- a/test/IRGen/marker_protocol.swift +++ b/test/IRGen/marker_protocol.swift @@ -57,9 +57,14 @@ public func markerInDictionary() -> Any { // CHECK: swiftcc void @"$s15marker_protocol7genericyyxAA1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T) public func generic(_: T) { } +public struct GenericType { } + +// CHECK-LABEL: @"$s15marker_protocol11testGeneric1i5arrayySi_SaySiGtF"( public func testGeneric(i: Int, array: [Int]) { generic(i) generic(array) + // CHECK: __swift_instantiateConcreteTypeFromMangledName{{.*}}$s15marker_protocol11GenericTypeVySaySiGGmMD + print(GenericType<[Int]>.self) } // Forming an existential involving a marker protocol would crash the compiler From 39edb8be8908ff018eb4ab1999f84834c196f248 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 25 May 2022 22:38:55 -0700 Subject: [PATCH 50/53] [AST Mangler] Don't look into invalid conformances. --- lib/AST/ASTMangler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 7674b4a70c7f9..64460d9979d10 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1686,6 +1686,9 @@ void ASTMangler::appendRetroactiveConformances(SubstitutionMap subMap, unsigned numProtocolRequirements = 0; for (auto conformance : subMap.getConformances()) { + if (conformance.isInvalid()) + continue; + if (conformance.getRequirement()->isMarkerProtocol()) continue; From 7898b5a0883f66efdcd6b14d66d8bca09e742d4e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 17 May 2022 16:47:50 -0700 Subject: [PATCH 51/53] [CSSimplify] Disfavor choices that have injected `callAsFunction` Ambiguities like: ``` struct S { init(v: Int) {} init(v: Int, _: () -> Void) {} func callAsFunction(_: () -> Void) {} } S(v: 42) { } ``` Should always be resolved in favor of choice that doesn't require injection of `.callAsFunction`, so let's try to avoid solving if such an overload has already been found. --- lib/Sema/CSSimplify.cpp | 1 + .../result_builder_callAsFunction.swift | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 test/Constraints/result_builder_callAsFunction.swift diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index d416cd065fd3f..8ce2afd77c9f4 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -11404,6 +11404,7 @@ ConstraintSystem::simplifyApplicableFnConstraint( FunctionType::get(trailingClosureTypes, callAsFunctionResultTy, FunctionType::ExtInfo()); + increaseScore(SK_DisfavoredOverload); // Form an unsolved constraint to apply trailing closures to a // callable type produced by `.init`. This constraint would become // active when `callableType` is bound. diff --git a/test/Constraints/result_builder_callAsFunction.swift b/test/Constraints/result_builder_callAsFunction.swift new file mode 100644 index 0000000000000..a1546345b94d9 --- /dev/null +++ b/test/Constraints/result_builder_callAsFunction.swift @@ -0,0 +1,36 @@ +// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5 -debug-constraints > %t.log 2>&1 +// RUN: %FileCheck %s < %t.log + +// REQUIRES: objc_interop +// REQUIRES: OS=macosx + +protocol View {} +protocol Callable {} + +struct EmptyView : View {} + +@resultBuilder struct ViewBuilder { + static func buildBlock(_ content: Content) -> Content where Content : View { fatalError() } +} + +extension Callable { + func callAsFunction(@ViewBuilder _: () -> T) -> some View { EmptyView() } +} + +struct MyView : View { + init(v: Int, @ViewBuilder _: () -> Content) {} +} + +extension MyView : Callable where Content == EmptyView { + init(v: Int) {} +} + +// CHECK: (overload set choice binding $T6 := (Int) -> MyView<{{.*}}>) +// CHECK-NEXT: (increasing score due to disfavored overload) +// CHECK-NEXT: (solution is worse than the best solution) + +func test() -> some View { + return MyView(v: 42) { + return EmptyView() + } +} From bf665158581cd4bc4ab932d837a08df1b77e4ee3 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 26 May 2022 09:33:51 -0600 Subject: [PATCH 52/53] add default values for SymbolGraphOptions (#59037) rdar://93780666 --- .../swift/SymbolGraphGen/SymbolGraphOptions.h | 18 +++++++++--------- lib/Frontend/CompilerInvocation.cpp | 1 + .../ClangImporter/EmitWhileBuilding.swift | 4 ++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/swift/SymbolGraphGen/SymbolGraphOptions.h b/include/swift/SymbolGraphGen/SymbolGraphOptions.h index 371a7a6b5e3c0..a973a60f0cf51 100644 --- a/include/swift/SymbolGraphGen/SymbolGraphOptions.h +++ b/include/swift/SymbolGraphGen/SymbolGraphOptions.h @@ -21,33 +21,33 @@ namespace symbolgraphgen { struct SymbolGraphOptions { /// The directory to output the symbol graph JSON files. - StringRef OutputDir; + StringRef OutputDir = {}; /// The target of the module. - llvm::Triple Target; + llvm::Triple Target = {}; /// Pretty-print the JSON with newlines and indentation. - bool PrettyPrint; + bool PrettyPrint = false; /// The minimum access level that symbols must have in order to be /// included in the graph. - AccessLevel MinimumAccessLevel; + AccessLevel MinimumAccessLevel = AccessLevel::Public; /// Emit members gotten through class inheritance or protocol default /// implementations with compound, "SYNTHESIZED" USRs. - bool EmitSynthesizedMembers; + bool EmitSynthesizedMembers = false; /// Whether to print informational messages when rendering /// a symbol graph. - bool PrintMessages; + bool PrintMessages = false; /// Whether to skip docs for symbols with compound, "SYNTHESIZED" USRs. - bool SkipInheritedDocs; + bool SkipInheritedDocs = false; /// Whether to emit symbols with SPI information. - bool IncludeSPISymbols; + bool IncludeSPISymbols = false; /// Whether to include documentation for clang nodes or not. - bool IncludeClangDocs; + bool IncludeClangDocs = false; }; } // end namespace symbolgraphgen diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c670b510e792d..724e26ccb042d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1257,6 +1257,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts, Opts.PrettyPrint = false; Opts.EmitSynthesizedMembers = true; Opts.PrintMessages = false; + Opts.IncludeClangDocs = false; } static bool ParseSearchPathArgs(SearchPathOptions &Opts, diff --git a/test/SymbolGraph/ClangImporter/EmitWhileBuilding.swift b/test/SymbolGraph/ClangImporter/EmitWhileBuilding.swift index 7c39f50551537..4d084851d6d94 100644 --- a/test/SymbolGraph/ClangImporter/EmitWhileBuilding.swift +++ b/test/SymbolGraph/ClangImporter/EmitWhileBuilding.swift @@ -4,6 +4,7 @@ // RUN: %{python} -m json.tool %t/EmitWhileBuilding.symbols.json %t/EmitWhileBuilding.formatted.symbols.json // RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.formatted.symbols.json // RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.formatted.symbols.json --check-prefix HEADER +// RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.formatted.symbols.json --check-prefix LOCATION // REQUIRES: objc_interop @@ -28,3 +29,6 @@ public enum SwiftEnum {} // CHECK-NEXT: "spelling": "SwiftEnum" // CHECK-NEXT: } // CHECK-NEXT: ], + +// ensure that the only nodes with a "location" field are the ones that came from Swift +// LOCATION-COUNT-2: "location": From f7cfc7ff9a84d2426ac754a5e09a97ef5f85caec Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 27 May 2022 03:16:01 +0000 Subject: [PATCH 53/53] build lld explicitly for darwin build environment --- utils/webassembly/build-presets.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/webassembly/build-presets.ini b/utils/webassembly/build-presets.ini index a92292bedbf8f..2cf2fc31c69f6 100644 --- a/utils/webassembly/build-presets.ini +++ b/utils/webassembly/build-presets.ini @@ -41,6 +41,7 @@ swiftpm indexstore-db sourcekit-lsp libcxx +build-lld install-llvm install-swift