diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index ee99f99911ba0..a65799b8c53cd 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -1047,3 +1047,63 @@ Some kinds need arguments, which precede ``Tf``. If the first character of the string literal is a digit ``[0-9]`` or an underscore ``_``, the identifier for the string literal is prefixed with an additional underscore ``_``. + +Conventions for foreign symbols +------------------------------- + +Swift interoperates with multiple other languages - C, C++, Objective-C, and +Objective-C++. Each of these languages defines their own mangling conventions, +so Swift must take care to follow them. However, these conventions do not cover +Swift-specific symbols like Swift type metadata for foreign types, so Swift uses +its own mangling scheme for those symbols. + +Importing C and C++ structs +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Types imported from C and C++ are imported as if they are located in the ``__C`` +module, regardless of the actual Clang module that they are coming from. This +can be observed when mangling a Swift function that accepts a C/C++ struct as a +parameter: + +C++ module ``CxxStructModule``: + +.. code-block:: c++ + + struct CxxStruct {}; + + inline void cxxFunction(CxxStruct s) {} + +Swift module ``main`` that imports ``CxxStructModule``: + +.. code-block:: swift + + import CxxStructModule + + public func swiftFunction(_ s: CxxStruct) {} + +Resulting symbols (showing only Itanium-mangled C++ symbols for brevity): + +.. code:: + + _Z11cxxFunction9CxxStruct // -> cxxFunction(CxxStruct) + s4main13swiftFunctionyySo9CxxStructVF // -> main.swiftFunction(__C.CxxStruct) -> () + +The reason for ignoring the Clang module and always putting C and C++ types into +``__C`` at the Swift ABI level is that the Clang module is not a part of the C +or C++ ABI. When owners of C and C++ Clang modules decide what changes are +ABI-compatible or not, they will likely take into account C and C++ ABI, but not +the Swift ABI. Therefore, Swift ABI can only encode information about a C or C++ +type that the C and C++ ABI already encodes in order to remain compatible with +future versions of libraries that evolve according to C and C++ ABI +compatibility principles. + +The C/C++ compiler does not generate Swift metadata symbols and value witness +tables for C and C++ types. To make a foreign type usable in Swift in the same +way as a native type, the Swift compiler must generate these symbols. +Specifically, each Swift module that uses a given C or C++ type generates the +necessary Swift symbols. For the example above the Swift compiler will generate following +nominal type descriptor symbol for ``CxxStruct`` while compiling the ``main`` module: + +.. code:: + + sSo9CxxStructVMn // -> nominal type descriptor for __C.CxxStruct diff --git a/docs/ContinuousIntegration.md b/docs/ContinuousIntegration.md index 27685776f6b2d..e83a28a47d0d4 100644 --- a/docs/ContinuousIntegration.md +++ b/docs/ContinuousIntegration.md @@ -106,9 +106,11 @@ macOS platform | @swift-ci Please smoke benchmark | S Linux platform | @swift-ci Please test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform Linux platform | @swift-ci Please clean test Linux platform | Swift Test Linux Platform (smoke test)
Swift Test Linux Platform macOS platform | @swift-ci Please ASAN test | Swift ASAN Test OS X Platform -Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform -CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform -Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform +Ubuntu 18.04 | @swift-ci Please test Ubuntu 18.04 platform | Swift Test Ubuntu 18.04 Platform +Ubuntu 20.04 | @swift-ci Please test Ubuntu 20.04 platform | Swift Test Ubuntu 20.04 Platform +CentOS 7 | @swift-ci Please test CentOS 7 platform | Swift Test CentOS 7 Platform +CentOS 8 | @swift-ci Please test CentOS 8 platform | Swift Test CentOS 8 Platform +Amazon Linux 2 | @swift-ci Please test Amazon Linux 2 platform | Swift Test Amazon Linux 2 Platform The core principles of validation testing is that: diff --git a/docs/DifferentiableProgramming.md b/docs/DifferentiableProgramming.md index 0e1196f138cca..26d2e99fca2fb 100644 --- a/docs/DifferentiableProgramming.md +++ b/docs/DifferentiableProgramming.md @@ -893,8 +893,15 @@ extension Perceptron { ### `@differentiable` function types -A subtype of normal function types with a different runtime representation, -which stores metadata that allows their values to be differentiated anywhere. +Differentiable functions are first-class values, identified by a +`@differentiable` attribute in the function type. A `@differentiable` function +type is a subtype of its corresponding normal function type (i.e. without a +`@differentiable` attribute) with an extended ABI, which stores metadata that +allows their values to be differentiated anywhere the function is passed. A +`@differentiable(linear)` function type is a subtype of its corresponding +`@differentiable` function type. A normal function can be implicitly converted +to a `@differentiable` or `@differentiable(linear)` function with appropriate +compile-time checks. ```swift func addOne(_ x: Float) -> Float { x + 1 } @@ -920,8 +927,9 @@ func _(_ x: Float) -> (value: Float, ### Differential operators -Standard library differentiation APIs that take `@differentiable` functions and -return derivative functions or compute derivative values. +Differential operators are APIs defined in the standard library that take +`@differentiable` functions and return derivative functions or compute +derivative values. ```swift // In the standard library: @@ -2318,7 +2326,7 @@ As shown in the subsection, a `@differentiable` function value's runtime representation contains the original function along with extra information that allows the function to be differentiated (or transposed, if it is `@differentiable(linear)`). A -@differentiable or `@differentiable(linear)` function value can be called like a +`@differentiable` or `@differentiable(linear)` function value can be called like a non-`@differentiable` function. A `@differentiable(linear)` function value can be implicitly converted to a `@differentiable` one, which can be implicitly converted to a non-`@differentiable` one. diff --git a/docs/README.md b/docs/README.md index 1492d1ef48430..b3e2c3f976d4d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -105,7 +105,7 @@ documentation, please create a thread on the Swift forums under the - [RequestEvaluator.md](/docs/RequestEvaluator.md): Describes the request evaluator architecture, which is used for lazy type-checking and efficient caching. - - [Literal.md](/docs/Literal.md): + - [Literals.md](/docs/Literals.md): Describes type-checking and inference specifically for literals. - [Serialization.rst](/docs/Serialization.rst): Gives an overview of the LLVM bitcode format used for swiftmodules. @@ -117,7 +117,7 @@ documentation, please create a thread on the Swift forums under the Provides an overview of the implementation of SIL in the compiler. - [OptimizerDesign.md](/docs/OptimizerDesign.md): Describes the design of the optimizer pipeline. - - [HighLevelSILOptimizations.rst](docs/HighLevelSILOptimizations.rst): + - [HighLevelSILOptimizations.rst](/docs/HighLevelSILOptimizations.rst): Describes how the optimizer understands the semantics of high-level operations on currency data types and optimizes accordingly. Includes a thorough discussion of the `@_semantics` attribute. diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index ef9160641981e..ee3c776cd9db6 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -24,6 +24,8 @@ #include "swift/AST/TypeLoc.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" namespace swift { @@ -742,8 +744,26 @@ namespace swift { void setLocalization(std::string locale, std::string path) { assert(!locale.empty()); assert(!path.empty()); - localization = - std::make_unique(locale, path); + llvm::SmallString<128> filePath(path); + llvm::sys::path::append(filePath, locale); + llvm::sys::path::replace_extension(filePath, ".db"); + + // If the serialized diagnostics file not available, + // fallback to the `YAML` file. + if (llvm::sys::fs::exists(filePath)) { + if (auto file = llvm::MemoryBuffer::getFile(filePath)) { + localization = std::make_unique( + std::move(file.get())); + } + } else { + llvm::sys::path::replace_extension(filePath, ".yaml"); + // In case of missing localization files, we should fallback to messages + // from `.def` files. + if (llvm::sys::fs::exists(filePath)) { + localization = + std::make_unique(filePath.str()); + } + } } void ignoreDiagnostic(DiagID id) { diff --git a/include/swift/AST/DiagnosticsCommon.def b/include/swift/AST/DiagnosticsCommon.def index 788fb0e09f767..cdeef09e3058e 100644 --- a/include/swift/AST/DiagnosticsCommon.def +++ b/include/swift/AST/DiagnosticsCommon.def @@ -178,5 +178,12 @@ WARNING(cross_imported_by_both_modules, none, "please report this bug to the maintainers of these modules", (Identifier, Identifier, Identifier)) +//------------------------------------------------------------------------------ +// MARK: dependencies scanner diagnostics +//------------------------------------------------------------------------------ + +ERROR(scanner_find_cycle, none, + "dependency scanner detected dependency cycle: '%0'", (StringRef)) + #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 0c8d0df993b8c..8eaafddc06e5a 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -88,6 +88,13 @@ ERROR(could_not_find_subscript_member_did_you_mean,none, "did you mean to use the subscript operator?", (Type)) +ERROR(could_not_find_subscript_member_tuple, none, + "cannot access element using subscript for tuple type %0; " + "use '.' notation instead", (Type)) +ERROR(could_not_find_subscript_member_tuple_did_you_mean_use_dot, none, + "cannot access element using subscript for tuple type %0; " + "did you mean to use '.%1'?", (Type, StringRef)) + ERROR(could_not_find_enum_case,none, "enum type %0 has no case %1; did you mean %2?", (Type, DeclNameRef, DeclName)) @@ -2835,7 +2842,8 @@ NOTE(codable_extraneous_codingkey_case_here,none, NOTE(codable_non_conforming_property_here,none, "cannot automatically synthesize %0 because %1 does not conform to %0", (Type, TypeLoc)) NOTE(codable_non_decoded_property_here,none, - "cannot automatically synthesize %0 because %1 does not have a matching CodingKey and does not have a default value", (Type, Identifier)) + "cannot automatically synthesize %0 because %1 does not have a matching " + "CodingKey and does not have a default value", (Type, Identifier)) NOTE(codable_codingkeys_type_is_not_an_enum_here,none, "cannot automatically synthesize %0 because 'CodingKeys' is not an enum", (Type)) NOTE(codable_codingkeys_type_does_not_conform_here,none, @@ -4064,10 +4072,13 @@ ERROR(throw_in_nonexhaustive_catch,none, "error is not handled because the enclosing catch is not exhaustive", ()) ERROR(throwing_call_in_illegal_context,none, - "call can throw, but errors cannot be thrown out of %0", - (StringRef)) + "call can throw, but errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throw_in_illegal_context,none, - "errors cannot be thrown out of %0", (StringRef)) + "errors cannot be thrown out of " + "%select{<>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0", + (unsigned)) ERROR(throwing_operator_without_try,none, "operator can throw but expression is not marked with 'try'", ()) @@ -4716,6 +4727,11 @@ ERROR(availability_decl_unavailable, none, "%select{ in %3|}2%select{|: %4}4", (unsigned, DeclName, bool, StringRef, StringRef)) +WARNING(availability_decl_unavailable_warn, none, + "%select{getter for |setter for |}0%1 is unavailable" + "%select{ in %3|}2%select{|: %4}4", + (unsigned, DeclName, bool, StringRef, StringRef)) + #define REPLACEMENT_DECL_KIND_SELECT "select{| instance method| property}" ERROR(availability_decl_unavailable_rename, none, "%select{getter for |setter for |}0%1 has been " @@ -4723,6 +4739,12 @@ ERROR(availability_decl_unavailable_rename, none, "'%4'%select{|: %5}5", (unsigned, DeclName, bool, unsigned, StringRef, StringRef)) +WARNING(availability_decl_unavailable_rename_warn, none, + "%select{getter for |setter for |}0%1 has been " + "%select{renamed to|replaced by}2%" REPLACEMENT_DECL_KIND_SELECT "3 " + "'%4'%select{|: %5}5", + (unsigned, DeclName, bool, unsigned, StringRef, StringRef)) + NOTE(availability_marked_unavailable, none, "%select{getter for |setter for |}0%1 has been explicitly marked " "unavailable here", (unsigned, DeclName)) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index a62c045674a18..a75d9d56b39e4 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -861,9 +861,6 @@ class StringLiteralExpr : public LiteralExpr { /// A UTF-8 string. UTF8, - /// A UTF-16 string. - UTF16, - /// A single UnicodeScalar, passed as an integer. OneUnicodeScalar }; @@ -5259,6 +5256,7 @@ class KeyPathExpr : public Expr { OptionalWrap, Identity, TupleElement, + DictionaryKey, }; private: @@ -5367,6 +5365,16 @@ class KeyPathExpr : public Expr { propertyType, loc); } + + /// Create a component for a dictionary key (#keyPath only). + static Component forDictionaryKey(DeclNameRef UnresolvedName, + Type valueType, + SourceLoc loc) { + return Component(nullptr, UnresolvedName, nullptr, {}, {}, + Kind::DictionaryKey, + valueType, + loc); + } /// Create a component for a subscript. static Component forSubscript(ASTContext &ctx, @@ -5457,6 +5465,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return true; case Kind::UnresolvedSubscript: @@ -5481,6 +5490,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return nullptr; } llvm_unreachable("unhandled kind"); @@ -5500,6 +5510,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: llvm_unreachable("no subscript labels for this kind"); } llvm_unreachable("unhandled kind"); @@ -5522,6 +5533,7 @@ class KeyPathExpr : public Expr { case Kind::Property: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: return {}; } llvm_unreachable("unhandled kind"); @@ -5533,6 +5545,7 @@ class KeyPathExpr : public Expr { DeclNameRef getUnresolvedDeclName() const { switch (getKind()) { case Kind::UnresolvedProperty: + case Kind::DictionaryKey: return Decl.UnresolvedName; case Kind::Invalid: @@ -5563,6 +5576,7 @@ class KeyPathExpr : public Expr { case Kind::OptionalForce: case Kind::Identity: case Kind::TupleElement: + case Kind::DictionaryKey: llvm_unreachable("no decl ref for this kind"); } llvm_unreachable("unhandled kind"); @@ -5582,6 +5596,7 @@ class KeyPathExpr : public Expr { case Kind::Identity: case Kind::Property: case Kind::Subscript: + case Kind::DictionaryKey: llvm_unreachable("no field number for this kind"); } llvm_unreachable("unhandled kind"); diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h index 1cf1d535d5f4a..e91543b476539 100644 --- a/include/swift/AST/GenericSignatureBuilder.h +++ b/include/swift/AST/GenericSignatureBuilder.h @@ -751,7 +751,7 @@ class GenericSignatureBuilder { /// \param resolutionKind How to perform the resolution. /// /// \param wantExactPotentialArchetype Whether to return the precise - /// potential archetype described by the type (vs. just the equivalance + /// potential archetype described by the type (vs. just the equivalence /// class and resolved type). ResolvedType maybeResolveEquivalenceClass( Type type, diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index d03c1310cf8e8..3d1facf4e6a60 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -139,6 +139,12 @@ struct PointerAuthOptions : clang::PointerAuthOptions { PointerAuthSchema ResilientClassStubInitCallbacks; }; +enum class JITDebugArtifact : unsigned { + None, ///< None + LLVMIR, ///< LLVM IR + Object, ///< Object File +}; + /// The set of options supported by IR generation. class IRGenOptions { public: @@ -326,6 +332,8 @@ class IRGenOptions { Optional AutolinkRuntimeCompatibilityLibraryVersion; Optional AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion; + JITDebugArtifact DumpJIT = JITDebugArtifact::None; + IRGenOptions() : DWARFVersion(2), OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true), OptMode(OptimizationMode::NotSet), diff --git a/include/swift/AST/LocalizationFormat.h b/include/swift/AST/LocalizationFormat.h index a4205bb85be72..efd3d5345467f 100644 --- a/include/swift/AST/LocalizationFormat.h +++ b/include/swift/AST/LocalizationFormat.h @@ -1,5 +1,4 @@ -//===--- LocalizationFormat.h - YAML format for Diagnostic Messages ---*- -// C++ -*-===// +//===--- LocalizationFormat.h - Format for Diagnostic Messages --*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -18,16 +17,127 @@ #ifndef SWIFT_LOCALIZATIONFORMAT_H #define SWIFT_LOCALIZATIONFORMAT_H +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include +#include #include #include +#include +#include namespace swift { enum class DiagID : uint32_t; namespace diag { + +using namespace llvm::support; + +class LocalizationWriterInfo { +public: + using key_type = uint32_t; + using key_type_ref = const uint32_t &; + using data_type = std::string; + using data_type_ref = llvm::StringRef; + using hash_value_type = uint32_t; + using offset_type = uint32_t; + + hash_value_type ComputeHash(key_type_ref key) { return llvm::hash_code(key); } + + std::pair EmitKeyDataLength(llvm::raw_ostream &out, + key_type_ref key, + data_type_ref data) { + offset_type dataLength = static_cast(data.size()); + endian::write(out, dataLength, little); + // No need to write the key length; it's constant. + return {sizeof(key_type), dataLength}; + } + + void EmitKey(llvm::raw_ostream &out, key_type_ref key, unsigned len) { + assert(len == sizeof(key_type)); + endian::write(out, key, little); + } + + void EmitData(llvm::raw_ostream &out, key_type_ref key, data_type_ref data, + unsigned len) { + out << data; + } +}; + +class LocalizationReaderInfo { +public: + using internal_key_type = uint32_t; + using external_key_type = swift::DiagID; + using data_type = llvm::StringRef; + using hash_value_type = uint32_t; + using offset_type = uint32_t; + + internal_key_type GetInternalKey(external_key_type key) { + return static_cast(key); + } + + external_key_type GetExternalKey(internal_key_type key) { + return static_cast(key); + } + + static bool EqualKey(internal_key_type lhs, internal_key_type rhs) { + return lhs == rhs; + } + + hash_value_type ComputeHash(internal_key_type key) { + return llvm::hash_code(key); + } + + static std::pair + ReadKeyDataLength(const unsigned char *&data) { + offset_type dataLength = + endian::readNext(data); + return {sizeof(uint32_t), dataLength}; + } + + internal_key_type ReadKey(const unsigned char *data, offset_type length) { + return endian::readNext(data); + } + + data_type ReadData(internal_key_type Key, const unsigned char *data, + offset_type length) { + return data_type((const char *)data, length); + } +}; + +class SerializedLocalizationWriter { + using offset_type = LocalizationWriterInfo::offset_type; + llvm::OnDiskChainedHashTableGenerator generator; + +public: + /// Enqueue the given diagnostic to be included in a serialized translations + /// file. + /// + /// \param id The identifier associated with the given diagnostic message e.g. + /// 'cannot_convert_argument'. + /// \param translation The localized diagnostic message for the given + /// identifier. + void insert(swift::DiagID id, llvm::StringRef translation); + + /// Write out previously inserted diagnostic translations into the given + /// location. + /// + /// \param filePath The location of the serialized diagnostics file. It's + /// supposed to be a file with '.db' postfix. + /// \returns true if all diagnostic + /// messages have been successfully serialized, false otherwise. + bool emit(llvm::StringRef filePath); +}; + class LocalizationProducer { public: /// If the message isn't available/localized in the current `yaml` file, @@ -41,9 +151,33 @@ class LocalizationProducer { }; class YAMLLocalizationProducer final : public LocalizationProducer { -public: std::vector diagnostics; - explicit YAMLLocalizationProducer(std::string locale, std::string path); + +public: + /// The diagnostics IDs that are no longer available in `.def` + std::vector unknownIDs; + explicit YAMLLocalizationProducer(llvm::StringRef filePath); + llvm::StringRef getMessageOr(swift::DiagID id, + llvm::StringRef defaultMessage) const override; + + /// Iterate over all of the available (non-empty) translations + /// maintained by this producer, callback gets each translation + /// with its unique identifier. + void forEachAvailable( + llvm::function_ref callback) const; +}; + +class SerializedLocalizationProducer final : public LocalizationProducer { + using SerializedLocalizationTable = + llvm::OnDiskIterableChainedHashTable; + using offset_type = LocalizationReaderInfo::offset_type; + std::unique_ptr Buffer; + std::unique_ptr SerializedTable; + +public: + explicit SerializedLocalizationProducer( + std::unique_ptr buffer); + llvm::StringRef getMessageOr(swift::DiagID id, llvm::StringRef defaultMessage) const override; }; @@ -55,12 +189,23 @@ class LocalizationInput : public llvm::yaml::Input { template friend typename std::enable_if::value, void>::type - readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx); + readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx); template friend typename std::enable_if::value, LocalizationInput &>::type operator>>(LocalizationInput &yin, T &diagnostics); + +public: + /// A vector that keeps track of the diagnostics IDs that are available in + /// YAML and not available in `.def` files. + std::vector unknownIDs; + + /// A diagnostic ID might be present in YAML and not in `.def` file, if that's + /// the case the `id` won't have a `DiagID` value. + /// If the `id` is available in `.def` file this method will return the `id`'s + /// value, otherwise this method won't return a value. + static llvm::Optional readID(llvm::yaml::IO &io); }; } // namespace diag diff --git a/include/swift/AST/NameLookup.h b/include/swift/AST/NameLookup.h index 57e6c63740d5c..ea847ce01c1ba 100644 --- a/include/swift/AST/NameLookup.h +++ b/include/swift/AST/NameLookup.h @@ -512,14 +512,6 @@ void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name, } // end namespace namelookup -/// Retrieve the set of nominal type declarations that are directly -/// referenced in the given \c typeRepr, looking through typealiases. -/// -/// \param dc The \c DeclContext from which to perform lookup. -TinyPtrVector -getDirectlyReferencedNominalTypeDecls(ASTContext &ctx, TypeRepr *typeRepr, - DeclContext *dc, bool &anyObject); - /// Retrieve the set of nominal type declarations that are directly /// "inherited" by the given declaration at a particular position in the /// list of "inherited" types. diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 5fd6baee95994..90e0e814d0f32 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -390,6 +390,12 @@ namespace swift { /// Load swiftmodule files in memory as volatile and avoid mmap. bool EnableVolatileModules = false; + /// Allow deserializing implementation only dependencies. This should only + /// be set true by lldb and other tooling, so that deserilization + /// recovery issues won't bring down the debugger. + /// TODO: remove this when @_implementationOnly modules are robust enough. + bool AllowDeserializingImplementationOnly = false; + /// Sets the target we are building for and updates platform conditions /// to match. /// diff --git a/include/swift/Basic/Unicode.h b/include/swift/Basic/Unicode.h index ff2163eb0f374..4b1108af7fac1 100644 --- a/include/swift/Basic/Unicode.h +++ b/include/swift/Basic/Unicode.h @@ -68,10 +68,6 @@ bool isSingleUnicodeScalar(StringRef S); unsigned extractFirstUnicodeScalar(StringRef S); -/// Get the length of the UTF8 string transcoded into UTF16. -/// Returns the number of code units in UTF16 representation -uint64_t getUTF16Length(StringRef Str); - } // end namespace unicode } // end namespace swift diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 76cd3658ee615..5bd693d2ffe7d 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -329,6 +329,9 @@ def disable_llvm_verify : Flag<["-"], "disable-llvm-verify">, def disable_llvm_value_names : Flag<["-"], "disable-llvm-value-names">, HelpText<"Don't add names to local values in LLVM IR">; +def dump_jit : JoinedOrSeparate<["-"], "dump-jit">, + HelpText<"Dump JIT contents">; + def enable_llvm_value_names : Flag<["-"], "enable-llvm-value-names">, HelpText<"Add names to local values in LLVM IR">; diff --git a/include/swift/Runtime/ObjCBridge.h b/include/swift/Runtime/ObjCBridge.h index 33e5022463434..a24fb03feeb9d 100644 --- a/include/swift/Runtime/ObjCBridge.h +++ b/include/swift/Runtime/ObjCBridge.h @@ -68,6 +68,9 @@ OBJC_EXPORT Class objc_readClassPair(Class cls, const struct objc_image_info *info) __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0); +// Magic symbol whose _address_ is the runtime's isa mask. +OBJC_EXPORT const struct { char c; } objc_absolute_packed_isa_class_mask; + namespace swift { diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index ae3f940d21ad4..8125736fc391f 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -274,6 +274,9 @@ class SILFunction /// that it may have unboxed capture (i.e. @inout_aliasable parameters). unsigned IsWithoutActuallyEscapingThunk : 1; + /// True if this function is an async function. + unsigned IsAsync : 1; + /// If != OptimizationMode::NotSet, the optimization mode specified with an /// function attribute. unsigned OptMode : NumOptimizationModeBits; @@ -501,6 +504,10 @@ class SILFunction IsWithoutActuallyEscapingThunk = val; } + bool isAsync() const { return IsAsync; } + + void setAsync(bool val = true) { IsAsync = val; } + /// Returns the calling convention used by this entry point. SILFunctionTypeRepresentation getRepresentation() const { return getLoweredFunctionType()->getRepresentation(); diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index dd9e3731b9ac9..d504f37085831 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -3307,7 +3307,6 @@ class StringLiteralInst final enum class Encoding { Bytes, UTF8, - UTF16, /// UTF-8 encoding of an Objective-C selector. ObjCSelector, }; diff --git a/include/swift/SIL/SILValue.h b/include/swift/SIL/SILValue.h index 37064391dd50a..751484a90e175 100644 --- a/include/swift/SIL/SILValue.h +++ b/include/swift/SIL/SILValue.h @@ -41,6 +41,7 @@ class SILLocation; class DeadEndBlocks; class ValueBaseUseIterator; class ValueUseIterator; +class SILValue; /// An enumeration which contains values for all the concrete ValueBase /// subclasses. @@ -188,6 +189,12 @@ struct ValueOwnershipKind { return merge(other).hasValue(); } + /// Returns isCompatibleWith(other.getOwnershipKind()). + /// + /// Definition is inline after SILValue is defined to work around circular + /// dependencies. + bool isCompatibleWith(SILValue other) const; + template static Optional merge(RangeTy &&r) { auto initial = Optional(ValueOwnershipKind::None); @@ -440,6 +447,10 @@ class SILValue { void verifyOwnership(DeadEndBlocks *DEBlocks = nullptr) const; }; +inline bool ValueOwnershipKind::isCompatibleWith(SILValue other) const { + return isCompatibleWith(other.getOwnershipKind()); +} + /// A map from a ValueOwnershipKind that an operand can accept to a /// UseLifetimeConstraint that describes the effect that the operand's use has /// on the underlying value. If a ValueOwnershipKind is not in this map then diff --git a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h index f222f2309cc79..6cac152cd8ce4 100644 --- a/include/swift/SILOptimizer/Utils/SILSSAUpdater.h +++ b/include/swift/SILOptimizer/Utils/SILSSAUpdater.h @@ -18,9 +18,14 @@ #include "swift/SIL/SILValue.h" namespace llvm { - template class SSAUpdaterTraits; - template class SmallVectorImpl; -} + +template +class SSAUpdaterTraits; + +template +class SmallVectorImpl; + +} // namespace llvm namespace swift { @@ -31,7 +36,7 @@ class SILUndef; /// Independent utility that canonicalizes BB arguments by reusing structurally /// equivalent arguments and replacing the original arguments with casts. -SILValue replaceBBArgWithCast(SILPhiArgument *Arg); +SILValue replaceBBArgWithCast(SILPhiArgument *arg); /// This class updates SSA for a set of SIL instructions defined in multiple /// blocks. @@ -40,16 +45,16 @@ class SILSSAUpdater { // A map of basic block to available phi value. using AvailableValsTy = llvm::DenseMap; - std::unique_ptr AV; + std::unique_ptr blockToAvailableValueMap; - SILType ValType; + SILType type; // The SSAUpdaterTraits specialization uses this sentinel to mark 'new' phi // nodes (all the incoming edge arguments have this sentinel set). - std::unique_ptr PHISentinel; + std::unique_ptr phiSentinel; // If not null updated with inserted 'phi' nodes (SILArgument). - SmallVectorImpl *InsertedPHIs; + SmallVectorImpl *insertedPhis; // Not copyable. void operator=(const SILSSAUpdater &) = delete; @@ -57,21 +62,21 @@ class SILSSAUpdater { public: explicit SILSSAUpdater( - SmallVectorImpl *InsertedPHIs = nullptr); + SmallVectorImpl *insertedPhis = nullptr); ~SILSSAUpdater(); - void setInsertedPhis(SmallVectorImpl *insertedPhis) { - InsertedPHIs = insertedPhis; + void setInsertedPhis(SmallVectorImpl *inputInsertedPhis) { + insertedPhis = inputInsertedPhis; } /// Initialize for a use of a value of type. - void Initialize(SILType T); + void initialize(SILType type); - bool HasValueForBlock(SILBasicBlock *BB) const; - void AddAvailableValue(SILBasicBlock *BB, SILValue V); + bool hasValueForBlock(SILBasicBlock *block) const; + void addAvailableValue(SILBasicBlock *block, SILValue value); /// Construct SSA for a value that is live at the *end* of a basic block. - SILValue GetValueAtEndOfBlock(SILBasicBlock *BB); + SILValue getValueAtEndOfBlock(SILBasicBlock *block); /// Construct SSA for a value that is live in the middle of a block. /// This handles the case where the use is before a definition of the value. @@ -85,15 +90,15 @@ class SILSSAUpdater { /// /// In this case we need to insert a 'PHI' node at the beginning of BB2 /// merging val_1 and val_2. - SILValue GetValueInMiddleOfBlock(SILBasicBlock *BB); + SILValue getValueInMiddleOfBlock(SILBasicBlock *block); - void RewriteUse(Operand &Op); + void rewriteUse(Operand &operand); - void *allocate(unsigned Size, unsigned Align) const; - static void deallocateSentinel(SILUndef *U); -private: + void *allocate(unsigned size, unsigned align) const; + static void deallocateSentinel(SILUndef *undef); - SILValue GetValueAtEndOfBlockInternal(SILBasicBlock *BB); +private: + SILValue getValueAtEndOfBlockInternal(SILBasicBlock *block); }; /// Utility to wrap 'Operand's to deal with invalidation of @@ -112,15 +117,15 @@ class SILSSAUpdater { /// identify the use allowing us to reconstruct the use after the branch has /// been changed. class UseWrapper { - Operand *U; - SILBasicBlock *Parent; + Operand *wrappedUse; + SILBasicBlock *parent; enum { kRegularUse, kBranchUse, kCondBranchUseTrue, kCondBranchUseFalse - } Type; - unsigned Idx; + } type; + unsigned index; public: @@ -131,7 +136,7 @@ class UseWrapper { /// (ValueUseIterator) become invalid as they point to freed operands. /// Instead we store the branch's parent and the idx so that we can /// reconstruct the use. - UseWrapper(Operand *Use); + UseWrapper(Operand *use); Operand *getOperand(); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 94e6654c5562b..532790cc94f3b 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -368,7 +368,6 @@ static StringRef getStringLiteralExprEncodingString(StringLiteralExpr::Encoding value) { switch (value) { case StringLiteralExpr::UTF8: return "utf8"; - case StringLiteralExpr::UTF16: return "utf16"; case StringLiteralExpr::OneUnicodeScalar: return "unicodeScalar"; } @@ -2829,6 +2828,11 @@ class PrintExpr : public ExprVisitor { PrintWithColorRAII(OS, DiscriminatorColor) << "#" << component.getTupleIndex(); break; + case KeyPathExpr::Component::Kind::DictionaryKey: + PrintWithColorRAII(OS, ASTNodeColor) << "dict_key"; + PrintWithColorRAII(OS, IdentifierColor) + << " key='" << component.getUnresolvedDeclName() << "'"; + break; } PrintWithColorRAII(OS, TypeColor) << " type='" << GetTypeOfKeyPathComponent(E, i) << "'"; diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 6c6726c2c0225..3641f7c807627 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -1133,6 +1133,7 @@ class Traversal : public ASTVisitor parents; for (unsigned i : range(equivClass->derivedSameTypeComponents.size())) { parents.push_back(i); diff --git a/lib/AST/LocalizationFormat.cpp b/lib/AST/LocalizationFormat.cpp index f0af4a133288a..5bc4f46cf5e64 100644 --- a/lib/AST/LocalizationFormat.cpp +++ b/lib/AST/LocalizationFormat.cpp @@ -1,5 +1,4 @@ -//===--- LocalizationFormat.cpp - YAML format for Diagnostic Messages ---*- -// C++ -*-===// +//===-- LocalizationFormat.cpp - Format for Diagnostic Messages -*- C++ -*-===// // // This source file is part of the Swift.org open source project // @@ -16,26 +15,27 @@ //===----------------------------------------------------------------------===// #include "swift/AST/LocalizationFormat.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include #include +#include #include namespace { + enum LocalDiagID : uint32_t { #define DIAG(KIND, ID, Options, Text, Signature) ID, #include "swift/AST/DiagnosticsAll.def" NumDiags }; -struct DiagnosticNode { - uint32_t id; - std::string msg; -}; } // namespace namespace llvm { @@ -46,15 +46,10 @@ template <> struct ScalarEnumerationTraits { #define DIAG(KIND, ID, Options, Text, Signature) \ io.enumCase(value, #ID, LocalDiagID::ID); #include "swift/AST/DiagnosticsAll.def" - } -}; - -template <> struct MappingTraits { - static void mapping(IO &io, DiagnosticNode &node) { - LocalDiagID diagID; - io.mapRequired("id", diagID); - io.mapRequired("msg", node.msg); - node.id = static_cast(diagID); + // Ignore diagnostic IDs that are available in the YAML file and not + // available in the `.def` file. + if (io.matchEnumFallback()) + value = LocalDiagID::NumDiags; } }; @@ -64,18 +59,58 @@ template <> struct MappingTraits { namespace swift { namespace diag { -YAMLLocalizationProducer::YAMLLocalizationProducer(std::string locale, - std::string path) { - llvm::SmallString<128> DiagnosticsFilePath(path); - llvm::sys::path::append(DiagnosticsFilePath, locale); - llvm::sys::path::replace_extension(DiagnosticsFilePath, ".yaml"); - auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(DiagnosticsFilePath); - // Absence of localizations shouldn't crash the compiler. - if (!FileBufOrErr) - return; +void SerializedLocalizationWriter::insert(swift::DiagID id, + llvm::StringRef translation) { + generator.insert(static_cast(id), translation); +} + +bool SerializedLocalizationWriter::emit(llvm::StringRef filePath) { + assert(llvm::sys::path::extension(filePath) == ".db"); + std::error_code error; + llvm::raw_fd_ostream OS(filePath, error, llvm::sys::fs::F_None); + if (OS.has_error()) { + return true; + } + + offset_type offset; + { + llvm::support::endian::write(OS, 0, llvm::support::little); + offset = generator.Emit(OS); + } + OS.seek(0); + llvm::support::endian::write(OS, offset, llvm::support::little); + OS.close(); + + return OS.has_error(); +} + +SerializedLocalizationProducer::SerializedLocalizationProducer( + std::unique_ptr buffer) + : Buffer(std::move(buffer)) { + auto base = + reinterpret_cast(Buffer.get()->getBufferStart()); + auto tableOffset = endian::read(base, little); + SerializedTable.reset(SerializedLocalizationTable::Create( + base + tableOffset, base + sizeof(offset_type), base)); +} + +llvm::StringRef SerializedLocalizationProducer::getMessageOr( + swift::DiagID id, llvm::StringRef defaultMessage) const { + auto value = SerializedTable.get()->find(id); + llvm::StringRef diagnosticMessage((const char *)value.getDataPtr(), + value.getDataLen()); + if (diagnosticMessage.empty()) + return defaultMessage; + + return diagnosticMessage; +} + +YAMLLocalizationProducer::YAMLLocalizationProducer(llvm::StringRef filePath) { + auto FileBufOrErr = llvm::MemoryBuffer::getFileOrSTDIN(filePath); llvm::MemoryBuffer *document = FileBufOrErr->get(); diag::LocalizationInput yin(document->getBuffer()); yin >> diagnostics; + unknownIDs = std::move(yin.unknownIDs); } llvm::StringRef @@ -89,24 +124,54 @@ YAMLLocalizationProducer::getMessageOr(swift::DiagID id, return diagnosticMessage; } +void YAMLLocalizationProducer::forEachAvailable( + llvm::function_ref callback) const { + for (uint32_t i = 0, n = diagnostics.size(); i != n; ++i) { + auto translation = diagnostics[i]; + if (!translation.empty()) + callback(static_cast(i), translation); + } +} + +llvm::Optional LocalizationInput::readID(llvm::yaml::IO &io) { + LocalDiagID diagID; + io.mapRequired("id", diagID); + if (diagID == LocalDiagID::NumDiags) + return llvm::None; + return static_cast(diagID); +} + template typename std::enable_if::value, void>::type -readYAML(llvm::yaml::IO &io, T &Seq, bool, Context &Ctx) { +readYAML(llvm::yaml::IO &io, T &Seq, T &unknownIDs, bool, Context &Ctx) { unsigned count = io.beginSequence(); - if (count) + if (count) { Seq.resize(LocalDiagID::NumDiags); + } + for (unsigned i = 0; i < count; ++i) { void *SaveInfo; if (io.preflightElement(i, SaveInfo)) { - DiagnosticNode current; - yamlize(io, current, true, Ctx); + io.beginMapping(); + + // If the current diagnostic ID is available in YAML and in `.def`, add it + // to the diagnostics array. Otherwise, re-parse the current diagnnostic + // id as a string and store it in `unknownIDs` array. + if (auto id = LocalizationInput::readID(io)) { + // YAML file isn't guaranteed to have diagnostics in order of their + // declaration in `.def` files, to accommodate that we need to leave + // holes in diagnostic array for diagnostics which haven't yet been + // localized and for the ones that have `id` indicates their position. + io.mapRequired("msg", Seq[*id]); + } else { + std::string unknownID, message; + // Read "raw" id since it doesn't exist in `.def` file. + io.mapRequired("id", unknownID); + io.mapRequired("msg", message); + unknownIDs.push_back(unknownID); + } + io.endMapping(); io.postflightElement(SaveInfo); - // YAML file isn't guaranteed to have diagnostics in order of their - // declaration in `.def` files, to accommodate that we need to leave - // holes in diagnostic array for diagnostics which haven't yet been - // localized and for the ones that have `DiagnosticNode::id` - // indicates their position. - Seq[static_cast(current.id)] = std::move(current.msg); } } io.endSequence(); @@ -120,7 +185,7 @@ operator>>(LocalizationInput &yin, T &diagnostics) { if (yin.setCurrentDocument()) { // If YAML file's format doesn't match the current format in // DiagnosticMessageFormat, will throw an error. - readYAML(yin, diagnostics, true, Ctx); + readYAML(yin, diagnostics, yin.unknownIDs, true, Ctx); } return yin; } diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index df94b8ea9a972..fdbfb119ebddb 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -861,13 +861,18 @@ SelfBounds SelfBoundsFromWhereClauseRequest::evaluate( continue; // Resolve the right-hand side. - if (auto *const typeRepr = req.getConstraintRepr()) { - const auto rhsNominals = getDirectlyReferencedNominalTypeDecls( - ctx, typeRepr, lookupDC, result.anyObject); - - result.decls.insert(result.decls.end(), rhsNominals.begin(), - rhsNominals.end()); + DirectlyReferencedTypeDecls rhsDecls; + if (auto typeRepr = req.getConstraintRepr()) { + rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC); } + + SmallVector modulesFound; + auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls, + modulesFound, + result.anyObject); + result.decls.insert(result.decls.end(), + rhsNominals.begin(), + rhsNominals.end()); } return result; @@ -2134,17 +2139,6 @@ static DirectlyReferencedTypeDecls directReferencesForType(Type type) { return { }; } -TinyPtrVector swift::getDirectlyReferencedNominalTypeDecls( - ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc, bool &anyObject) { - const auto referenced = - directReferencesForTypeRepr(ctx.evaluator, ctx, typeRepr, dc); - - // Resolve those type declarations to nominal type declarations. - SmallVector modulesFound; - return resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, modulesFound, - anyObject); -} - DirectlyReferencedTypeDecls InheritedDeclsReferencedRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion decl, @@ -2266,10 +2260,16 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator, // We must've seen 'extension { ... }' during parsing. return nullptr; + ASTContext &ctx = ext->getASTContext(); + DirectlyReferencedTypeDecls referenced = + directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext->getParent()); + // Resolve those type declarations to nominal type declarations. + SmallVector modulesFound; bool anyObject = false; - const auto nominalTypes = getDirectlyReferencedNominalTypeDecls( - ext->getASTContext(), typeRepr, ext->getParent(), anyObject); + auto nominalTypes + = resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound, + anyObject); // If there is more than 1 element, we will emit a warning or an error // elsewhere, so don't handle that case here. diff --git a/lib/Basic/Unicode.cpp b/lib/Basic/Unicode.cpp index a299c457a7805..e7479be57820f 100644 --- a/lib/Basic/Unicode.cpp +++ b/lib/Basic/Unicode.cpp @@ -123,22 +123,3 @@ unsigned swift::unicode::extractFirstUnicodeScalar(StringRef S) { (void)Result; return Scalar; } - -uint64_t swift::unicode::getUTF16Length(StringRef Str) { - uint64_t Length; - // Transcode the string to UTF-16 to get its length. - SmallVector buffer(Str.size() + 1); // +1 for ending nulls. - const llvm::UTF8 *fromPtr = (const llvm::UTF8 *) Str.data(); - llvm::UTF16 *toPtr = &buffer[0]; - llvm::ConversionResult Result = - ConvertUTF8toUTF16(&fromPtr, fromPtr + Str.size(), - &toPtr, toPtr + Str.size(), - llvm::strictConversion); - assert(Result == llvm::conversionOK && - "UTF-8 encoded string cannot be converted into UTF-16 encoding"); - (void)Result; - - // The length of the transcoded string in UTF-16 code points. - Length = toPtr - &buffer[0]; - return Length; -} diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index bdb3437ee50e2..f9c3828c19c67 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1448,9 +1448,23 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_disable_concrete_type_metadata_mangled_name_accessors)) Opts.DisableConcreteTypeMetadataMangledNameAccessors = true; - if (Args.hasArg(OPT_use_jit)) + if (Args.hasArg(OPT_use_jit)) { Opts.UseJIT = true; - + if (const Arg *A = Args.getLastArg(OPT_dump_jit)) { + llvm::Optional artifact = + llvm::StringSwitch>(A->getValue()) + .Case("llvm-ir", JITDebugArtifact::LLVMIR) + .Case("object", JITDebugArtifact::Object) + .Default(None); + if (!artifact) { + Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value, + A->getOption().getName(), A->getValue()); + return true; + } + Opts.DumpJIT = *artifact; + } + } + for (const Arg *A : Args.filtered(OPT_verify_type_layout)) { Opts.VerifyTypeLayoutNames.push_back(A->getValue()); } diff --git a/lib/FrontendTool/ScanDependencies.cpp b/lib/FrontendTool/ScanDependencies.cpp index e68955216b343..6a90ae8231c86 100644 --- a/lib/FrontendTool/ScanDependencies.cpp +++ b/lib/FrontendTool/ScanDependencies.cpp @@ -470,6 +470,57 @@ static void writeJSON(llvm::raw_ostream &out, } } +static bool diagnoseCycle(CompilerInstance &instance, + ModuleDependenciesCache &cache, + ModuleDependencyID mainId, + InterfaceSubContextDelegate &astDelegate) { + llvm::SetVector, + std::set> openSet; + llvm::SetVector, + std::set> closeSet; + // Start from the main module. + openSet.insert(mainId); + while(!openSet.empty()) { + auto &lastOpen = openSet.back(); + auto beforeSize = openSet.size(); + for (auto dep: resolveDirectDependencies(instance, lastOpen, cache, + astDelegate)) { + if (closeSet.count(dep)) + continue; + if (openSet.insert(dep)) { + break; + } else { + // Find a cycle, diagnose. + auto startIt = std::find(openSet.begin(), openSet.end(), dep); + assert(startIt != openSet.end()); + llvm::SmallString<64> buffer; + for (auto it = startIt; it != openSet.end(); ++ it) { + buffer.append(it->first); + buffer.append(it->second == ModuleDependenciesKind::Swift? + ".swiftmodule": ".pcm"); + buffer.append(" -> "); + } + buffer.append(startIt->first); + buffer.append(startIt->second == ModuleDependenciesKind::Swift? + ".swiftmodule": ".pcm"); + instance.getASTContext().Diags.diagnose(SourceLoc(), + diag::scanner_find_cycle, + buffer.str()); + return true; + } + } + // No new node added. We can close this node + if (openSet.size() == beforeSize) { + closeSet.insert(openSet.back()); + openSet.pop_back(); + } else { + assert(openSet.size() == beforeSize + 1); + } + } + assert(openSet.empty()); + return false; +} + bool swift::scanDependencies(CompilerInstance &instance) { ASTContext &Context = instance.getASTContext(); ModuleDecl *mainModule = instance.getMainModule(); @@ -592,6 +643,10 @@ bool swift::scanDependencies(CompilerInstance &instance) { allModules.insert(id); }); + // Dignose cycle in dependency graph. + if (diagnoseCycle(instance, cache, /*MainModule*/allModules.front(), ASTDelegate)) + return true; + // Write out the JSON description. writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef()); diff --git a/lib/IDE/SourceEntityWalker.cpp b/lib/IDE/SourceEntityWalker.cpp index a7a3f7d0ea4de..6f6f08e9daf27 100644 --- a/lib/IDE/SourceEntityWalker.cpp +++ b/lib/IDE/SourceEntityWalker.cpp @@ -412,6 +412,7 @@ std::pair SemaAnnotator::walkToExprPre(Expr *E) { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::OptionalForce: case KeyPathExpr::Component::Kind::Identity: + case KeyPathExpr::Component::Kind::DictionaryKey: break; } } @@ -684,7 +685,7 @@ bool SemaAnnotator:: passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc, ReferenceMetaData Data) { SourceManager &SM = D->getASTContext().SourceMgr; SourceLoc BaseStart = Loc.getBaseNameLoc(), BaseEnd = BaseStart; - if (SM.extractText({BaseStart, 1}) == "`") + if (BaseStart.isValid() && SM.extractText({BaseStart, 1}) == "`") BaseEnd = Lexer::getLocForEndOfToken(SM, BaseStart.getAdvancedLoc(1)); return passReference(D, Ty, BaseStart, {BaseStart, BaseEnd}, Data); } diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index 5054b5344303f..90ff58b9bfa15 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -357,7 +357,7 @@ llvm::Value *irgen::emitReferenceToObjCProtocol(IRGenFunction &IGF, /// The function's output type is (value, witnessTable...) /// /// The value is NULL if the cast failed. -static llvm::Function * +static llvm::Constant * emitExistentialScalarCastFn(IRGenModule &IGM, unsigned numProtocols, CheckedCastMode mode, @@ -385,13 +385,7 @@ emitExistentialScalarCastFn(IRGenModule &IGM, } } - // See if we already defined this function. - - if (auto fn = IGM.Module.getFunction(name)) - return fn; - // Build the function type. - llvm::SmallVector argTys; llvm::SmallVector returnTys; argTys.push_back(IGM.Int8PtrTy); @@ -405,84 +399,77 @@ emitExistentialScalarCastFn(IRGenModule &IGM, } llvm::Type *returnTy = llvm::StructType::get(IGM.getLLVMContext(), returnTys); - - auto fnTy = llvm::FunctionType::get(returnTy, argTys, /*vararg*/ false); - auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, - llvm::Twine(name), IGM.getModule()); - fn->setAttributes(IGM.constructInitialAttributes()); - - IRGenFunction IGF(IGM, fn); - if (IGM.DebugInfo) - IGM.DebugInfo->emitArtificialFunction(IGF, fn); - Explosion args = IGF.collectParameters(); - - auto value = args.claimNext(); - auto ref = args.claimNext(); - auto failBB = IGF.createBasicBlock("fail"); - auto conformsToProtocol = IGM.getConformsToProtocolFn(); - - Explosion rets; - rets.add(value); - - // Check the class constraint if necessary. - if (checkSuperclassConstraint) { - auto superclassMetadata = args.claimNext(); - auto castFn = IGF.IGM.getDynamicCastMetatypeFn(); - auto castResult = IGF.Builder.CreateCall(castFn, {ref, - superclassMetadata}); - - auto cc = cast(castFn)->getCallingConv(); - - // FIXME: Eventually, we may want to throw. - castResult->setCallingConv(cc); - castResult->setDoesNotThrow(); - auto isClass = IGF.Builder.CreateICmpNE( - castResult, - llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy)); + return IGM.getOrCreateHelperFunction(name, returnTy, argTys, + [&](IRGenFunction &IGF) { + Explosion args = IGF.collectParameters(); + + auto value = args.claimNext(); + auto ref = args.claimNext(); + auto failBB = IGF.createBasicBlock("fail"); + auto conformsToProtocol = IGM.getConformsToProtocolFn(); + + Explosion rets; + rets.add(value); + + // Check the class constraint if necessary. + if (checkSuperclassConstraint) { + auto superclassMetadata = args.claimNext(); + auto castFn = IGF.IGM.getDynamicCastMetatypeFn(); + auto castResult = IGF.Builder.CreateCall(castFn, {ref, + superclassMetadata}); + + auto cc = cast(castFn)->getCallingConv(); + + // FIXME: Eventually, we may want to throw. + castResult->setCallingConv(cc); + castResult->setDoesNotThrow(); + + auto isClass = IGF.Builder.CreateICmpNE( + castResult, + llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy)); + + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isClass, contBB, failBB); + IGF.Builder.emitBlock(contBB); + } else if (checkClassConstraint) { + auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref); + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isClass, contBB, failBB); + IGF.Builder.emitBlock(contBB); + } - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isClass, contBB, failBB); - IGF.Builder.emitBlock(contBB); - } else if (checkClassConstraint) { - auto isClass = IGF.Builder.CreateCall(IGM.getIsClassTypeFn(), ref); - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isClass, contBB, failBB); - IGF.Builder.emitBlock(contBB); - } + // Look up each protocol conformance we want. + for (unsigned i = 0; i < numProtocols; ++i) { + auto proto = args.claimNext(); + auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto}); + auto isNull = IGF.Builder.CreateICmpEQ(witness, + llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); + auto contBB = IGF.createBasicBlock("cont"); + IGF.Builder.CreateCondBr(isNull, failBB, contBB); + + IGF.Builder.emitBlock(contBB); + rets.add(witness); + } - // Look up each protocol conformance we want. - for (unsigned i = 0; i < numProtocols; ++i) { - auto proto = args.claimNext(); - auto witness = IGF.Builder.CreateCall(conformsToProtocol, {ref, proto}); - auto isNull = IGF.Builder.CreateICmpEQ(witness, - llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); - auto contBB = IGF.createBasicBlock("cont"); - IGF.Builder.CreateCondBr(isNull, failBB, contBB); + // If we succeeded, return the witnesses. + IGF.emitScalarReturn(returnTy, rets); - IGF.Builder.emitBlock(contBB); - rets.add(witness); - } - - // If we succeeded, return the witnesses. - IGF.emitScalarReturn(returnTy, rets); - - // If we failed, return nil or trap. - IGF.Builder.emitBlock(failBB); - switch (mode) { - case CheckedCastMode::Conditional: { - auto null = llvm::ConstantStruct::getNullValue(returnTy); - IGF.Builder.CreateRet(null); - break; - } + // If we failed, return nil or trap. + IGF.Builder.emitBlock(failBB); + switch (mode) { + case CheckedCastMode::Conditional: { + auto null = llvm::ConstantStruct::getNullValue(returnTy); + IGF.Builder.CreateRet(null); + break; + } - case CheckedCastMode::Unconditional: { - IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true); - break; - } - } - - return fn; + case CheckedCastMode::Unconditional: { + IGF.emitTrap("type cast failed", /*EmitUnreachable=*/true); + break; + } + } + }); } llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF, diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index 912f0e3ad6131..94ab37632feba 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -1284,7 +1284,7 @@ namespace { // }; assert(fields.getNextOffsetFromGlobal() == size); - return buildGlobalVariable(fields, "_CATEGORY_"); + return buildGlobalVariable(fields, "_CATEGORY_", /*const*/ true); } llvm::Constant *emitProtocol() { @@ -1336,7 +1336,7 @@ namespace { // }; assert(fields.getNextOffsetFromGlobal() == size); - return buildGlobalVariable(fields, "_PROTOCOL_"); + return buildGlobalVariable(fields, "_PROTOCOL_", /*const*/ true); } void emitRODataFields(ConstantStructBuilder &b, @@ -1439,7 +1439,7 @@ namespace { emitRODataFields(fields, forMeta, hasUpdater); auto dataSuffix = forMeta ? "_METACLASS_DATA_" : "_DATA_"; - return buildGlobalVariable(fields, dataSuffix); + return buildGlobalVariable(fields, dataSuffix, /*const*/ true); } private: @@ -1673,7 +1673,8 @@ namespace { return null(); } - return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_"); + return buildGlobalVariable(array, "_PROTOCOL_METHOD_TYPES_", + /*const*/ true); } void buildExtMethodTypes(ConstantArrayBuilder &array, @@ -1698,6 +1699,7 @@ namespace { llvm::Constant *buildMethodList(ArrayRef methods, StringRef name) { return buildOptionalList(methods, 3 * IGM.getPointerSize(), name, + /*isConst*/ false, [&](ConstantArrayBuilder &descriptors, MethodDescriptor descriptor) { buildMethod(descriptors, descriptor); @@ -1723,6 +1725,7 @@ namespace { chooseNamePrefix("_PROTOCOLS_", "_CATEGORY_PROTOCOLS_", "_PROTOCOL_PROTOCOLS_"), + /*isConst*/ true, [&](ConstantArrayBuilder &descriptors, ProtocolDecl *protocol) { buildProtocol(descriptors, protocol); @@ -1836,6 +1839,7 @@ namespace { llvm::Constant *buildIvarList() { Size eltSize = 3 * IGM.getPointerSize() + Size(8); return buildOptionalList(Ivars, eltSize, "_IVARS_", + /*constant*/ true, [&](ConstantArrayBuilder &descriptors, VarDecl *ivar) { buildIvar(descriptors, ivar); @@ -1971,6 +1975,7 @@ namespace { StringRef namePrefix) { Size eltSize = 2 * IGM.getPointerSize(); return buildOptionalList(properties, eltSize, namePrefix, + /*constant*/ true, [&](ConstantArrayBuilder &descriptors, VarDecl *property) { buildProperty(descriptors, property); @@ -1989,6 +1994,7 @@ namespace { llvm::Constant *buildOptionalList(const C &objects, Size optionalEltSize, StringRef nameBase, + bool isConst, Fn &&buildElement) { if (objects.empty()) return null(); @@ -2027,7 +2033,7 @@ namespace { fields.fillPlaceholderWithInt(countPosition, countType, count); - return buildGlobalVariable(fields, nameBase); + return buildGlobalVariable(fields, nameBase, isConst); } /// Get the name of the class or protocol to mangle into the ObjC symbol @@ -2047,7 +2053,8 @@ namespace { /// Build a private global variable as a structure containing the /// given fields. template - llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase) { + llvm::Constant *buildGlobalVariable(B &fields, StringRef nameBase, + bool isConst) { llvm::SmallString<64> nameBuffer; auto var = fields.finishAndCreateGlobal(Twine(nameBase) @@ -2061,7 +2068,8 @@ namespace { switch (IGM.TargetInfo.OutputObjectFormat) { case llvm::Triple::MachO: - var->setSection("__DATA, __objc_const"); + var->setSection(isConst ? "__DATA, __objc_const" + : "__DATA, __objc_data"); break; case llvm::Triple::XCOFF: case llvm::Triple::COFF: diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index 071d49f82603b..0d6e021e8327f 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -102,14 +102,6 @@ llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM, case StringLiteralInst::Encoding::UTF8: return IGM.getAddrOfGlobalString(SLI->getValue()); - case StringLiteralInst::Encoding::UTF16: { - // This is always a GEP of a GlobalVariable with a nul terminator. - auto addr = IGM.getAddrOfGlobalUTF16String(SLI->getValue()); - - // Cast to Builtin.RawPointer. - return llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy); - } - case StringLiteralInst::Encoding::ObjCSelector: llvm_unreachable("cannot get the address of an Objective-C selector"); } diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 81fd8183d7aec..c207e75ad800f 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -4860,6 +4860,7 @@ static llvm::Function *shouldDefineHelper(IRGenModule &IGM, if (!def) return nullptr; if (!def->empty()) return nullptr; + def->setAttributes(IGM.constructInitialAttributes()); ApplyIRLinkage(IRLinkage::InternalLinkOnceODR).to(def); def->setDoesNotThrow(); def->setCallingConv(IGM.DefaultCC); diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index 41128f62b8620..6cfc8d962c9b9 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -277,6 +277,7 @@ getLayoutFunctionForComputedComponent(IRGenModule &IGM, auto layoutFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_get_arg_layout", IGM.getModule()); + layoutFn->setAttributes(IGM.constructInitialAttributes()); { IRGenFunction IGF(IGM, layoutFn); @@ -378,6 +379,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, auto destroyFn = llvm::Function::Create(destroyType, llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule()); destroy = destroyFn; + destroyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, destroyFn); if (IGM.DebugInfo) @@ -426,6 +428,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, auto copyFn = llvm::Function::Create(copyType, llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule()); copy = copyFn; + copyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, copyFn); if (IGM.DebugInfo) @@ -538,6 +541,7 @@ getInitializerForComputedComponent(IRGenModule &IGM, auto initFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_arg_init", IGM.getModule()); + initFn->setAttributes(IGM.constructInitialAttributes()); { IRGenFunction IGF(IGM, initFn); @@ -945,23 +949,16 @@ emitKeyPathComponent(IRGenModule &IGM, // Note that we'd need to do this anyway in JIT mode because we would // need to unique the selector at runtime anyway. auto selectorName = IGM.getObjCSelectorName(declRef); - llvm::Type *fnParams[] = {IGM.Int8PtrTy}; - auto fnTy = llvm::FunctionType::get(IGM.Int8PtrTy, fnParams, false); SmallString<32> fnName; fnName.append("keypath_get_selector_"); fnName.append(selectorName); - auto fn = cast( - IGM.Module.getOrInsertFunction(fnName, fnTy).getCallee()); - if (fn->empty()) { - fn->setLinkage(llvm::Function::PrivateLinkage); - IRGenFunction subIGF(IGM, fn); - if (IGM.DebugInfo) - IGM.DebugInfo->emitArtificialFunction(subIGF, fn); - + auto fn = IGM.getOrCreateHelperFunction(fnName, IGM.Int8PtrTy, + {IGM.Int8PtrTy}, + [&selectorName](IRGenFunction &subIGF) { auto selectorValue = subIGF.emitObjCSelectorRefLoad(selectorName); subIGF.Builder.CreateRet(selectorValue); - } - + }); + idValue = fn; idResolution = KeyPathComponentHeader::FunctionCall; } else { diff --git a/lib/IRGen/GenOpaque.cpp b/lib/IRGen/GenOpaque.cpp index a6a328f273aa4..a01ff1ad59adc 100644 --- a/lib/IRGen/GenOpaque.cpp +++ b/lib/IRGen/GenOpaque.cpp @@ -1354,6 +1354,7 @@ irgen::getOrCreateGetExtraInhabitantTagFunction(IRGenModule &IGM, auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage, "__swift_get_extra_inhabitant_index", &IGM.Module); + fn->setAttributes(IGM.constructInitialAttributes()); fn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, fn); auto parameters = IGF.collectParameters(); @@ -1427,8 +1428,9 @@ irgen::getOrCreateStoreExtraInhabitantTagFunction(IRGenModule &IGM, // TODO: use a meaningful mangled name and internal/shared linkage. auto fn = llvm::Function::Create(fnTy, llvm::Function::PrivateLinkage, - "__swift_get_extra_inhabitant_index", + "__swift_store_extra_inhabitant_index", &IGM.Module); + fn->setAttributes(IGM.constructInitialAttributes()); fn->setCallingConv(IGM.SwiftCC); IRGenFunction IGF(IGM, fn); auto parameters = IGF.collectParameters(); diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index b8c647fbefc6d..3f1961f80664b 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -53,6 +53,7 @@ enum class StructTypeInfoKind { LoadableStructTypeInfo, FixedStructTypeInfo, LoadableClangRecordTypeInfo, + AddressOnlyClangRecordTypeInfo, NonFixedStructTypeInfo, ResilientStructTypeInfo }; @@ -83,6 +84,12 @@ namespace { /// A field-info implementation for fields of Clang types. class ClangFieldInfo : public RecordField { public: + ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout, + const TypeInfo &typeInfo) + : RecordField(typeInfo), Field(swiftField) { + completeFrom(layout); + } + ClangFieldInfo(VarDecl *swiftField, const ElementLayout &layout, unsigned explosionBegin, unsigned explosionEnd) : RecordField(layout, explosionBegin, explosionEnd), @@ -290,7 +297,7 @@ namespace { } } }; - + /// A type implementation for loadable record types imported from Clang. class LoadableClangRecordTypeInfo final : public StructTypeInfoBase { + const clang::RecordDecl *ClangDecl; + + public: + AddressOnlyClangRecordTypeInfo(ArrayRef fields, + llvm::Type *storageType, Size size, + Alignment align, + const clang::RecordDecl *clangDecl) + : StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo, + fields, storageType, size, + // We can't assume any spare bits in a C++ type + // with user-defined special member functions. + SpareBitVector(llvm::Optional{ + llvm::APInt(size.getValueInBits(), 0)}), + align, IsPOD, IsNotBitwiseTakable, IsFixedSize), + ClangDecl(clangDecl) { + (void)ClangDecl; + } + + TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM, + SILType T) const override { + return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T); + } + + void initializeFromParams(IRGenFunction &IGF, Explosion ¶ms, + Address addr, SILType T, + bool isOutlined) const override { + llvm_unreachable("Address-only C++ types must be created by C++ special " + "member functions."); + } + + llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; } + llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF, SILType T) const { + return None; + } + MemberAccessStrategy + getNonFixedFieldAccessStrategy(IRGenModule &IGM, SILType T, + const ClangFieldInfo &field) const { + llvm_unreachable("non-fixed field in Clang type?"); + } + }; + /// A type implementation for loadable struct types. class LoadableStructTypeInfo final : public StructTypeInfoBase { @@ -680,6 +731,10 @@ class ClangRecordLowering { const TypeInfo *createTypeInfo(llvm::StructType *llvmType) { llvmType->setBody(LLVMFields, /*packed*/ true); + if (SwiftType.getStructOrBoundGenericStruct()->isCxxNonTrivial()) { + return AddressOnlyClangRecordTypeInfo::create( + FieldInfos, llvmType, TotalStride, TotalAlignment, ClangDecl); + } return LoadableClangRecordTypeInfo::create(FieldInfos, NextExplosionIndex, llvmType, TotalStride, std::move(SpareBits), TotalAlignment, @@ -773,7 +828,7 @@ class ClangRecordLowering { // If we have a Swift import of this type, use our lowered information. if (swiftField) { - auto &fieldTI = cast(IGM.getTypeInfo( + auto &fieldTI = cast(IGM.getTypeInfo( SwiftType.getFieldType(swiftField, IGM.getSILModule(), IGM.getMaximalTypeExpansionContext()))); addField(swiftField, offset, fieldTI); @@ -812,7 +867,7 @@ class ClangRecordLowering { /// Add storage for an (optional) Swift field at the given offset. void addField(VarDecl *swiftField, Size offset, - const LoadableTypeInfo &fieldType) { + const FixedTypeInfo &fieldType) { assert(offset >= NextOffset && "adding fields out of order"); // Add a padding field if required. @@ -823,8 +878,11 @@ class ClangRecordLowering { } /// Add information to track a value field at the current offset. - void addFieldInfo(VarDecl *swiftField, const LoadableTypeInfo &fieldType) { - unsigned explosionSize = fieldType.getExplosionSize(); + void addFieldInfo(VarDecl *swiftField, const FixedTypeInfo &fieldType) { + bool isLoadableField = isa(fieldType); + unsigned explosionSize = 0; + if (isLoadableField) + explosionSize = cast(fieldType).getExplosionSize(); unsigned explosionBegin = NextExplosionIndex; NextExplosionIndex += explosionSize; unsigned explosionEnd = NextExplosionIndex; @@ -838,9 +896,12 @@ class ClangRecordLowering { layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal), NextOffset, LLVMFields.size()); - FieldInfos.push_back( - ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd)); - + if (isLoadableField) + FieldInfos.push_back( + ClangFieldInfo(swiftField, layout, explosionBegin, explosionEnd)); + else + FieldInfos.push_back(ClangFieldInfo(swiftField, layout, fieldType)); + if (!isEmpty) { LLVMFields.push_back(fieldType.getStorageType()); NextOffset += fieldType.getFixedSize(); @@ -862,22 +923,26 @@ class ClangRecordLowering { /// A convenient macro for delegating an operation to all of the /// various struct implementations. -#define FOR_STRUCT_IMPL(IGF, type, op, ...) do { \ - auto &structTI = IGF.getTypeInfo(type); \ - switch (getStructTypeInfoKind(structTI)) { \ - case StructTypeInfoKind::LoadableClangRecordTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::LoadableStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::FixedStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::NonFixedStructTypeInfo: \ - return structTI.as().op(IGF, __VA_ARGS__); \ - case StructTypeInfoKind::ResilientStructTypeInfo: \ - llvm_unreachable("resilient structs are opaque"); \ - } \ - llvm_unreachable("bad struct type info kind!"); \ -} while (0) +#define FOR_STRUCT_IMPL(IGF, type, op, ...) \ + do { \ + auto &structTI = IGF.getTypeInfo(type); \ + switch (getStructTypeInfoKind(structTI)) { \ + case StructTypeInfoKind::LoadableClangRecordTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::AddressOnlyClangRecordTypeInfo: \ + return structTI.as().op(IGF, \ + __VA_ARGS__); \ + case StructTypeInfoKind::LoadableStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::FixedStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::NonFixedStructTypeInfo: \ + return structTI.as().op(IGF, __VA_ARGS__); \ + case StructTypeInfoKind::ResilientStructTypeInfo: \ + llvm_unreachable("resilient structs are opaque"); \ + } \ + llvm_unreachable("bad struct type info kind!"); \ + } while (0) Address irgen::projectPhysicalStructMemberAddress(IRGenFunction &IGF, Address base, diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index a3f83a2e9edd5..91eefd6d832dc 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1418,6 +1418,7 @@ void IRGenModule::emitAutolinkInfo() { llvm::Function::Create(llvm::FunctionType::get(VoidTy, false), llvm::GlobalValue::ExternalLinkage, buf, &Module); + ForceImportThunk->setAttributes(constructInitialAttributes()); ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk); if (Triple.supportsCOMDAT()) if (auto *GO = cast(ForceImportThunk)) diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 7dfd2be9b2f44..5a794512e3ff1 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -2256,66 +2256,57 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( // Factor out the buffer shuffling for metadata accessors that take their // arguments directly, so that the accessor function itself only needs to // materialize the nominal type descriptor and call this thunk. - auto thunkFn = cast( - IGM.getModule() - ->getOrInsertFunction("__swift_instantiateGenericMetadata", - IGM.TypeMetadataResponseTy, - IGM.SizeTy, // request - IGM.Int8PtrTy, // arg 0 - IGM.Int8PtrTy, // arg 1 - IGM.Int8PtrTy, // arg 2 - IGM.TypeContextDescriptorPtrTy) // type context descriptor - .getCallee() - ->stripPointerCasts()); - - if (thunkFn->empty()) { - ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) - .to(thunkFn); - thunkFn->setDoesNotAccessMemory(); - thunkFn->setDoesNotThrow(); - thunkFn->setCallingConv(IGM.SwiftCC); - thunkFn->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoInline); - IGM.setHasNoFramePointer(thunkFn); - - [&IGM, thunkFn]{ - IRGenFunction subIGF(IGM, thunkFn); - - auto params = subIGF.collectParameters(); - auto request = params.claimNext(); - auto arg0 = params.claimNext(); - auto arg1 = params.claimNext(); - auto arg2 = params.claimNext(); - auto descriptor = params.claimNext(); - - // Allocate a buffer with enough storage for the arguments. - auto argsBufferTy = - llvm::ArrayType::get(IGM.Int8PtrTy, - NumDirectGenericTypeMetadataAccessFunctionArgs); - auto argsBuffer = subIGF.createAlloca(argsBufferTy, - IGM.getPointerAlignment(), - "generic.arguments"); - subIGF.Builder.CreateLifetimeStart(argsBuffer, - IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs); - - auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 0); - subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment()); - auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 1); - subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment()); - auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, - argsBuffer.getAddress(), 0, 2); - subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment()); - - // Make the call. - auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(), - IGM.Int8PtrTy); - auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), - {request, argsAddr, descriptor}); - subIGF.Builder.CreateRet(result); - }(); - } + auto generateThunkFn = [&IGM](IRGenFunction &subIGF) { + subIGF.CurFn->setDoesNotAccessMemory(); + subIGF.CurFn->setCallingConv(IGM.SwiftCC); + IGM.setHasNoFramePointer(subIGF.CurFn); + + auto params = subIGF.collectParameters(); + auto request = params.claimNext(); + auto arg0 = params.claimNext(); + auto arg1 = params.claimNext(); + auto arg2 = params.claimNext(); + auto descriptor = params.claimNext(); + + // Allocate a buffer with enough storage for the arguments. + auto argsBufferTy = + llvm::ArrayType::get(IGM.Int8PtrTy, + NumDirectGenericTypeMetadataAccessFunctionArgs); + auto argsBuffer = subIGF.createAlloca(argsBufferTy, + IGM.getPointerAlignment(), + "generic.arguments"); + subIGF.Builder.CreateLifetimeStart(argsBuffer, + IGM.getPointerSize() * NumDirectGenericTypeMetadataAccessFunctionArgs); + + auto arg0Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 0); + subIGF.Builder.CreateStore(arg0, arg0Buf, IGM.getPointerAlignment()); + auto arg1Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 1); + subIGF.Builder.CreateStore(arg1, arg1Buf, IGM.getPointerAlignment()); + auto arg2Buf = subIGF.Builder.CreateConstInBoundsGEP2_32(argsBufferTy, + argsBuffer.getAddress(), 0, 2); + subIGF.Builder.CreateStore(arg2, arg2Buf, IGM.getPointerAlignment()); + + // Make the call. + auto argsAddr = subIGF.Builder.CreateBitCast(argsBuffer.getAddress(), + IGM.Int8PtrTy); + auto result = subIGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(), + {request, argsAddr, descriptor}); + subIGF.Builder.CreateRet(result); + }; + auto thunkFn = IGM.getOrCreateHelperFunction( + "__swift_instantiateGenericMetadata", + IGM.TypeMetadataResponseTy, + { + IGM.SizeTy, // request + IGM.Int8PtrTy, // arg 0 + IGM.Int8PtrTy, // arg 1 + IGM.Int8PtrTy, // arg 2 + IGM.TypeContextDescriptorPtrTy // type context descriptor + }, + generateThunkFn, + /*noinline*/true); // Call out to the helper. auto arg0 = numArguments >= 1 @@ -2805,136 +2796,127 @@ emitMetadataAccessByMangledName(IRGenFunction &IGF, CanType type, request.isStaticallyAbstract() ? "__swift_instantiateConcreteTypeFromMangledNameAbstract" : "__swift_instantiateConcreteTypeFromMangledName"; - auto instantiationFn = cast( - IGM.getModule() - ->getOrInsertFunction(instantiationFnName, IGF.IGM.TypeMetadataPtrTy, - cache->getType()) - .getCallee() - ->stripPointerCasts()); - if (instantiationFn->empty()) { - ApplyIRLinkage(IRLinkage::InternalLinkOnceODR) - .to(instantiationFn); - instantiationFn->setDoesNotAccessMemory(); - instantiationFn->setDoesNotThrow(); - instantiationFn->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoInline); - IGM.setHasNoFramePointer(instantiationFn); - - [&IGM, instantiationFn, request]{ - IRGenFunction subIGF(IGM, instantiationFn); - - auto params = subIGF.collectParameters(); - auto cache = params.claimNext(); - - // Load the existing cache value. - // Conceptually, this needs to establish memory ordering with the - // store we do later in the function: if the metadata value is - // non-null, we must be able to see any stores performed by the - // initialization of the metadata. However, any attempt to read - // from the metadata will be address-dependent on the loaded - // metadata pointer, which is sufficient to provide adequate - // memory ordering guarantees on all the platforms we care about: - // ARM has special rules about address dependencies, and x86's - // memory ordering is strong enough to guarantee the visibility - // even without the address dependency. - // - // And we do not need to worry about the compiler because the - // address dependency naturally forces an order to the memory - // accesses. - // - // Therefore, we can perform a completely naked load here. - // FIXME: Technically should be "consume", but that introduces barriers - // in the current LLVM ARM backend. - auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache, - IGM.Int64Ty->getPointerTo()); - auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8)); - // Make this barrier explicit when building for TSan to avoid false positives. - if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) - load->setOrdering(llvm::AtomicOrdering::Acquire); - else - load->setOrdering(llvm::AtomicOrdering::Monotonic); - - // Compare the load result to see if it's negative. - auto isUnfilledBB = subIGF.createBasicBlock(""); - auto contBB = subIGF.createBasicBlock(""); - llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load, - llvm::ConstantInt::get(IGM.Int64Ty, 0)); - comparison = subIGF.Builder.CreateExpect(comparison, - llvm::ConstantInt::get(IGM.Int1Ty, 0)); - subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB); - auto loadBB = subIGF.Builder.GetInsertBlock(); - - // If the load is negative, emit the call to instantiate the type - // metadata. - subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back()); - subIGF.Builder.emitBlock(isUnfilledBB); - - // Break up the loaded value into size and relative address to the - // string. - auto size = subIGF.Builder.CreateAShr(load, 32); - size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy); - size = subIGF.Builder.CreateNeg(size); - - auto stringAddrOffset = subIGF.Builder.CreateTrunc(load, - IGM.Int32Ty); - stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset, - IGM.SizeTy); - auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); - if (IGM.getModule()->getDataLayout().isBigEndian()) { - stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, - llvm::ConstantInt::get(IGM.SizeTy, 4)); - } - auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, - stringAddrOffset); - stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); - - llvm::CallInst *call; - if (request.isStaticallyAbstract()) { - call = subIGF.Builder.CreateCall( - IGM.getGetTypeByMangledNameInContextInMetadataStateFn(), - {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract), - stringAddr, size, - // TODO: Use mangled name lookup in generic - // contexts? - llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), - llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); - } else { - call = subIGF.Builder.CreateCall( - IGM.getGetTypeByMangledNameInContextFn(), - {stringAddr, size, - // TODO: Use mangled name lookup in generic - // contexts? - llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), - llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); - } - call->setDoesNotThrow(); - call->setDoesNotAccessMemory(); - call->setCallingConv(IGM.SwiftCC); - - // Store the result back to the cache. Metadata instantatiation should - // already have emitted the necessary barriers to publish the instantiated - // metadata to other threads, so we only need to expose the pointer. - // Worst case, another thread might race with us and reinstantiate the - // exact same metadata pointer. - auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy); - resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty); - auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr, - Alignment(8)); - store->setOrdering(llvm::AtomicOrdering::Monotonic); - subIGF.Builder.CreateBr(contBB); - - subIGF.Builder.SetInsertPoint(loadBB); - subIGF.Builder.emitBlock(contBB); - auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2); - phi->addIncoming(load, loadBB); - phi->addIncoming(resultWord, isUnfilledBB); - - auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy); - resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr, - IGM.TypeMetadataPtrTy); - subIGF.Builder.CreateRet(resultAddr); - }(); - } + auto generateInstantiationFn = [&IGM, request](IRGenFunction &subIGF) { + subIGF.CurFn->setDoesNotAccessMemory(); + IGM.setHasNoFramePointer(subIGF.CurFn); + + auto params = subIGF.collectParameters(); + auto cache = params.claimNext(); + + // Load the existing cache value. + // Conceptually, this needs to establish memory ordering with the + // store we do later in the function: if the metadata value is + // non-null, we must be able to see any stores performed by the + // initialization of the metadata. However, any attempt to read + // from the metadata will be address-dependent on the loaded + // metadata pointer, which is sufficient to provide adequate + // memory ordering guarantees on all the platforms we care about: + // ARM has special rules about address dependencies, and x86's + // memory ordering is strong enough to guarantee the visibility + // even without the address dependency. + // + // And we do not need to worry about the compiler because the + // address dependency naturally forces an order to the memory + // accesses. + // + // Therefore, we can perform a completely naked load here. + // FIXME: Technically should be "consume", but that introduces barriers + // in the current LLVM ARM backend. + auto cacheWordAddr = subIGF.Builder.CreateBitCast(cache, + IGM.Int64Ty->getPointerTo()); + auto load = subIGF.Builder.CreateLoad(cacheWordAddr, Alignment(8)); + // Make this barrier explicit when building for TSan to avoid false positives. + if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread) + load->setOrdering(llvm::AtomicOrdering::Acquire); + else + load->setOrdering(llvm::AtomicOrdering::Monotonic); + + // Compare the load result to see if it's negative. + auto isUnfilledBB = subIGF.createBasicBlock(""); + auto contBB = subIGF.createBasicBlock(""); + llvm::Value *comparison = subIGF.Builder.CreateICmpSLT(load, + llvm::ConstantInt::get(IGM.Int64Ty, 0)); + comparison = subIGF.Builder.CreateExpect(comparison, + llvm::ConstantInt::get(IGM.Int1Ty, 0)); + subIGF.Builder.CreateCondBr(comparison, isUnfilledBB, contBB); + auto loadBB = subIGF.Builder.GetInsertBlock(); + + // If the load is negative, emit the call to instantiate the type + // metadata. + subIGF.Builder.SetInsertPoint(&subIGF.CurFn->back()); + subIGF.Builder.emitBlock(isUnfilledBB); + + // Break up the loaded value into size and relative address to the + // string. + auto size = subIGF.Builder.CreateAShr(load, 32); + size = subIGF.Builder.CreateTruncOrBitCast(size, IGM.SizeTy); + size = subIGF.Builder.CreateNeg(size); + + auto stringAddrOffset = subIGF.Builder.CreateTrunc(load, + IGM.Int32Ty); + stringAddrOffset = subIGF.Builder.CreateSExtOrBitCast(stringAddrOffset, + IGM.SizeTy); + auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); + if (IGM.getModule()->getDataLayout().isBigEndian()) { + stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, + llvm::ConstantInt::get(IGM.SizeTy, 4)); + } + auto stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, + stringAddrOffset); + stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); + + llvm::CallInst *call; + if (request.isStaticallyAbstract()) { + call = subIGF.Builder.CreateCall( + IGM.getGetTypeByMangledNameInContextInMetadataStateFn(), + {llvm::ConstantInt::get(IGM.SizeTy, (size_t)MetadataState::Abstract), + stringAddr, size, + // TODO: Use mangled name lookup in generic + // contexts? + llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), + llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); + } else { + call = subIGF.Builder.CreateCall( + IGM.getGetTypeByMangledNameInContextFn(), + {stringAddr, size, + // TODO: Use mangled name lookup in generic + // contexts? + llvm::ConstantPointerNull::get(IGM.TypeContextDescriptorPtrTy), + llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy)}); + } + call->setDoesNotThrow(); + call->setDoesNotAccessMemory(); + call->setCallingConv(IGM.SwiftCC); + + // Store the result back to the cache. Metadata instantatiation should + // already have emitted the necessary barriers to publish the instantiated + // metadata to other threads, so we only need to expose the pointer. + // Worst case, another thread might race with us and reinstantiate the + // exact same metadata pointer. + auto resultWord = subIGF.Builder.CreatePtrToInt(call, IGM.SizeTy); + resultWord = subIGF.Builder.CreateZExtOrBitCast(resultWord, IGM.Int64Ty); + auto store = subIGF.Builder.CreateStore(resultWord, cacheWordAddr, + Alignment(8)); + store->setOrdering(llvm::AtomicOrdering::Monotonic); + subIGF.Builder.CreateBr(contBB); + + subIGF.Builder.SetInsertPoint(loadBB); + subIGF.Builder.emitBlock(contBB); + auto phi = subIGF.Builder.CreatePHI(IGM.Int64Ty, 2); + phi->addIncoming(load, loadBB); + phi->addIncoming(resultWord, isUnfilledBB); + + auto resultAddr = subIGF.Builder.CreateTruncOrBitCast(phi, IGM.SizeTy); + resultAddr = subIGF.Builder.CreateIntToPtr(resultAddr, + IGM.TypeMetadataPtrTy); + subIGF.Builder.CreateRet(resultAddr); + }; + auto instantiationFn = + IGM.getOrCreateHelperFunction(instantiationFnName, + IGF.IGM.TypeMetadataPtrTy, + cache->getType(), + generateInstantiationFn, + /*noinline*/true); auto call = IGF.Builder.CreateCall(instantiationFn, cache); call->setDoesNotThrow(); diff --git a/lib/Immediate/Immediate.cpp b/lib/Immediate/Immediate.cpp index 5ac87f6f42397..b49156177b8f1 100644 --- a/lib/Immediate/Immediate.cpp +++ b/lib/Immediate/Immediate.cpp @@ -30,6 +30,7 @@ #include "swift/SILOptimizer/PassManager/Passes.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/LLVMContext.h" @@ -75,6 +76,18 @@ static void *loadRuntimeLib(StringRef sharedLibName, return nullptr; } +static void DumpLLVMIR(const llvm::Module &M) { + std::string path = (M.getName() + ".ll").str(); + for (size_t count = 0; llvm::sys::fs::exists(path); ) + path = (M.getName() + llvm::utostr(count++) + ".ll").str(); + + std::error_code error; + llvm::raw_fd_ostream stream(path, error); + if (error) + return; + M.print(stream, /*AssemblyAnnotationWriter=*/nullptr); +} + void *swift::immediate::loadSwiftRuntime(ArrayRef runtimeLibPaths) { #if defined(_WIN32) @@ -290,6 +303,18 @@ int swift::RunImmediately(CompilerInstance &CI, } auto Module = GenModule.getModule(); + + switch (IRGenOpts.DumpJIT) { + case JITDebugArtifact::None: + break; + case JITDebugArtifact::LLVMIR: + DumpLLVMIR(*Module); + break; + case JITDebugArtifact::Object: + JIT->getObjTransformLayer().setTransform(llvm::orc::DumpObjects()); + break; + } + { // Get a generator for the process symbols and attach it to the main // JITDylib. diff --git a/lib/LLVMPasses/LLVMMergeFunctions.cpp b/lib/LLVMPasses/LLVMMergeFunctions.cpp index da76bba87217f..51db1af2f4892 100644 --- a/lib/LLVMPasses/LLVMMergeFunctions.cpp +++ b/lib/LLVMPasses/LLVMMergeFunctions.cpp @@ -222,12 +222,6 @@ class SwiftMergeFunctions : public ModulePass { bool runOnModule(Module &M) override; private: - enum { - /// The maximum number of parameters added to a merged functions. This - /// roughly corresponds to the number of differing constants. - maxAddedParams = 4 - }; - struct FunctionEntry; /// Describes the set of functions which are considered as "equivalent" (i.e. @@ -359,7 +353,7 @@ class SwiftMergeFunctions : public ModulePass { } }; - using ParamInfos = SmallVector; + using ParamInfos = SmallVector; GlobalNumberState GlobalNumbers; @@ -398,14 +392,15 @@ class SwiftMergeFunctions : public ModulePass { FunctionInfo removeFuncWithMostParams(FunctionInfos &FInfos); - bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos); + bool deriveParams(ParamInfos &Params, FunctionInfos &FInfos, + unsigned maxParams); bool numOperandsDiffer(FunctionInfos &FInfos); bool constsDiffer(const FunctionInfos &FInfos, unsigned OpIdx); bool tryMapToParameter(FunctionInfos &FInfos, unsigned OpIdx, - ParamInfos &Params); + ParamInfos &Params, unsigned maxParams); void mergeWithParams(const FunctionInfos &FInfos, ParamInfos &Params); @@ -524,17 +519,9 @@ static bool mayMergeCallsToFunction(Function &F) { return true; } -/// Returns true if function \p F is eligible for merging. -static bool isEligibleFunction(Function *F) { - if (F->isDeclaration()) - return false; - - if (F->hasAvailableExternallyLinkage()) - return false; - - if (F->getFunctionType()->isVarArg()) - return false; - +/// Returns the benefit, which is approximately the size of the function. +/// Return 0, if the function should not be merged. +static unsigned getBenefit(Function *F) { unsigned Benefit = 0; // We don't want to merge very small functions, because the overhead of @@ -545,7 +532,7 @@ static bool isEligibleFunction(Function *F) { if (CallBase *CB = dyn_cast(&I)) { Function *Callee = CB->getCalledFunction(); if (Callee && !mayMergeCallsToFunction(*Callee)) - return false; + return 0; if (!Callee || !Callee->isIntrinsic()) { Benefit += 5; continue; @@ -554,6 +541,21 @@ static bool isEligibleFunction(Function *F) { Benefit += 1; } } + return Benefit; +} + +/// Returns true if function \p F is eligible for merging. +static bool isEligibleFunction(Function *F) { + if (F->isDeclaration()) + return false; + + if (F->hasAvailableExternallyLinkage()) + return false; + + if (F->getFunctionType()->isVarArg()) + return false; + + unsigned Benefit = getBenefit(F); if (Benefit < FunctionMergeThreshold) return false; @@ -723,12 +725,17 @@ bool SwiftMergeFunctions::tryMergeEquivalenceClass(FunctionEntry *FirstInClass) bool Changed = false; int Try = 0; + unsigned Benefit = getBenefit(FirstInClass->F); + + // The bigger the function, the more parameters are allowed. + unsigned maxParams = std::max(4u, Benefit / 100); + // We need multiple tries if there are some functions in FInfos which differ // too much from the first function in FInfos. But we limit the number of // tries to a small number, because this is quadratic. while (FInfos.size() >= 2 && Try++ < 4) { ParamInfos Params; - bool Merged = deriveParams(Params, FInfos); + bool Merged = deriveParams(Params, FInfos, maxParams); if (Merged) { mergeWithParams(FInfos, Params); Changed = true; @@ -767,7 +774,8 @@ removeFuncWithMostParams(FunctionInfos &FInfos) { /// Returns true on success, i.e. the functions in \p FInfos can be merged with /// the parameters returned in \p Params. bool SwiftMergeFunctions::deriveParams(ParamInfos &Params, - FunctionInfos &FInfos) { + FunctionInfos &FInfos, + unsigned maxParams) { for (FunctionInfo &FI : FInfos) FI.init(); @@ -796,7 +804,7 @@ bool SwiftMergeFunctions::deriveParams(ParamInfos &Params, if (constsDiffer(FInfos, OpIdx)) { // This instruction has operands which differ in at least some // functions. So we need to parameterize it. - if (!tryMapToParameter(FInfos, OpIdx, Params)) { + if (!tryMapToParameter(FInfos, OpIdx, Params, maxParams)) { // We ran out of parameters. return false; } @@ -845,7 +853,8 @@ bool SwiftMergeFunctions::constsDiffer(const FunctionInfos &FInfos, /// Returns true if a parameter could be created or found without exceeding the /// maximum number of parameters. bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos, - unsigned OpIdx, ParamInfos &Params) { + unsigned OpIdx, ParamInfos &Params, + unsigned maxParams) { ParamInfo *Matching = nullptr; // Try to find an existing parameter which exactly matches the differing // operands of the current instruction. @@ -858,7 +867,7 @@ bool SwiftMergeFunctions::tryMapToParameter(FunctionInfos &FInfos, if (!Matching) { // We need a new parameter. // Check if we are within the limit. - if (Params.size() >= maxAddedParams) + if (Params.size() >= maxParams) return false; Params.resize(Params.size() + 1); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1009646c1c40e..d7f77869d6723 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -397,7 +397,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, SourceLoc awaitLoc = consumeToken(tok::kw___await); ParserResult sub = parseExprUnary(message, isExprBasic); if (!sub.hasCodeCompletion() && !sub.isNull()) { - ElementContext.setCreateSyntax(SyntaxKind::TryExpr); + ElementContext.setCreateSyntax(SyntaxKind::AwaitExpr); sub = makeParserResult(new (Context) AwaitExpr(awaitLoc, sub.get())); } diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 443f572c04acb..aefea2401c15a 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -465,10 +465,10 @@ ParserResult Parser::parseType(Diag<> MessageID, ParsedFunctionTypeSyntaxBuilder Builder(*SyntaxContext); Builder.useReturnType(std::move(*SyntaxContext->popIf())); Builder.useArrow(SyntaxContext->popToken()); - if (asyncLoc.isValid()) - Builder.useAsyncKeyword(SyntaxContext->popToken()); if (throwsLoc.isValid()) Builder.useThrowsOrRethrowsKeyword(SyntaxContext->popToken()); + if (asyncLoc.isValid()) + Builder.useAsyncKeyword(SyntaxContext->popToken()); auto InputNode(std::move(*SyntaxContext->popIf())); if (auto TupleTypeNode = InputNode.getAs()) { diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index 8e0d770d82310..0a39386e3f35c 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -110,7 +110,7 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name, ExactSelfClass(isExactSelfClass), Inlined(false), Zombie(false), HasOwnership(true), WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false), - OptMode(unsigned(OptimizationMode::NotSet)), + IsAsync(false), OptMode(unsigned(OptimizationMode::NotSet)), EffectsKindAttr(unsigned(E)) { assert(!Transparent || !IsDynamicReplaceable); validateSubclassScope(classSubclassScope, isThunk, nullptr); diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index b56d34ea74d00..c28ba05090b1b 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -217,6 +217,10 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( } addFunctionAttributes(F, decl->getAttrs(), mod, getOrCreateDeclaration, constant); + + if (auto *funcDecl = dyn_cast(decl)) { + F->setAsync(funcDecl->hasAsync()); + } } return F; diff --git a/lib/SIL/IR/SILFunctionType.cpp b/lib/SIL/IR/SILFunctionType.cpp index e165434668d42..60f7584418787 100644 --- a/lib/SIL/IR/SILFunctionType.cpp +++ b/lib/SIL/IR/SILFunctionType.cpp @@ -242,12 +242,14 @@ IndexSubset *SILFunctionType::getDifferentiabilityResultIndices() { // 2. `@noDerivative`: neither a differentiability parameter nor a // differentiability result. // However, there is no way to represent an `inout` parameter that: - // 3. Is a differentiability parameter but not a differentiability result. - // 4. Is a differentiability result but not a differentiability parameter. + // 3. Is a differentiability result but not a differentiability parameter. + // 4. Is a differentiability parameter but not a differentiability result. + // This case is not currently expressible and does not yet have clear use + // cases, so supporting it is a non-goal. // // See TF-1305 for solution ideas. For now, `@noDerivative` `inout` // parameters are not treated as differentiability results, unless the - // original function has no formal results, which case all `inout` + // original function has no formal results, in which case all `inout` // parameters are treated as differentiability results. if (getResults().empty() || inoutParamAndIndex.value().getDifferentiability() != diff --git a/lib/SIL/IR/SILGlobalVariable.cpp b/lib/SIL/IR/SILGlobalVariable.cpp index bad50c8437f93..609a8318b153d 100644 --- a/lib/SIL/IR/SILGlobalVariable.cpp +++ b/lib/SIL/IR/SILGlobalVariable.cpp @@ -157,7 +157,6 @@ bool SILGlobalVariable::isValidStaticInitializerInst(const SILInstruction *I, switch (cast(I)->getEncoding()) { case StringLiteralInst::Encoding::Bytes: case StringLiteralInst::Encoding::UTF8: - case StringLiteralInst::Encoding::UTF16: return true; case StringLiteralInst::Encoding::ObjCSelector: // Objective-C selector string literals cannot be used in static diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index 85e21ea609f21..1faa9ec6ae6a1 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -1043,9 +1043,6 @@ CondFailInst *CondFailInst::create(SILDebugLocation DebugLoc, SILValue Operand, } uint64_t StringLiteralInst::getCodeUnitCount() { - auto E = unsigned(Encoding::UTF16); - if (SILInstruction::Bits.StringLiteralInst.TheEncoding == E) - return unicode::getUTF16Length(getValue()); return SILInstruction::Bits.StringLiteralInst.Length; } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index b1d92dd8ee5a4..bb84c23ef1e4c 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -1339,7 +1339,6 @@ class SILPrinter : public SILInstructionVisitor { switch (kind) { case StringLiteralInst::Encoding::Bytes: return "bytes "; case StringLiteralInst::Encoding::UTF8: return "utf8 "; - case StringLiteralInst::Encoding::UTF16: return "utf16 "; case StringLiteralInst::Encoding::ObjCSelector: return "objc_selector "; } llvm_unreachable("bad string literal encoding"); @@ -2599,6 +2598,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isWithoutActuallyEscapingThunk()) OS << "[without_actually_escaping] "; + if (isAsync()) + OS << "[async] "; + switch (getSpecialPurpose()) { case SILFunction::Purpose::None: break; diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 1cb9139437f49..57a637eed8c1b 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -918,6 +918,7 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *isWeakImported, AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, + bool *isAsync, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, @@ -956,6 +957,8 @@ static bool parseDeclSILOptional(bool *isTransparent, else if (isWithoutActuallyEscapingThunk && SP.P.Tok.getText() == "without_actually_escaping") *isWithoutActuallyEscapingThunk = true; + else if (isAsync && SP.P.Tok.getText() == "async") + *isAsync = true; else if (specialPurpose && SP.P.Tok.getText() == "global_init") *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") @@ -2615,8 +2618,6 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B, StringLiteralInst::Encoding encoding; if (P.Tok.getText() == "utf8") { encoding = StringLiteralInst::Encoding::UTF8; - } else if (P.Tok.getText() == "utf16") { - encoding = StringLiteralInst::Encoding::UTF16; } else if (P.Tok.getText() == "objc_selector") { encoding = StringLiteralInst::Encoding::ObjCSelector; } else if (P.Tok.getText() == "bytes") { @@ -5682,6 +5683,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { bool isWeakImported = false; AvailabilityContext availability = AvailabilityContext::alwaysAvailable(); bool isWithoutActuallyEscapingThunk = false; + bool isAsync = false; Inline_t inlineStrategy = InlineDefault; OptimizationMode optimizationMode = OptimizationMode::NotSet; SmallVector Semantics; @@ -5696,8 +5698,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { &isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, nullptr, &isWeakImported, &availability, - &isWithoutActuallyEscapingThunk, &Semantics, - &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || + &isWithoutActuallyEscapingThunk, &isAsync, &Semantics, &SpecAttrs, + &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5735,6 +5737,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setAvailabilityForLinkage(availability); FunctionState.F->setWithoutActuallyEscapingThunk( isWithoutActuallyEscapingThunk); + FunctionState.F->setAsync(isAsync); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setOptimizationMode(optimizationMode); FunctionState.F->setEffectsKind(MRK); @@ -5920,10 +5923,9 @@ bool SILParserState::parseSILGlobal(Parser &P) { SILParser State(P); if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, - &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, State, M) || + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_sil_type)) @@ -5972,7 +5974,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, SP, M)) + nullptr, nullptr, nullptr, nullptr, SP, M)) return true; ValueDecl *VD; @@ -6042,8 +6044,7 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - VTableState, M)) + nullptr, nullptr, nullptr, nullptr, VTableState, M)) return true; // Parse the class name. @@ -6582,8 +6583,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - WitnessState, M)) + nullptr, nullptr, nullptr, nullptr, WitnessState, M)) return true; Scope S(&P, ScopeKind::TopLevel); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index c8c80a3f1d3f3..bffecc2c2c187 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -1628,11 +1628,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E, Length = Str.size(); break; - case StringLiteralExpr::UTF16: { - instEncoding = StringLiteralInst::Encoding::UTF16; - Length = unicode::getUTF16Length(Str); - break; - } case StringLiteralExpr::OneUnicodeScalar: { SILType Int32Ty = SILType::getBuiltinIntegerType(32, SGF.getASTContext()); SILValue UnicodeScalarValue = @@ -1674,11 +1669,6 @@ static PreparedArguments emitStringLiteral(SILGenFunction &SGF, Expr *E, ArrayRef Elts; ArrayRef TypeElts; switch (instEncoding) { - case StringLiteralInst::Encoding::UTF16: - Elts = llvm::makeArrayRef(EltsArray).slice(0, 2); - TypeElts = llvm::makeArrayRef(TypeEltsArray).slice(0, 2); - break; - case StringLiteralInst::Encoding::UTF8: Elts = EltsArray; TypeElts = TypeEltsArray; diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 6b524fe06a9d2..cb8273d129e1e 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -3734,6 +3734,11 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) { case KeyPathExpr::Component::Kind::UnresolvedProperty: case KeyPathExpr::Component::Kind::UnresolvedSubscript: llvm_unreachable("not resolved"); + break; + + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } } diff --git a/lib/SILOptimizer/ARC/RefCountState.cpp b/lib/SILOptimizer/ARC/RefCountState.cpp index eabe4d5ed7958..e0c43fed19040 100644 --- a/lib/SILOptimizer/ARC/RefCountState.cpp +++ b/lib/SILOptimizer/ARC/RefCountState.cpp @@ -365,6 +365,14 @@ bool BottomUpRefCountState::handlePotentialGuaranteedUser( if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; + // If we can prove that the pointer we are tracking cannot be decremented, + // return. On return, BottomUpRefCountState::handlePotentialUser can correctly + // handle transition of refcount state. It transitions from a Decrement + // refcount state to a MighBeUsed refcount state + if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) { + return false; + } + // Instructions that we do not recognize (and thus will not move) and that // *must* use RCIdentity, implies we are always known safe as long as meet // over all path constraints are satisfied. @@ -816,6 +824,13 @@ bool TopDownRefCountState::handlePotentialGuaranteedUser( if (!mayGuaranteedUseValue(PotentialGuaranteedUser, getRCRoot(), AA)) return false; + // If we can prove that the pointer we are tracking cannot be decremented, + // return. On return, TopDownRefCountState::handlePotentialUser can correctly + // handle transition of refcount state. + if (!mayDecrementRefCount(PotentialGuaranteedUser, getRCRoot(), AA)) { + return false; + } + // Otherwise, update our step given that we have a potential decrement. return handleGuaranteedUser(PotentialGuaranteedUser, getRCRoot(), SetFactory, AA); diff --git a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 0438285ed07aa..aa40f16f53d91 100644 --- a/lib/SILOptimizer/Differentiation/PullbackCloner.cpp +++ b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp @@ -650,6 +650,19 @@ class PullbackCloner::Implementation final return alloc; } + //--------------------------------------------------------------------------// + // Optional differentiation + //--------------------------------------------------------------------------// + + /// Given a `wrappedAdjoint` value of type `T.TangentVector`, creates an + /// `Optional.TangentVector` value from it and adds it to the adjoint value + /// of `optionalValue`. + /// + /// `wrappedAdjoint` may be an object or address value, both cases are + /// handled. + void accumulateAdjointForOptional(SILBasicBlock *bb, SILValue optionalValue, + SILValue wrappedAdjoint); + //--------------------------------------------------------------------------// // Array literal initialization differentiation //--------------------------------------------------------------------------// @@ -1503,6 +1516,30 @@ class PullbackCloner::Implementation final } } + /// Handle `unchecked_take_enum_data_addr` instruction. + /// Currently, only `Optional`-typed operands are supported. + /// Original: y = unchecked_take_enum_data_addr x : $*Enum, #Enum.Case + /// Adjoint: adj[x] += $Enum.TangentVector(adj[y]) + void + visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *utedai) { + auto *bb = utedai->getParent(); + auto adjBuf = getAdjointBuffer(bb, utedai); + auto enumTy = utedai->getOperand()->getType(); + auto *optionalEnumDecl = getASTContext().getOptionalDecl(); + // Only `Optional`-typed operands are supported for now. Diagnose all other + // enum operand types. + if (enumTy.getASTType().getEnumOrBoundGenericEnum() != optionalEnumDecl) { + LLVM_DEBUG(getADDebugStream() + << "Unhandled instruction in PullbackCloner: " << *utedai); + getContext().emitNondifferentiabilityError( + utedai, getInvoker(), + diag::autodiff_expression_not_differentiable_note); + errorOccurred = true; + return; + } + accumulateAdjointForOptional(bb, utedai->getOperand(), adjBuf); + } + #define NOT_DIFFERENTIABLE(INST, DIAG) void visit##INST##Inst(INST##Inst *inst); #undef NOT_DIFFERENTIABLE @@ -1639,11 +1676,16 @@ bool PullbackCloner::Implementation::run() { // Diagnose active enum values. Differentiation of enum values requires // special adjoint value handling and is not yet supported. Diagnose // only the first active enum value to prevent too many diagnostics. - if (type.getEnumOrBoundGenericEnum()) { - getContext().emitNondifferentiabilityError( - v, getInvoker(), diag::autodiff_enums_unsupported); - errorOccurred = true; - return true; + // + // Do not diagnose `Optional`-typed values, which will have special-case + // differentiation support. + if (auto *enumDecl = type.getEnumOrBoundGenericEnum()) { + if (enumDecl != getContext().getASTContext().getOptionalDecl()) { + getContext().emitNondifferentiabilityError( + v, getInvoker(), diag::autodiff_enums_unsupported); + errorOccurred = true; + return true; + } } // Diagnose unsupported stored property projections. if (auto *inst = dyn_cast(v)) { @@ -1972,6 +2014,103 @@ void PullbackCloner::Implementation::emitZeroDerivativesForNonvariedResult( << pullback); } +void PullbackCloner::Implementation::accumulateAdjointForOptional( + SILBasicBlock *bb, SILValue optionalValue, SILValue wrappedAdjoint) { + auto pbLoc = getPullback().getLocation(); + // Handle `switch_enum` on `Optional`. + auto *optionalEnumDecl = getASTContext().getOptionalDecl(); + auto optionalTy = optionalValue->getType(); + assert(optionalTy.getASTType().getEnumOrBoundGenericEnum() == + optionalEnumDecl); + // `Optional` + optionalTy = remapType(optionalTy); + // `T` + auto wrappedType = optionalTy.getOptionalObjectType(); + // `T.TangentVector` + auto wrappedTanType = remapType(wrappedAdjoint->getType()); + // `Optional` + auto optionalOfWrappedTanType = SILType::getOptionalType(wrappedTanType); + // `Optional.TangentVector` + auto optionalTanTy = getRemappedTangentType(optionalTy); + auto *optionalTanDecl = optionalTanTy.getNominalOrBoundGenericNominal(); + // Look up the `Optional.TangentVector.init` declaration. + auto initLookup = + optionalTanDecl->lookupDirect(DeclBaseName::createConstructor()); + ConstructorDecl *constructorDecl = nullptr; + for (auto *candidate : initLookup) { + auto candidateModule = candidate->getModuleContext(); + if (candidateModule->getName() == + builder.getASTContext().Id_Differentiation || + candidateModule->isStdlibModule()) { + assert(!constructorDecl && "Multiple `Optional.TangentVector.init`s"); + constructorDecl = cast(candidate); +#ifdef NDEBUG + break; +#endif + } + } + assert(constructorDecl && "No `Optional.TangentVector.init`"); + + // Allocate a local buffer for the `Optional` adjoint value. + auto *optTanAdjBuf = builder.createAllocStack(pbLoc, optionalTanTy); + // Find `Optional.some` EnumElementDecl. + auto someEltDecl = builder.getASTContext().getOptionalSomeDecl(); + + // Initialize an `Optional` buffer from `wrappedAdjoint` as + // the input for `Optional.TangentVector.init`. + auto *optArgBuf = builder.createAllocStack(pbLoc, optionalOfWrappedTanType); + if (optionalOfWrappedTanType.isLoadableOrOpaque(builder.getFunction())) { + // %enum = enum $Optional, #Optional.some!enumelt, + // %wrappedAdjoint : $T + auto *enumInst = builder.createEnum(pbLoc, wrappedAdjoint, someEltDecl, + optionalOfWrappedTanType); + // store %enum to %optArgBuf + builder.emitStoreValueOperation(pbLoc, enumInst, optArgBuf, + StoreOwnershipQualifier::Init); + } else { + // %enumAddr = init_enum_data_addr %optArgBuf $Optional, + // #Optional.some!enumelt + auto *enumAddr = builder.createInitEnumDataAddr( + pbLoc, optArgBuf, someEltDecl, wrappedTanType.getAddressType()); + // copy_addr %wrappedAdjoint to [initialization] %enumAddr + builder.createCopyAddr(pbLoc, wrappedAdjoint, enumAddr, IsNotTake, + IsInitialization); + // inject_enum_addr %optArgBuf : $*Optional, + // #Optional.some!enumelt + builder.createInjectEnumAddr(pbLoc, optArgBuf, someEltDecl); + } + + // Apply `Optional.TangentVector.init`. + SILOptFunctionBuilder fb(getContext().getTransform()); + // %init_fn = function_ref @Optional.TangentVector.init + auto *initFn = fb.getOrCreateFunction(pbLoc, SILDeclRef(constructorDecl), + NotForDefinition); + auto *initFnRef = builder.createFunctionRef(pbLoc, initFn); + auto *diffProto = + builder.getASTContext().getProtocol(KnownProtocolKind::Differentiable); + auto *swiftModule = getModule().getSwiftModule(); + auto diffConf = + swiftModule->lookupConformance(wrappedType.getASTType(), diffProto); + assert(!diffConf.isInvalid() && "Missing conformance to `Differentiable`"); + auto subMap = SubstitutionMap::get( + initFn->getLoweredFunctionType()->getSubstGenericSignature(), + ArrayRef(wrappedType.getASTType()), {diffConf}); + // %metatype = metatype $Optional.TangentVector.Type + auto metatypeType = CanMetatypeType::get(optionalTanTy.getASTType(), + MetatypeRepresentation::Thin); + auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType); + auto metatype = builder.createMetatype(pbLoc, metatypeSILType); + // apply %init_fn(%optTanAdjBuf, %optArgBuf, %metatype) + builder.createApply(pbLoc, initFnRef, subMap, + {optTanAdjBuf, optArgBuf, metatype}); + builder.createDeallocStack(pbLoc, optArgBuf); + + // Accumulate adjoint for the incoming `Optional` value. + addToAdjointBuffer(bb, optionalValue, optTanAdjBuf, pbLoc); + builder.emitDestroyAddr(pbLoc, optTanAdjBuf); + builder.createDeallocStack(pbLoc, optTanAdjBuf); +} + SILBasicBlock *PullbackCloner::Implementation::buildPullbackSuccessor( SILBasicBlock *origBB, SILBasicBlock *origPredBB, SmallDenseMap &pullbackTrampolineBlockMap) { @@ -2110,18 +2249,65 @@ void PullbackCloner::Implementation::visitSILBasicBlock(SILBasicBlock *bb) { // Get predecessor terminator operands. SmallVector, 4> incomingValues; bbArg->getSingleTerminatorOperands(incomingValues); - // Materialize adjoint value of active basic block argument, create a - // copy, and set copy as adjoint value of incoming values. - auto bbArgAdj = getAdjointValue(bb, bbArg); - auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc); - auto concreteBBArgAdjCopy = - builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj); - for (auto pair : incomingValues) { - auto *predBB = std::get<0>(pair); - auto incomingValue = std::get<1>(pair); - blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); - setAdjointValue(predBB, incomingValue, - makeConcreteAdjointValue(concreteBBArgAdjCopy)); + + // Returns true if the given terminator instruction is a `switch_enum` on + // an `Optional`-typed value. `switch_enum` instructions require + // special-case adjoint value propagation for the operand. + auto isSwitchEnumInstOnOptional = + [&ctx = getASTContext()](TermInst *termInst) { + if (!termInst) + return false; + if (auto *sei = dyn_cast(termInst)) { + auto *optionalEnumDecl = ctx.getOptionalDecl(); + auto operandTy = sei->getOperand()->getType(); + return operandTy.getASTType().getEnumOrBoundGenericEnum() == + optionalEnumDecl; + } + return false; + }; + + // Check the tangent value category of the active basic block argument. + switch (getTangentValueCategory(bbArg)) { + // If argument has a loadable tangent value category: materialize adjoint + // value of the argument, create a copy, and set the copy as the adjoint + // value of incoming values. + case SILValueCategory::Object: { + auto bbArgAdj = getAdjointValue(bb, bbArg); + auto concreteBBArgAdj = materializeAdjointDirect(bbArgAdj, pbLoc); + auto concreteBBArgAdjCopy = + builder.emitCopyValueOperation(pbLoc, concreteBBArgAdj); + for (auto pair : incomingValues) { + auto *predBB = std::get<0>(pair); + auto incomingValue = std::get<1>(pair); + // Handle `switch_enum` on `Optional`. + auto termInst = bbArg->getSingleTerminator(); + if (isSwitchEnumInstOnOptional(termInst)) { + accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); + } else { + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); + setAdjointValue(predBB, incomingValue, + makeConcreteAdjointValue(concreteBBArgAdjCopy)); + } + } + break; + } + // If argument has an address tangent value category: materialize adjoint + // value of the argument, create a copy, and set the copy as the adjoint + // value of incoming values. + case SILValueCategory::Address: { + auto bbArgAdjBuf = getAdjointBuffer(bb, bbArg); + for (auto pair : incomingValues) { + auto *predBB = std::get<0>(pair); + auto incomingValue = std::get<1>(pair); + // Handle `switch_enum` on `Optional`. + auto termInst = bbArg->getSingleTerminator(); + if (isSwitchEnumInstOnOptional(termInst)) + accumulateAdjointForOptional(bb, incomingValue, bbArgAdjBuf); + else + addToAdjointBuffer(predBB, incomingValue, bbArgAdjBuf, pbLoc); + } + break; + } } } @@ -2657,7 +2843,7 @@ void PullbackCloner::Implementation::accumulateIndirect(SILValue resultAddress, CanMetatypeType::get(adjointASTTy, MetatypeRepresentation::Thick); auto metatypeSILType = SILType::getPrimitiveObjectType(metatypeType); auto metatype = builder.createMetatype(loc, metatypeSILType); - // %2 = apply $0(%result, %new, %old, %1) + // %2 = apply %0(%result, %new, %old, %1) builder.createApply(loc, witnessMethod, subMap, {resultAddress, rhsAddress, lhsAddress, metatype}, /*isNonThrowing*/ false); diff --git a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp index b734d134cf29e..76a30bfaca3d2 100644 --- a/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp +++ b/lib/SILOptimizer/LoopTransforms/ArrayPropertyOpt.cpp @@ -519,13 +519,13 @@ class RegionCloner : public SILCloner { return; // Update SSA form. - SSAUp.Initialize(V->getType()); - SSAUp.AddAvailableValue(OrigBB, V); + SSAUp.initialize(V->getType()); + SSAUp.addAvailableValue(OrigBB, V); SILValue NewVal = getMappedValue(V); - SSAUp.AddAvailableValue(getOpBasicBlock(OrigBB), NewVal); + SSAUp.addAvailableValue(getOpBasicBlock(OrigBB), NewVal); for (auto U : UseList) { Operand *Use = U; - SSAUp.RewriteUse(*Use); + SSAUp.rewriteUse(*Use); } } diff --git a/lib/SILOptimizer/LoopTransforms/LICM.cpp b/lib/SILOptimizer/LoopTransforms/LICM.cpp index 79e5bd6d96b8e..e4be5ac35f5fa 100644 --- a/lib/SILOptimizer/LoopTransforms/LICM.cpp +++ b/lib/SILOptimizer/LoopTransforms/LICM.cpp @@ -1062,8 +1062,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins LLVM_DEBUG(llvm::dbgs() << "Creating preload " << *initialLoad); SILSSAUpdater ssaUpdater; - ssaUpdater.Initialize(initialLoad->getType()); - ssaUpdater.AddAvailableValue(preheader, initialLoad); + ssaUpdater.initialize(initialLoad->getType()); + ssaUpdater.addAvailableValue(preheader, initialLoad); // Set all stored values as available values in the ssaUpdater. // If there are multiple stores in a block, only the last one counts. @@ -1078,7 +1078,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins if (isLoadFromAddr(dyn_cast(SI->getSrc()), addr)) return; - ssaUpdater.AddAvailableValue(SI->getParent(), SI->getSrc()); + ssaUpdater.addAvailableValue(SI->getParent(), SI->getSrc()); } } @@ -1099,7 +1099,7 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins // If we didn't see a store in this block yet, get the current value from // the ssaUpdater. if (!currentVal) - currentVal = ssaUpdater.GetValueInMiddleOfBlock(block); + currentVal = ssaUpdater.getValueInMiddleOfBlock(block); SILValue projectedValue = projectLoadValue(LI->getOperand(), addr, currentVal, LI); LLVM_DEBUG(llvm::dbgs() << "Replacing stored load " << *LI << " with " @@ -1117,8 +1117,8 @@ void LoopTreeOptimization::hoistLoadsAndStores(SILValue addr, SILLoop *loop, Ins "should have split critical edges"); SILBuilder B(succ->begin()); auto *SI = B.createStore(loc.getValue(), - ssaUpdater.GetValueInMiddleOfBlock(succ), - addr, StoreOwnershipQualifier::Unqualified); + ssaUpdater.getValueInMiddleOfBlock(succ), addr, + StoreOwnershipQualifier::Unqualified); (void)SI; LLVM_DEBUG(llvm::dbgs() << "Creating loop-exit store " << *SI); } diff --git a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp index ea9521f061b2f..fff3b201dc415 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopRotate.cpp @@ -131,9 +131,9 @@ static void updateSSAForUseOfValue( assert(Res->getType() == MappedValue->getType() && "The types must match"); insertedPhis.clear(); - updater.Initialize(Res->getType()); - updater.AddAvailableValue(Header, Res); - updater.AddAvailableValue(EntryCheckBlock, MappedValue); + updater.initialize(Res->getType()); + updater.addAvailableValue(Header, Res); + updater.addAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another @@ -155,7 +155,7 @@ static void updateSSAForUseOfValue( assert(user->getParent() != EntryCheckBlock && "The entry check block should dominate the header"); - updater.RewriteUse(*use); + updater.rewriteUse(*use); } // Canonicalize inserted phis to avoid extra BB Args. for (SILPhiArgument *arg : insertedPhis) { diff --git a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp index 752e74ecc7001..967bfdbf4d468 100644 --- a/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp +++ b/lib/SILOptimizer/LoopTransforms/LoopUnroll.cpp @@ -334,13 +334,13 @@ updateSSA(SILModule &M, SILLoop *Loop, if (!Loop->contains(Use->getUser()->getParent())) UseList.push_back(UseWrapper(Use)); // Update SSA of use with the available values. - SSAUp.Initialize(OrigValue->getType()); - SSAUp.AddAvailableValue(OrigValue->getParentBlock(), OrigValue); + SSAUp.initialize(OrigValue->getType()); + SSAUp.addAvailableValue(OrigValue->getParentBlock(), OrigValue); for (auto NewValue : MapEntry.second) - SSAUp.AddAvailableValue(NewValue->getParentBlock(), NewValue); + SSAUp.addAvailableValue(NewValue->getParentBlock(), NewValue); for (auto U : UseList) { Operand *Use = U; - SSAUp.RewriteUse(*Use); + SSAUp.rewriteUse(*Use); } } } diff --git a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp index 093cb4482e6b1..ff14e4a0f05ea 100644 --- a/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp +++ b/lib/SILOptimizer/Mandatory/ClosureLifetimeFixup.cpp @@ -244,7 +244,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, // lifetime respecting loops. SmallVector insertedPhis; SILSSAUpdater updater(&insertedPhis); - updater.Initialize(optionalEscapingClosureTy); + updater.initialize(optionalEscapingClosureTy); // Create an Optional<() -> ()>.none in the entry block of the function and // add it as an available value to the SSAUpdater. @@ -256,7 +256,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, SILBuilderWithScope b(fn.getEntryBlock()->begin()); return b.createOptionalNone(loc, optionalEscapingClosureTy); }(); - updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); + updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); // Create a copy of the convert_escape_to_no_escape and add it as an available // value to the SSA updater. @@ -270,7 +270,7 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, cvt->setLifetimeGuaranteed(); cvt->setOperand(innerCVI); SILBuilderWithScope b(std::next(cvt->getIterator())); - updater.AddAvailableValue( + updater.addAvailableValue( cvt->getParent(), b.createOptionalSome(loc, innerCVI, optionalEscapingClosureTy)); return innerCVI; @@ -284,13 +284,13 @@ static void extendLifetimeToEndOfFunction(SILFunction &fn, { // Before the copy value, insert an extra destroy_value to handle // loops. Since we used our enum value this is safe. - SILValue v = updater.GetValueInMiddleOfBlock(cvi->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(cvi->getParent()); SILBuilderWithScope(cvi).createDestroyValue(loc, v); } for (auto *block : exitingBlocks) { auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block); - SILValue v = updater.GetValueAtEndOfBlock(block); + SILValue v = updater.getValueAtEndOfBlock(block); SILBuilderWithScope(safeDestructionPt).createDestroyValue(loc, v); } @@ -849,7 +849,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, SmallVector insertedPhis; SILSSAUpdater updater(&insertedPhis); - updater.Initialize(optionalEscapingClosureTy); + updater.initialize(optionalEscapingClosureTy); // Create the Optional.none as the beginning available value. SILValue entryBlockOptionalNone; @@ -857,7 +857,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, SILBuilderWithScope b(fn.getEntryBlock()->begin()); entryBlockOptionalNone = b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy); - updater.AddAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); + updater.addAvailableValue(fn.getEntryBlock(), entryBlockOptionalNone); } assert(entryBlockOptionalNone); @@ -872,7 +872,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, // operand consumed at +1, so we don't need a copy) to it. auto *result = b.createOptionalSome(autoGenLoc, sentinelClosure, optionalEscapingClosureTy); - updater.AddAvailableValue(result->getParent(), result); + updater.addAvailableValue(result->getParent(), result); return result; }(); @@ -881,14 +881,14 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, if (singleDestroy) { SILBuilderWithScope b(std::next(singleDestroy->getIterator())); auto *result = b.createOptionalNone(autoGenLoc, optionalEscapingClosureTy); - updater.AddAvailableValue(result->getParent(), result); + updater.addAvailableValue(result->getParent(), result); } // Now that we have all of our available values, insert a destroy_value before // the initial Optional.some value using the SSA updater to ensure that we // handle loops correctly. { - SILValue v = updater.GetValueInMiddleOfBlock(initialValue->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(initialValue->getParent()); SILBuilderWithScope(initialValue).createDestroyValue(autoGenLoc, v); } @@ -896,7 +896,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, // lifetime end points. This ensures we do not expand our lifetime too much. if (singleDestroy) { SILBuilderWithScope b(std::next(singleDestroy->getIterator())); - SILValue v = updater.GetValueInMiddleOfBlock(singleDestroy->getParent()); + SILValue v = updater.getValueInMiddleOfBlock(singleDestroy->getParent()); SILValue isEscaping = b.createIsEscapingClosure(loc, v, IsEscapingClosureInst::ObjCEscaping); b.createCondFail(loc, isEscaping, "non-escaping closure has escaped"); @@ -911,7 +911,7 @@ static bool fixupCopyBlockWithoutEscaping(CopyBlockWithoutEscapingInst *cb, for (auto *block : exitingBlocks) { auto *safeDestructionPt = getDeinitSafeClosureDestructionPoint(block); - SILValue v = updater.GetValueAtEndOfBlock(block); + SILValue v = updater.getValueAtEndOfBlock(block); SILBuilderWithScope(safeDestructionPt).createDestroyValue(autoGenLoc, v); } } diff --git a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp index 5d4d4f889cb6c..1b7a6c384fc80 100644 --- a/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp +++ b/lib/SILOptimizer/Mandatory/PredictableMemOpt.cpp @@ -686,7 +686,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, // have multiple insertion points if we are storing exactly the same value // implying that we can just copy firstVal at each insertion point. SILSSAUpdater updater(&insertedPhiNodes); - updater.Initialize(loadTy); + updater.initialize(loadTy); Optional singularValue; for (auto *insertPt : insertPts) { @@ -707,7 +707,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, } // And then put the value into the SSA updater. - updater.AddAvailableValue(insertPt->getParent(), eltVal); + updater.addAvailableValue(insertPt->getParent(), eltVal); } // If we only are tracking a singular value, we do not need to construct @@ -727,7 +727,7 @@ AvailableValueAggregator::aggregateFullyAvailableValue(SILType loadTy, } // Finally, grab the value from the SSA updater. - SILValue result = updater.GetValueInMiddleOfBlock(B.getInsertionBB()); + SILValue result = updater.getValueInMiddleOfBlock(B.getInsertionBB()); assert(result.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); if (isTake() || !B.hasOwnership()) { return result; @@ -863,7 +863,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, // never have the same value along all paths unless we have a trivial value // meaning the SSA updater given a non-trivial value must /always/ be used. SILSSAUpdater updater(&insertedPhiNodes); - updater.Initialize(loadTy); + updater.initialize(loadTy); Optional singularValue; for (auto *i : insertPts) { @@ -881,7 +881,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, singularValue = SILValue(); } - updater.AddAvailableValue(i->getParent(), eltVal); + updater.addAvailableValue(i->getParent(), eltVal); } SILBasicBlock *insertBlock = B.getInsertionBB(); @@ -902,7 +902,7 @@ SILValue AvailableValueAggregator::handlePrimitiveValue(SILType loadTy, } // Finally, grab the value from the SSA updater. - SILValue eltVal = updater.GetValueInMiddleOfBlock(insertBlock); + SILValue eltVal = updater.getValueInMiddleOfBlock(insertBlock); assert(!B.hasOwnership() || eltVal.getOwnershipKind().isCompatibleWith(ValueOwnershipKind::Owned)); assert(eltVal->getType() == loadTy && "Subelement types mismatch"); diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 9cde36a2239f4..6483b47a12a6f 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -12,6 +12,7 @@ #define DEBUG_TYPE "allocbox-to-stack" #include "swift/AST/DiagnosticsSIL.h" +#include "swift/Basic/BlotMapVector.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/Dominance.h" #include "swift/SIL/SILArgument.h" @@ -43,6 +44,10 @@ static llvm::cl::opt MaxLocalApplyRecurDepth( "max-local-apply-recur-depth", llvm::cl::init(4), llvm::cl::desc("Max recursive depth for analyzing local functions")); +static llvm::cl::opt AllocBoxToStackAnalyzeApply( + "allocbox-to-stack-analyze-apply", llvm::cl::init(true), + llvm::cl::desc("Analyze functions into while alloc_box is passed")); + //===-----------------------------------------------------------------------===// // SIL Utilities for alloc_box Promotion //===----------------------------------------------------------------------===// @@ -319,6 +324,10 @@ static bool checkLocalApplyBody(Operand *O, // AllocBoxToStack opt. We don't want to increase code size, so this is // restricted only for private local functions currently. static bool isOptimizableApplySite(ApplySite Apply) { + if (!AllocBoxToStackAnalyzeApply) { + // turned off explicitly + return false; + } auto callee = Apply.getReferencedFunctionOrNull(); if (!callee) { return false; @@ -978,8 +987,7 @@ specializeApplySite(SILOptFunctionBuilder &FuncBuilder, ApplySite Apply, } static void rewriteApplySites(AllocBoxToStackState &pass) { - llvm::DenseMap IndexMap; - llvm::SmallVector AppliesToSpecialize; + swift::SmallBlotMapVector AppliesToSpecialize; ArgIndexList Indices; // Build a map from the ApplySite to the indices of the operands @@ -993,17 +1001,26 @@ static void rewriteApplySites(AllocBoxToStackState &pass) { Indices.clear(); Indices.push_back(CalleeArgIndexNumber); - auto iterAndSuccess = IndexMap.try_emplace(Apply, Indices); // AllocBoxStack opt promotes boxes passed to a chain of applies when it is // safe to do so. All such applies have to be specialized to take pointer // arguments instead of box arguments. This has to be done in dfs order. - // Since PromotedOperands is already populated in dfs order by - // `recursivelyFindBoxOperandsPromotableToAddress`. Build - // `AppliesToSpecialize` in the same order. - if (iterAndSuccess.second) { - AppliesToSpecialize.push_back(Apply); - } else { - iterAndSuccess.first->second.push_back(CalleeArgIndexNumber); + + // PromotedOperands is already populated in dfs order by + // `recursivelyFindBoxOperandsPromotableToAddress` w.r.t a single alloc_box. + // AppliesToSpecialize is then populated in the order of PromotedOperands. + // If multiple alloc_boxes are passed to the same apply instruction, then + // the apply instruction can appear multiple times in AppliesToSpecialize. + // Only its last appearance is maintained and previous appearances are + // blotted. + auto iterAndSuccess = + AppliesToSpecialize.insert(std::make_pair(Apply, Indices)); + if (!iterAndSuccess.second) { + // Blot the previously inserted apply and insert at the end with updated + // indices + auto OldIndices = iterAndSuccess.first->getValue().second; + OldIndices.push_back(CalleeArgIndexNumber); + AppliesToSpecialize.erase(iterAndSuccess.first); + AppliesToSpecialize.insert(std::make_pair(Apply, OldIndices)); } } @@ -1011,11 +1028,12 @@ static void rewriteApplySites(AllocBoxToStackState &pass) { // operands that we will not need, and remove the existing // ApplySite. SILOptFunctionBuilder FuncBuilder(*pass.T); - for (auto &Apply : AppliesToSpecialize) { - auto It = IndexMap.find(Apply); - assert(It != IndexMap.end()); - auto &Indices = It->second; - + for (auto &It : AppliesToSpecialize) { + if (!It.hasValue()) { + continue; + } + auto Apply = It.getValue().first; + auto Indices = It.getValue().second; // Sort the indices and unique them. sortUnique(Indices); diff --git a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp index fff5fafdde1f7..a040d1166d176 100644 --- a/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadObjectElimination.cpp @@ -535,10 +535,10 @@ static void insertReleases(ArrayRef Stores, assert(!Stores.empty()); SILValue StVal = Stores.front()->getSrc(); - SSAUp.Initialize(StVal->getType()); + SSAUp.initialize(StVal->getType()); for (auto *Store : Stores) - SSAUp.AddAvailableValue(Store->getParent(), Store->getSrc()); + SSAUp.addAvailableValue(Store->getParent(), Store->getSrc()); SILLocation Loc = Stores[0]->getLoc(); for (auto *RelPoint : ReleasePoints) { @@ -547,7 +547,7 @@ static void insertReleases(ArrayRef Stores, // the right thing for local uses. We have already ensured a single store // per block, and all release points occur after all stores. Therefore we // can simply ask SSAUpdater for the reaching store. - SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent()); + SILValue RelVal = SSAUp.getValueAtEndOfBlock(RelPoint->getParent()); if (StVal->getType().isReferenceCounted(RelPoint->getModule())) B.createStrongRelease(Loc, RelVal, B.getDefaultAtomicity()); else diff --git a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp index 06968a86b32a5..373d62d92c976 100644 --- a/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp +++ b/lib/SILOptimizer/Transforms/RedundantLoadElimination.cpp @@ -1337,14 +1337,14 @@ SILValue RLEContext::computePredecessorLocationValue(SILBasicBlock *BB, // Finally, collect all the values for the SILArgument, materialize it using // the SSAUpdater. - Updater.Initialize( + Updater.initialize( L.getType(&BB->getModule(), TypeExpansionContext(*BB->getParent())) .getObjectType()); for (auto V : Values) { - Updater.AddAvailableValue(V.first, V.second); + Updater.addAvailableValue(V.first, V.second); } - return Updater.GetValueInMiddleOfBlock(BB); + return Updater.getValueInMiddleOfBlock(BB); } bool RLEContext::collectLocationValues(SILBasicBlock *BB, LSLocation &L, diff --git a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp index a70372768b507..6b5a52240da00 100644 --- a/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp +++ b/lib/SILOptimizer/Utils/BasicBlockOptUtils.cpp @@ -107,9 +107,9 @@ void BasicBlockCloner::updateSSAAfterCloning() { for (auto *use : inst->getUses()) useList.push_back(UseWrapper(use)); - ssaUpdater.Initialize(inst->getType()); - ssaUpdater.AddAvailableValue(origBB, inst); - ssaUpdater.AddAvailableValue(getNewBB(), newResult); + ssaUpdater.initialize(inst->getType()); + ssaUpdater.addAvailableValue(origBB, inst); + ssaUpdater.addAvailableValue(getNewBB(), newResult); if (useList.empty()) continue; @@ -124,7 +124,7 @@ void BasicBlockCloner::updateSSAAfterCloning() { if (user->getParent() == origBB) continue; - ssaUpdater.RewriteUse(*use); + ssaUpdater.rewriteUse(*use); } } } diff --git a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp index ba37d210559d3..92dec29e38461 100644 --- a/lib/SILOptimizer/Utils/SILSSAUpdater.cpp +++ b/lib/SILOptimizer/Utils/SILSSAUpdater.cpp @@ -25,71 +25,75 @@ using namespace swift; -void *SILSSAUpdater::allocate(unsigned Size, unsigned Align) const { - return AlignedAlloc(Size, Align); +void *SILSSAUpdater::allocate(unsigned size, unsigned align) const { + return AlignedAlloc(size, align); } -void SILSSAUpdater::deallocateSentinel(SILUndef *D) { - AlignedFree(D); +void SILSSAUpdater::deallocateSentinel(SILUndef *undef) { + AlignedFree(undef); } -SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *PHIs) - : AV(nullptr), PHISentinel(nullptr, deallocateSentinel), - InsertedPHIs(PHIs) {} +SILSSAUpdater::SILSSAUpdater(SmallVectorImpl *phis) + : blockToAvailableValueMap(nullptr), + phiSentinel(nullptr, deallocateSentinel), insertedPhis(phis) {} SILSSAUpdater::~SILSSAUpdater() = default; -void SILSSAUpdater::Initialize(SILType Ty) { - ValType = Ty; +void SILSSAUpdater::initialize(SILType inputType) { + type = inputType; - PHISentinel = std::unique_ptr( - SILUndef::getSentinelValue(Ty, this), SILSSAUpdater::deallocateSentinel); + phiSentinel = std::unique_ptr( + SILUndef::getSentinelValue(inputType, this), + SILSSAUpdater::deallocateSentinel); - if (!AV) - AV.reset(new AvailableValsTy()); + if (!blockToAvailableValueMap) + blockToAvailableValueMap.reset(new AvailableValsTy()); else - AV->clear(); + blockToAvailableValueMap->clear(); } -bool SILSSAUpdater::HasValueForBlock(SILBasicBlock *BB) const { - return AV->count(BB); +bool SILSSAUpdater::hasValueForBlock(SILBasicBlock *block) const { + return blockToAvailableValueMap->count(block); } /// Indicate that a rewritten value is available in the specified block with the /// specified value. -void SILSSAUpdater::AddAvailableValue(SILBasicBlock *BB, SILValue V) { - (*AV)[BB] = V; +void SILSSAUpdater::addAvailableValue(SILBasicBlock *block, SILValue value) { + (*blockToAvailableValueMap)[block] = value; } /// Construct SSA form, materializing a value that is live at the end of the /// specified block. -SILValue SILSSAUpdater::GetValueAtEndOfBlock(SILBasicBlock *BB) { - return GetValueAtEndOfBlockInternal(BB); +SILValue SILSSAUpdater::getValueAtEndOfBlock(SILBasicBlock *block) { + return getValueAtEndOfBlockInternal(block); } /// Are all available values identicalTo each other. -static bool areIdentical(llvm::DenseMap &Avails) { - if (auto *First = dyn_cast(Avails.begin()->second)) { - for (auto Avail : Avails) { - auto *Inst = dyn_cast(Avail.second); - if (!Inst) +static bool +areIdentical(llvm::DenseMap &availableValues) { + if (auto *firstInst = + dyn_cast(availableValues.begin()->second)) { + for (auto value : availableValues) { + auto *svi = dyn_cast(value.second); + if (!svi) return false; - if (!Inst->isIdenticalTo(First)) + if (!svi->isIdenticalTo(firstInst)) return false; } return true; } - auto *MVIR = dyn_cast(Avails.begin()->second); - if (!MVIR) + auto *mvir = + dyn_cast(availableValues.begin()->second); + if (!mvir) return false; - for (auto Avail : Avails) { - auto *Result = dyn_cast(Avail.second); - if (!Result) + for (auto value : availableValues) { + auto *result = dyn_cast(value.second); + if (!result) return false; - if (!Result->getParent()->isIdenticalTo(MVIR->getParent()) || - Result->getIndex() != MVIR->getIndex()) { + if (!result->getParent()->isIdenticalTo(mvir->getParent()) || + result->getIndex() != mvir->getIndex()) { return false; } } @@ -98,65 +102,61 @@ static bool areIdentical(llvm::DenseMap &Avails) { /// This should be called in top-down order of each def that needs its uses /// rewrited. The order that we visit uses for a given def is irrelevant. -void SILSSAUpdater::RewriteUse(Operand &Op) { +void SILSSAUpdater::rewriteUse(Operand &use) { // Replicate function_refs to their uses. SILGen can't build phi nodes for // them and it would not make much sense anyways. - if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + if (auto *fri = dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(fri->clone(user))); return; - } else if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + } else if (auto *pdfri = + dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(pdfri->clone(user))); return; - } else if (auto *FR = dyn_cast(Op.get())) { - assert(areIdentical(*AV) && + } else if (auto *dfri = dyn_cast(use.get())) { + assert(areIdentical(*blockToAvailableValueMap) && "The function_refs need to have the same value"); - SILInstruction *User = Op.getUser(); - auto *NewFR = cast(FR->clone(User)); - Op.set(NewFR); + SILInstruction *user = use.getUser(); + use.set(cast(dfri->clone(user))); return; - } else if (auto *IL = dyn_cast(Op.get())) - if (areIdentical(*AV)) { + } else if (auto *ili = dyn_cast(use.get())) + if (areIdentical(*blockToAvailableValueMap)) { // Some llvm intrinsics don't like phi nodes as their constant inputs (e.g // ctlz). - SILInstruction *User = Op.getUser(); - auto *NewIL = cast(IL->clone(User)); - Op.set(NewIL); + SILInstruction *user = use.getUser(); + use.set(cast(ili->clone(user))); return; } // Again we need to be careful here, because ssa construction (with the // existing representation) can change the operand from under us. - UseWrapper UW(&Op); + UseWrapper useWrapper(&use); - SILInstruction *User = Op.getUser(); - SILValue NewVal = GetValueInMiddleOfBlock(User->getParent()); - assert(NewVal && "Need a valid value"); - ((Operand *)UW)->set((SILValue)NewVal); + SILInstruction *user = use.getUser(); + SILValue newVal = getValueInMiddleOfBlock(user->getParent()); + assert(newVal && "Need a valid value"); + static_cast(useWrapper)->set(newVal); } - /// Get the edge values from the terminator to the destination basic block. -static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI, - SILBasicBlock *ToBB) { - if (auto *BrInst = dyn_cast(TI)) { - assert(BrInst->getDestBB() == ToBB && +static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *ti, + SILBasicBlock *toBlock) { + if (auto *br = dyn_cast(ti)) { + assert(br->getDestBB() == toBlock && "Incoming edge block and phi block mismatch"); - return BrInst->getArgs(); + return br->getArgs(); } - if (auto *CondBrInst = dyn_cast(TI)) { - bool IsTrueEdge = CondBrInst->getTrueBB() == ToBB; - assert(((IsTrueEdge && CondBrInst->getTrueBB() == ToBB) || - CondBrInst->getFalseBB() == ToBB) && + if (auto *cbi = dyn_cast(ti)) { + bool isTrueEdge = cbi->getTrueBB() == toBlock; + assert(((isTrueEdge && cbi->getTrueBB() == toBlock) || + cbi->getFalseBB() == toBlock) && "Incoming edge block and phi block mismatch"); - return IsTrueEdge ? CondBrInst->getTrueArgs() : CondBrInst->getFalseArgs(); + return isTrueEdge ? cbi->getTrueArgs() : cbi->getFalseArgs(); } // We need a predecessor who is capable of holding outgoing branch @@ -167,211 +167,219 @@ static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *TI, /// Check that the argument has the same incoming edge values as the value /// map. static bool -isEquivalentPHI(SILPhiArgument *PHI, - llvm::SmallDenseMap &ValueMap) { - SILBasicBlock *PhiBB = PHI->getParent(); - size_t Idx = PHI->getIndex(); - for (auto *PredBB : PhiBB->getPredecessorBlocks()) { - auto DesiredVal = ValueMap[PredBB]; - OperandValueArrayRef EdgeValues = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - if (EdgeValues[Idx] != DesiredVal) +isEquivalentPHI(SILPhiArgument *phi, + llvm::SmallDenseMap &valueMap) { + SILBasicBlock *phiBlock = phi->getParent(); + size_t phiArgEdgeIndex = phi->getIndex(); + for (auto *predBlock : phiBlock->getPredecessorBlocks()) { + auto desiredVal = valueMap[predBlock]; + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + if (edgeValues[phiArgEdgeIndex] != desiredVal) return false; } return true; } -SILValue SILSSAUpdater::GetValueInMiddleOfBlock(SILBasicBlock *BB) { +SILValue SILSSAUpdater::getValueInMiddleOfBlock(SILBasicBlock *block) { // If this basic block does not define a value we can just use the value // live at the end of the block. - if (!HasValueForBlock(BB)) - return GetValueAtEndOfBlock(BB); + if (!hasValueForBlock(block)) + return getValueAtEndOfBlock(block); /// Otherwise, we have to build SSA for the value defined in this block and /// this block's predecessors. - SILValue SingularValue; - SmallVector, 4> PredVals; - bool FirstPred = true; + SILValue singularValue; + SmallVector, 4> predVals; + bool firstPred = true; // SSAUpdater can modify TerminatorInst and therefore invalidate the // predecessor iterator. Find all the predecessors before the SSA update. - SmallVector Preds; - for (auto *PredBB : BB->getPredecessorBlocks()) { - Preds.push_back(PredBB); + SmallVector preds; + for (auto *predBlock : block->getPredecessorBlocks()) { + preds.push_back(predBlock); } - for (auto *PredBB : Preds) { - SILValue PredVal = GetValueAtEndOfBlock(PredBB); - PredVals.push_back(std::make_pair(PredBB, PredVal)); - if (FirstPred) { - SingularValue = PredVal; - FirstPred = false; - } else if (SingularValue != PredVal) - SingularValue = SILValue(); + for (auto *predBlock : preds) { + SILValue predVal = getValueAtEndOfBlock(predBlock); + predVals.push_back(std::make_pair(predBlock, predVal)); + if (firstPred) { + singularValue = predVal; + firstPred = false; + } else if (singularValue != predVal) + singularValue = SILValue(); } // Return undef for blocks without predecessor. - if (PredVals.empty()) - return SILUndef::get(ValType, *BB->getParent()); + if (predVals.empty()) + return SILUndef::get(type, *block->getParent()); - if (SingularValue) - return SingularValue; + if (singularValue) + return singularValue; // Check if we already have an equivalent phi. - if (!BB->getArguments().empty()) { - llvm::SmallDenseMap ValueMap(PredVals.begin(), - PredVals.end()); - for (auto *Arg : BB->getSILPhiArguments()) - if (isEquivalentPHI(Arg, ValueMap)) - return Arg; - + if (!block->getArguments().empty()) { + llvm::SmallDenseMap valueMap(predVals.begin(), + predVals.end()); + for (auto *arg : block->getSILPhiArguments()) + if (isEquivalentPHI(arg, valueMap)) + return arg; } // Create a new phi node. - SILPhiArgument *PHI = - BB->createPhiArgument(ValType, ValueOwnershipKind::Owned); - for (auto &EV : PredVals) - addNewEdgeValueToBranch(EV.first->getTerminator(), BB, EV.second); + SILPhiArgument *phiArg = + block->createPhiArgument(type, ValueOwnershipKind::Owned); + for (auto &pair : predVals) + addNewEdgeValueToBranch(pair.first->getTerminator(), block, pair.second); - if (InsertedPHIs) - InsertedPHIs->push_back(PHI); + if (insertedPhis) + insertedPhis->push_back(phiArg); - return PHI; + return phiArg; } -/// SSAUpdaterTraits - Traits for the SSAUpdaterImpl -/// template, specialized for MachineSSAUpdater. namespace llvm { -template<> + +/// Traits for the SSAUpdaterImpl specialized for SIL and the SILSSAUpdater. +template <> class SSAUpdaterTraits { public: - typedef SILBasicBlock BlkT; - typedef SILValue ValT; - typedef SILPhiArgument PhiT; + using BlkT = SILBasicBlock; + using ValT = SILValue; + using PhiT = SILPhiArgument; - typedef SILBasicBlock::succ_iterator BlkSucc_iterator; - static BlkSucc_iterator BlkSucc_begin(BlkT *BB) { return BB->succ_begin(); } - static BlkSucc_iterator BlkSucc_end(BlkT *BB) { return BB->succ_end(); } + using BlkSucc_iterator = SILBasicBlock::succ_iterator; + static BlkSucc_iterator BlkSucc_begin(BlkT *block) { + return block->succ_begin(); + } + static BlkSucc_iterator BlkSucc_end(BlkT *block) { return block->succ_end(); } /// Iterator for PHI operands. class PHI_iterator { private: - SILBasicBlock::pred_iterator PredIt; - SILBasicBlock *BB; - size_t Idx; + SILBasicBlock::pred_iterator predBlockIter; + SILBasicBlock *phiBlock; + size_t phiArgEdgeIndex; public: - explicit PHI_iterator(SILPhiArgument *P) // begin iterator - : PredIt(P->getParent()->pred_begin()), - BB(P->getParent()), - Idx(P->getIndex()) {} - PHI_iterator(SILPhiArgument *P, bool) // end iterator - : PredIt(P->getParent()->pred_end()), - BB(P->getParent()), - Idx(P->getIndex()) {} - - PHI_iterator &operator++() { ++PredIt; return *this; } - bool operator==(const PHI_iterator& x) const { return PredIt == x.PredIt; } + explicit PHI_iterator(SILPhiArgument *phiArg) // begin iterator + : predBlockIter(phiArg->getParent()->pred_begin()), + phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {} + PHI_iterator(SILPhiArgument *phiArg, bool) // end iterator + : predBlockIter(phiArg->getParent()->pred_end()), + phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {} + + PHI_iterator &operator++() { + ++predBlockIter; + return *this; + } + + bool operator==(const PHI_iterator &x) const { + return predBlockIter == x.predBlockIter; + } + bool operator!=(const PHI_iterator& x) const { return !operator==(x); } - SILValue getValueForBlock(size_t Idx, SILBasicBlock *BB, TermInst *TI) { - OperandValueArrayRef Args = getEdgeValuesForTerminator(TI, BB); - assert(Idx < Args.size() && "Not enough values on incoming edge"); - return Args[Idx]; + SILValue getValueForBlock(size_t inputArgIndex, SILBasicBlock *block, + TermInst *ti) { + OperandValueArrayRef args = getEdgeValuesForTerminator(ti, block); + assert(inputArgIndex < args.size() && + "Not enough values on incoming edge"); + return args[inputArgIndex]; } SILValue getIncomingValue() { - return getValueForBlock(Idx, BB, (*PredIt)->getTerminator()); + return getValueForBlock(phiArgEdgeIndex, phiBlock, + (*predBlockIter)->getTerminator()); } - SILBasicBlock *getIncomingBlock() { - return *PredIt; - } + SILBasicBlock *getIncomingBlock() { return *predBlockIter; } }; - static inline PHI_iterator PHI_begin(PhiT *PHI) { return PHI_iterator(PHI); } - static inline PHI_iterator PHI_end(PhiT *PHI) { - return PHI_iterator(PHI, true); + static inline PHI_iterator PHI_begin(PhiT *phi) { return PHI_iterator(phi); } + static inline PHI_iterator PHI_end(PhiT *phi) { + return PHI_iterator(phi, true); } /// Put the predecessors of BB into the Preds vector. - static void FindPredecessorBlocks(SILBasicBlock *BB, - SmallVectorImpl *Preds){ - for (SILBasicBlock::pred_iterator PI = BB->pred_begin(), E = BB->pred_end(); - PI != E; ++PI) - Preds->push_back(*PI); + static void + FindPredecessorBlocks(SILBasicBlock *block, + SmallVectorImpl *predBlocks) { + llvm::copy(block->getPredecessorBlocks(), std::back_inserter(*predBlocks)); } - static SILValue GetUndefVal(SILBasicBlock *BB, - SILSSAUpdater *Updater) { - return SILUndef::get(Updater->ValType, *BB->getParent()); + static SILValue GetUndefVal(SILBasicBlock *block, SILSSAUpdater *ssaUpdater) { + return SILUndef::get(ssaUpdater->type, *block->getParent()); } /// Add an Argument to the basic block. - static SILValue CreateEmptyPHI(SILBasicBlock *BB, unsigned NumPreds, - SILSSAUpdater *Updater) { + static SILValue CreateEmptyPHI(SILBasicBlock *block, unsigned numPreds, + SILSSAUpdater *ssaUpdater) { // Add the argument to the block. - SILValue PHI( - BB->createPhiArgument(Updater->ValType, ValueOwnershipKind::Owned)); + SILValue phi( + block->createPhiArgument(ssaUpdater->type, ValueOwnershipKind::Owned)); // Mark all predecessor blocks with the sentinel undef value. - SmallVector Preds(BB->pred_begin(), BB->pred_end()); - for (auto *PredBB: Preds) { - TermInst *TI = PredBB->getTerminator(); - addNewEdgeValueToBranch(TI, BB, Updater->PHISentinel.get()); + SmallVector predBlockList( + block->getPredecessorBlocks()); + + for (auto *predBlock : predBlockList) { + TermInst *ti = predBlock->getTerminator(); + addNewEdgeValueToBranch(ti, block, ssaUpdater->phiSentinel.get()); } - return PHI; + + return phi; } - /// Add the specified value as an operand of the PHI for the specified - /// predecessor block. - static void AddPHIOperand(SILPhiArgument *PHI, SILValue Val, - SILBasicBlock *Pred) { - auto *PHIBB = PHI->getParent(); - size_t PhiIdx = PHI->getIndex(); - auto *TI = Pred->getTerminator(); - changeEdgeValue(TI, PHIBB, PhiIdx, Val); + /// Add \p value as an operand of the phi argument \p phi for the specified + /// predecessor block \p predBlock. + static void AddPHIOperand(SILPhiArgument *phi, SILValue value, + SILBasicBlock *predBlock) { + auto *phiBlock = phi->getParent(); + size_t phiArgIndex = phi->getIndex(); + auto *ti = predBlock->getTerminator(); + changeEdgeValue(ti, phiBlock, phiArgIndex, value); } - /// InstrIsPHI - Check if an instruction is a PHI. - /// - static SILPhiArgument *InstrIsPHI(ValueBase *I) { - auto *Res = dyn_cast(I); - return Res; + /// Check if an instruction is a PHI. + static SILPhiArgument *InstrIsPHI(ValueBase *valueBase) { + return dyn_cast(valueBase); } - /// ValueIsPHI - Check if the instruction that defines the specified register - /// is a PHI instruction. - static SILPhiArgument *ValueIsPHI(SILValue V, SILSSAUpdater *Updater) { - return InstrIsPHI(V); + /// Check if the instruction that defines the specified SILValue is a PHI + /// instruction. + static SILPhiArgument *ValueIsPHI(SILValue value, SILSSAUpdater *) { + return InstrIsPHI(value); } /// Like ValueIsPHI but also check if the PHI has no source /// operands, i.e., it was just added. - static SILPhiArgument *ValueIsNewPHI(SILValue Val, SILSSAUpdater *Updater) { - SILPhiArgument *PHI = ValueIsPHI(Val, Updater); - if (PHI) { - auto *PhiBB = PHI->getParent(); - size_t PhiIdx = PHI->getIndex(); - - // If all predecessor edges are 'not set' this is a new phi. - for (auto *PredBB : PhiBB->getPredecessorBlocks()) { - OperandValueArrayRef Edges = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - - assert(PhiIdx < Edges.size() && "Not enough edges!"); - - SILValue V = Edges[PhiIdx]; - // Check for the 'not set' sentinel. - if (V != Updater->PHISentinel.get()) - return nullptr; - } - return PHI; + static SILPhiArgument *ValueIsNewPHI(SILValue value, + SILSSAUpdater *ssaUpdater) { + SILPhiArgument *phiArg = ValueIsPHI(value, ssaUpdater); + if (!phiArg) { + return nullptr; } - return nullptr; + + auto *phiBlock = phiArg->getParent(); + size_t phiArgEdgeIndex = phiArg->getIndex(); + + // If all predecessor edges are 'not set' this is a new phi. + for (auto *predBlock : phiBlock->getPredecessorBlocks()) { + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + + assert(phiArgEdgeIndex < edgeValues.size() && "Not enough edges!"); + + SILValue edgeValue = edgeValues[phiArgEdgeIndex]; + // Check for the 'not set' sentinel. + if (edgeValue != ssaUpdater->phiSentinel.get()) + return nullptr; + } + return phiArg; } - static SILValue GetPHIValue(SILPhiArgument *PHI) { return PHI; } + static SILValue GetPHIValue(SILPhiArgument *phi) { return phi; } }; } // namespace llvm @@ -379,14 +387,15 @@ class SSAUpdaterTraits { /// Check to see if AvailableVals has an entry for the specified BB and if so, /// return it. If not, construct SSA form by first calculating the required /// placement of PHIs and then inserting new PHIs where needed. -SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){ - AvailableValsTy &AvailableVals = *AV; - auto AI = AvailableVals.find(BB); - if (AI != AvailableVals.end()) - return AI->second; - - llvm::SSAUpdaterImpl Impl(this, &AvailableVals, InsertedPHIs); - return Impl.GetValue(BB); +SILValue SILSSAUpdater::getValueAtEndOfBlockInternal(SILBasicBlock *block) { + AvailableValsTy &availableValues = *blockToAvailableValueMap; + auto iter = availableValues.find(block); + if (iter != availableValues.end()) + return iter->second; + + llvm::SSAUpdaterImpl impl(this, &availableValues, + insertedPhis); + return impl.GetValue(block); } /// Construct a use wrapper. For branches we store information so that we @@ -395,67 +404,70 @@ SILValue SILSSAUpdater::GetValueAtEndOfBlockInternal(SILBasicBlock *BB){ /// When a branch is modified existing pointers to the operand /// (ValueUseIterator) become invalid as they point to freed operands. Instead /// we store the branch's parent and the idx so that we can reconstruct the use. -UseWrapper::UseWrapper(Operand *Use) { - U = nullptr; - Type = kRegularUse; +UseWrapper::UseWrapper(Operand *inputUse) { + wrappedUse = nullptr; + type = kRegularUse; - SILInstruction *User = Use->getUser(); + SILInstruction *user = inputUse->getUser(); // Direct branch user. - if (auto *Br = dyn_cast(User)) { - auto Opds = User->getAllOperands(); - for (unsigned i = 0, e = Opds.size(); i != e; ++i) { - if (Use == &Opds[i]) { - Idx = i; - Type = kBranchUse; - Parent = Br->getParent(); + if (auto *br = dyn_cast(user)) { + for (auto pair : llvm::enumerate(user->getAllOperands())) { + if (inputUse == &pair.value()) { + index = pair.index(); + type = kBranchUse; + parent = br->getParent(); return; } } } // Conditional branch user. - if (auto *Br = dyn_cast(User)) { - auto Opds = User->getAllOperands(); - auto NumTrueArgs = Br->getTrueArgs().size(); - for (unsigned i = 0, e = Opds.size(); i != e; ++i) { - if (Use == &Opds[i]) { + if (auto *cbi = dyn_cast(user)) { + auto operands = user->getAllOperands(); + auto numTrueArgs = cbi->getTrueArgs().size(); + for (auto pair : llvm::enumerate(operands)) { + if (inputUse == &pair.value()) { + unsigned i = pair.index(); // We treat the condition as part of the true args. - if (i < NumTrueArgs + 1) { - Idx = i; - Type = kCondBranchUseTrue; + if (i < numTrueArgs + 1) { + index = i; + type = kCondBranchUseTrue; } else { - Idx = i - NumTrueArgs - 1; - Type = kCondBranchUseFalse; + index = i - numTrueArgs - 1; + type = kCondBranchUseFalse; } - Parent = Br->getParent(); + parent = cbi->getParent(); return; } } } - U = Use; + wrappedUse = inputUse; } /// Return the operand we wrap. Reconstructing branch operands. Operand *UseWrapper::getOperand() { - switch (Type) { + switch (type) { case kRegularUse: - return U; + return wrappedUse; case kBranchUse: { - auto *Br = cast(Parent->getTerminator()); - assert(Idx < Br->getNumArgs()); - return &Br->getAllOperands()[Idx]; + auto *br = cast(parent->getTerminator()); + assert(index < br->getNumArgs()); + return &br->getAllOperands()[index]; } case kCondBranchUseTrue: case kCondBranchUseFalse: { - auto *Br = cast(Parent->getTerminator()); - unsigned IdxToUse = - Type == kCondBranchUseTrue ? Idx : Br->getTrueArgs().size() + 1 + Idx; - assert(IdxToUse < Br->getAllOperands().size()); - return &Br->getAllOperands()[IdxToUse]; + auto *cbi = cast(parent->getTerminator()); + auto indexToUse = [&]() -> unsigned { + if (type == kCondBranchUseTrue) + return index; + return cbi->getTrueArgs().size() + 1 + index; + }(); + assert(indexToUse < cbi->getAllOperands().size()); + return &cbi->getAllOperands()[indexToUse]; } } @@ -470,12 +482,12 @@ Operand *UseWrapper::getOperand() { /// ArgValues are the values feeding the specified Argument from each /// predecessor. They must be listed in order of Arg->getParent()->getPreds(). static StructInst * -replaceBBArgWithStruct(SILPhiArgument *Arg, - SmallVectorImpl &ArgValues) { +replaceBBArgWithStruct(SILPhiArgument *phiArg, + SmallVectorImpl &argValues) { - SILBasicBlock *PhiBB = Arg->getParent(); - auto *FirstSI = dyn_cast(ArgValues[0]); - if (!FirstSI) + SILBasicBlock *phiBlock = phiArg->getParent(); + auto *firstSI = dyn_cast(argValues[0]); + if (!firstSI) return nullptr; // Collect the BBArg index of each struct oper. @@ -483,42 +495,45 @@ replaceBBArgWithStruct(SILPhiArgument *Arg, // struct(A, B) // br (B, A) // : ArgIdxForOper => {1, 0} - SmallVector ArgIdxForOper; - for (unsigned OperIdx : indices(FirstSI->getElements())) { - bool FoundMatchingArgIdx = false; - for (unsigned ArgIdx : indices(PhiBB->getArguments())) { - SmallVectorImpl::const_iterator AVIter = ArgValues.begin(); - bool TryNextArgIdx = false; - for (SILBasicBlock *PredBB : PhiBB->getPredecessorBlocks()) { + SmallVector argIdxForOper; + for (unsigned operIdx : indices(firstSI->getElements())) { + bool foundMatchingArgIdx = false; + for (unsigned argIdx : indices(phiBlock->getArguments())) { + auto avIter = argValues.begin(); + bool tryNextArgIdx = false; + for (SILBasicBlock *predBlock : phiBlock->getPredecessorBlocks()) { // All argument values must be StructInst. - auto *PredSI = dyn_cast(*AVIter++); - if (!PredSI) + auto *predSI = dyn_cast(*avIter++); + if (!predSI) return nullptr; - OperandValueArrayRef EdgeValues = - getEdgeValuesForTerminator(PredBB->getTerminator(), PhiBB); - if (EdgeValues[ArgIdx] != PredSI->getElements()[OperIdx]) { - TryNextArgIdx = true; + OperandValueArrayRef edgeValues = + getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock); + if (edgeValues[argIdx] != predSI->getElements()[operIdx]) { + tryNextArgIdx = true; break; } } - if (!TryNextArgIdx) { - assert(AVIter == ArgValues.end() && "# ArgValues does not match # BB preds"); - FoundMatchingArgIdx = true; - ArgIdxForOper.push_back(ArgIdx); + if (!tryNextArgIdx) { + assert(avIter == argValues.end() && + "# ArgValues does not match # BB preds"); + foundMatchingArgIdx = true; + argIdxForOper.push_back(argIdx); break; } } - if (!FoundMatchingArgIdx) + if (!foundMatchingArgIdx) return nullptr; } - SmallVector StructArgs; - for (auto ArgIdx : ArgIdxForOper) - StructArgs.push_back(PhiBB->getArgument(ArgIdx)); + SmallVector structArgs; + for (auto argIdx : argIdxForOper) + structArgs.push_back(phiBlock->getArgument(argIdx)); - SILBuilder Builder(PhiBB, PhiBB->begin()); - return Builder.createStruct(cast(ArgValues[0])->getLoc(), - Arg->getType(), StructArgs); + // TODO: We probably want to use a SILBuilderWithScope here. What should we + // use? + SILBuilder builder(phiBlock, phiBlock->begin()); + return builder.createStruct(cast(argValues[0])->getLoc(), + phiArg->getType(), structArgs); } /// Canonicalize BB arguments, replacing argument-of-casts with @@ -527,10 +542,10 @@ replaceBBArgWithStruct(SILPhiArgument *Arg, /// detection like induction variable analysis to succeed. /// /// If Arg is replaced, return the cast instruction. Otherwise return nullptr. -SILValue swift::replaceBBArgWithCast(SILPhiArgument *Arg) { - SmallVector ArgValues; - Arg->getIncomingPhiValues(ArgValues); - if (isa(ArgValues[0])) - return replaceBBArgWithStruct(Arg, ArgValues); +SILValue swift::replaceBBArgWithCast(SILPhiArgument *arg) { + SmallVector argValues; + arg->getIncomingPhiValues(argValues); + if (isa(argValues[0])) + return replaceBBArgWithStruct(arg, argValues); return nullptr; } diff --git a/lib/SILOptimizer/Utils/SpecializationMangler.cpp b/lib/SILOptimizer/Utils/SpecializationMangler.cpp index 9807b43eb5f6d..3a37e3f3430ba 100644 --- a/lib/SILOptimizer/Utils/SpecializationMangler.cpp +++ b/lib/SILOptimizer/Utils/SpecializationMangler.cpp @@ -243,7 +243,6 @@ FunctionSignatureSpecializationMangler::mangleConstantProp(LiteralInst *LI) { switch (SLI->getEncoding()) { case StringLiteralInst::Encoding::Bytes: ArgOpBuffer << 'B'; break; case StringLiteralInst::Encoding::UTF8: ArgOpBuffer << 'b'; break; - case StringLiteralInst::Encoding::UTF16: ArgOpBuffer << 'w'; break; case StringLiteralInst::Encoding::ObjCSelector: ArgOpBuffer << 'c'; break; } break; diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 887ece0e2a85c..3beec6900ad47 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -59,7 +59,7 @@ add_swift_host_library(swiftSema STATIC TypeCheckDeclObjC.cpp TypeCheckDeclOverride.cpp TypeCheckDeclPrimary.cpp - TypeCheckError.cpp + TypeCheckEffects.cpp TypeCheckExpr.cpp TypeCheckExprObjC.cpp TypeCheckGeneric.cpp diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index ab6e244606004..96cf2965568c7 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -237,6 +237,9 @@ static bool buildObjCKeyPathString(KeyPathExpr *E, // Don't bother building the key path string if the key path didn't even // resolve. return false; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath expressions."); + return false; } } @@ -2696,7 +2699,7 @@ namespace { // then we're in an ambiguity tolerant mode used for diagnostic // generation. Just leave this as an unresolved member reference. Type resultTy = simplifyType(cs.getType(expr)); - if (resultTy->getRValueType()->is()) { + if (resultTy->hasUnresolvedType()) { cs.setType(expr, resultTy); return expr; } @@ -4700,6 +4703,10 @@ namespace { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::TupleElement: llvm_unreachable("already resolved"); + break; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } // Update "componentTy" with the result type of the last component. @@ -5472,124 +5479,6 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee, return false; } -/// Attach a Fix-It to the given diagnostic to give the trailing closure -/// argument a label. -static void labelTrailingClosureArgument( - ASTContext &ctx, Expr *fn, Expr *arg, Identifier paramName, - Expr *trailingClosure, InFlightDiagnostic &diag) { - // Dig out source locations. - SourceLoc existingRParenLoc; - SourceLoc leadingCommaLoc; - if (auto tupleExpr = dyn_cast(arg)) { - existingRParenLoc = tupleExpr->getRParenLoc(); - assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?"); - leadingCommaLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, - tupleExpr->getElements()[tupleExpr->getNumElements()-2]->getEndLoc()); - } else { - auto parenExpr = cast(arg); - existingRParenLoc = parenExpr->getRParenLoc(); - } - - // Figure out the text to be inserted before the trailing closure. - SmallString<16> insertionText; - SourceLoc insertionLoc; - if (leadingCommaLoc.isValid()) { - insertionText += ", "; - assert(existingRParenLoc.isValid()); - insertionLoc = leadingCommaLoc; - } else if (existingRParenLoc.isInvalid()) { - insertionText += "("; - insertionLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, fn->getEndLoc()); - } else { - insertionLoc = existingRParenLoc; - } - - // Add the label, if there is one. - if (!paramName.empty()) { - insertionText += paramName.str(); - insertionText += ": "; - } - - // If there is an existing right parentheses, remove it while we - // insert the new text. - if (existingRParenLoc.isValid()) { - SourceLoc afterExistingRParenLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, existingRParenLoc); - diag.fixItReplaceChars( - insertionLoc, afterExistingRParenLoc, insertionText); - } else { - // Insert the appropriate prefix. - diag.fixItInsert(insertionLoc, insertionText); - } - - // Insert a right parenthesis after the closing '}' of the trailing closure; - SourceLoc newRParenLoc = Lexer::getLocForEndOfToken( - ctx.SourceMgr, trailingClosure->getEndLoc()); - diag.fixItInsert(newRParenLoc, ")"); -} - -/// Find the trailing closure argument of a tuple or parenthesized expression. -/// -/// Due to a quirk of the backward scan that could allow reordering of -/// arguments in the presence of a trailing closure, it might not be the last -/// argument in the tuple. -static Expr *findTrailingClosureArgument(Expr *arg) { - if (auto parenExpr = dyn_cast(arg)) { - return parenExpr->getSubExpr(); - } - - auto tupleExpr = cast(arg); - SourceLoc endLoc = tupleExpr->getEndLoc(); - for (Expr *elt : llvm::reverse(tupleExpr->getElements())) { - if (elt->getEndLoc() == endLoc) - return elt; - } - - return tupleExpr->getElements().back(); -} - -/// Find the index of the parameter that binds the given argument. -static unsigned findParamBindingArgument( - ArrayRef parameterBindings, unsigned argIndex) { - for (unsigned paramIdx : indices(parameterBindings)) { - if (llvm::find(parameterBindings[paramIdx], argIndex) - != parameterBindings[paramIdx].end()) - return paramIdx; - } - - llvm_unreachable("No parameter binds the argument?"); -} - -/// Warn about the use of the deprecated "backward" scan for matching the -/// unlabeled trailing closure. It was needed to properly type check, but -/// this code will break with a future version of Swift. -static void warnAboutTrailingClosureBackwardScan( - ConcreteDeclRef callee, Expr *fn, Expr *arg, - ArrayRef params, - Optional unlabeledTrailingClosureIndex, - ArrayRef parameterBindings) { - - Expr *trailingClosure = findTrailingClosureArgument(arg); - unsigned paramIdx = findParamBindingArgument( - parameterBindings, *unlabeledTrailingClosureIndex); - ASTContext &ctx = params[paramIdx].getPlainType()->getASTContext(); - Identifier paramName = params[paramIdx].getLabel(); - - { - auto diag = ctx.Diags.diagnose( - trailingClosure->getStartLoc(), - diag::unlabeled_trailing_closure_deprecated, paramName); - labelTrailingClosureArgument( - ctx, fn, arg, paramName, trailingClosure, diag); - } - - if (auto decl = callee.getDecl()) { - ctx.Diags.diagnose(decl, diag::decl_declared_here, decl->getName()); - } -} - Expr *ExprRewriter::coerceCallArguments( Expr *arg, AnyFunctionType *funcType, ConcreteDeclRef callee, @@ -5681,13 +5570,6 @@ Expr *ExprRewriter::coerceCallArguments( // FIXME: Eventually, we want to enforce that we have either argTuple or // argParen here. - // Warn about the backward scan being deprecated. - if (trailingClosureMatching == TrailingClosureMatching::Backward) { - warnAboutTrailingClosureBackwardScan( - callee, apply ? apply->getFn() : nullptr, arg, params, - unlabeledTrailingClosureIndex, parameterBindings); - } - SourceLoc lParenLoc, rParenLoc; if (argTuple) { lParenLoc = argTuple->getLParenLoc(); @@ -7755,9 +7637,8 @@ namespace { componentType = solution.simplifyType(cs.getType(kp, i)); assert(!componentType->hasTypeVariable() && "Should not write type variable into key-path component"); + kp->getMutableComponents()[i].setComponentType(componentType); } - - kp->getMutableComponents()[i].setComponentType(componentType); } } diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 46c02ad1b70a2..bb99b97afd980 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -715,8 +715,7 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( // Make sure we aren't trying to equate type variables with different // lvalue-binding rules. - if (auto otherTypeVar = - type->lookThroughAllOptionalTypes()->getAs()) { + if (auto otherTypeVar = type->getAs()) { if (typeVar->getImpl().canBindToLValue() != otherTypeVar->getImpl().canBindToLValue()) return None; diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 2f15f49b0f071..30568a03ce29e 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3214,6 +3214,9 @@ bool MissingMemberFailure::diagnoseAsError() { if (diagnoseInLiteralCollectionContext()) return true; + if (diagnoseForSubscriptMemberWithTupleBase()) + return true; + auto baseType = resolveType(getBaseType())->getWithoutSpecifierType(); DeclNameLoc nameLoc(::getLoc(anchor)); @@ -3430,6 +3433,73 @@ bool MissingMemberFailure::diagnoseInLiteralCollectionContext() const { return false; } +bool MissingMemberFailure::diagnoseForSubscriptMemberWithTupleBase() const { + auto locator = getLocator(); + auto baseType = resolveType(getBaseType())->getWithoutSpecifierType(); + + auto *SE = getAsExpr(locator->getAnchor()); + if (!SE) + return false; + + auto tupleType = baseType->getAs(); + // For non-tuple type or empty tuples, let's fallback to the general + // diagnostic logic. + if (!tupleType || tupleType->getNumElements() == 0) + return false; + + auto *index = SE->getIndex(); + if (SE->getNumArguments() == 1) { + auto *literal = + dyn_cast(index->getSemanticsProvidingExpr()); + + llvm::Regex NumericRegex("^[0-9]+$"); + // Literal expressions may have other types of representations e.g. 0x01, + // 0b01. So let's make sure to only suggest this tailored literal fix-it for + // number only literals. + if (literal && NumericRegex.match(literal->getDigitsText())) { + unsigned int literalValue = 0; + literal->getDigitsText().getAsInteger(/*Radix=*/0, literalValue); + + // Verify if the literal value is within the bounds of tuple elements. + if (!literal->isNegative() && + literalValue < tupleType->getNumElements()) { + llvm::SmallString<4> dotAccess; + llvm::raw_svector_ostream OS(dotAccess); + OS << "." << literalValue; + + emitDiagnostic( + diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, + baseType, literal->getDigitsText()) + .fixItReplace(index->getSourceRange(), OS.str()); + return true; + } + } + + // For subscript access on tuple base types where the subscript index is a + // string literal expression which value matches a tuple element label, + // let's suggest tuple label access. + auto stringLiteral = + dyn_cast(index->getSemanticsProvidingExpr()); + if (stringLiteral && !stringLiteral->getValue().empty() && + llvm::any_of(tupleType->getElements(), [&](TupleTypeElt element) { + return element.getName().is(stringLiteral->getValue()); + })) { + llvm::SmallString<16> dotAccess; + llvm::raw_svector_ostream OS(dotAccess); + OS << "." << stringLiteral->getValue(); + + emitDiagnostic( + diag::could_not_find_subscript_member_tuple_did_you_mean_use_dot, + baseType, stringLiteral->getValue()) + .fixItReplace(index->getSourceRange(), OS.str()); + return true; + } + } + + emitDiagnostic(diag::could_not_find_subscript_member_tuple, baseType); + return true; +} + bool UnintendedExtraGenericParamMemberFailure::diagnoseAsError() { MissingMemberFailure::diagnoseAsError(); @@ -4956,6 +5026,9 @@ bool CollectionElementContextualFailure::diagnoseAsError() { Optional diagnostic; if (isExpr(anchor)) { + if (diagnoseMergedLiteralElements()) + return true; + diagnostic.emplace(emitDiagnostic(diag::cannot_convert_array_element, eltType, contextualType)); } @@ -5006,6 +5079,30 @@ bool CollectionElementContextualFailure::diagnoseAsError() { return true; } +bool CollectionElementContextualFailure::diagnoseMergedLiteralElements() { + auto elementAnchor = simplifyLocatorToAnchor(getLocator()); + if (!elementAnchor) + return false; + + auto *typeVar = getRawType(elementAnchor)->getAs(); + if (!typeVar || !typeVar->getImpl().getAtomicLiteralKind()) + return false; + + // This element is a literal whose type variable could have been merged with others, + // but the conversion constraint to the array element type was only placed on one + // of them. So, we want to emit the error for each element whose type variable is in + // this equivalence class. + auto &cs = getConstraintSystem(); + auto node = cs.getRepresentative(typeVar)->getImpl().getGraphNode(); + for (const auto *typeVar : node->getEquivalenceClass()) { + auto anchor = typeVar->getImpl().getLocator()->getAnchor(); + emitDiagnosticAt(constraints::getLoc(anchor), diag::cannot_convert_array_element, + getFromType(), getToType()); + } + + return true; +} + bool MissingContextualConformanceFailure::diagnoseAsError() { auto anchor = getAnchor(); auto path = getLocator()->getPath(); @@ -6573,3 +6670,95 @@ SourceLoc MissingOptionalUnwrapKeyPathFailure::getLoc() const { auto *SE = castToExpr(getAnchor()); return SE->getBase()->getEndLoc(); } + +bool TrailingClosureRequiresExplicitLabel::diagnoseAsError() { + auto argInfo = *getFunctionArgApplyInfo(getLocator()); + + { + auto diagnostic = emitDiagnostic( + diag::unlabeled_trailing_closure_deprecated, argInfo.getParamLabel()); + fixIt(diagnostic, argInfo); + } + + if (auto *callee = argInfo.getCallee()) { + emitDiagnosticAt(callee, diag::decl_declared_here, callee->getName()); + } + + return true; +} + +void TrailingClosureRequiresExplicitLabel::fixIt( + InFlightDiagnostic &diagnostic, const FunctionArgApplyInfo &info) const { + auto &ctx = getASTContext(); + + // Dig out source locations. + SourceLoc existingRParenLoc; + SourceLoc leadingCommaLoc; + + auto anchor = getRawAnchor(); + auto *arg = info.getArgListExpr(); + Expr *fn = nullptr; + + if (auto *applyExpr = getAsExpr(anchor)) { + fn = applyExpr->getFn(); + } else { + // Covers subscripts, unresolved members etc. + fn = getAsExpr(anchor); + } + + if (!fn) + return; + + auto *trailingClosure = info.getArgExpr(); + + if (auto tupleExpr = dyn_cast(arg)) { + existingRParenLoc = tupleExpr->getRParenLoc(); + assert(tupleExpr->getNumElements() >= 2 && "Should be a ParenExpr?"); + leadingCommaLoc = Lexer::getLocForEndOfToken( + ctx.SourceMgr, + tupleExpr->getElements()[tupleExpr->getNumElements() - 2]->getEndLoc()); + } else { + auto parenExpr = cast(arg); + existingRParenLoc = parenExpr->getRParenLoc(); + } + + // Figure out the text to be inserted before the trailing closure. + SmallString<16> insertionText; + SourceLoc insertionLoc; + if (leadingCommaLoc.isValid()) { + insertionText += ", "; + assert(existingRParenLoc.isValid()); + insertionLoc = leadingCommaLoc; + } else if (existingRParenLoc.isInvalid()) { + insertionText += "("; + insertionLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, fn->getEndLoc()); + } else { + insertionLoc = existingRParenLoc; + } + + // Add the label, if there is one. + auto paramName = info.getParamLabel(); + if (!paramName.empty()) { + insertionText += paramName.str(); + insertionText += ": "; + } + + // If there is an existing right parentheses/brace, remove it while we + // insert the new text. + if (existingRParenLoc.isValid()) { + SourceLoc afterExistingRParenLoc = + Lexer::getLocForEndOfToken(ctx.SourceMgr, existingRParenLoc); + diagnostic.fixItReplaceChars(insertionLoc, afterExistingRParenLoc, + insertionText); + } else { + // Insert the appropriate prefix. + diagnostic.fixItInsert(insertionLoc, insertionText); + } + + // Insert a right parenthesis/brace after the closing '}' of the trailing + // closure; + SourceLoc newRParenLoc = + Lexer::getLocForEndOfToken(ctx.SourceMgr, trailingClosure->getEndLoc()); + diagnostic.fixItInsert(newRParenLoc, + isExpr(anchor) ? "]" : ")"); +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 2bbaebd30ec39..30192dbc20fc4 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -1075,6 +1075,14 @@ class MissingMemberFailure : public InvalidMemberRefFailure { /// that defaults the element type. e.g. _ = [.e] bool diagnoseInLiteralCollectionContext() const; + /// Tailored diagnostics for missing subscript member on a tuple base type. + /// e.g + /// ```swift + /// let tuple: (Int, Int) = (0, 0) + /// _ = tuple[0] // -> tuple.0. + /// ``` + bool diagnoseForSubscriptMemberWithTupleBase() const; + static DeclName findCorrectEnumCaseName(Type Ty, TypoCorrectionResults &corrections, DeclNameRef memberName); @@ -1637,6 +1645,8 @@ class CollectionElementContextualFailure final : public ContextualFailure { : ContextualFailure(solution, eltType, contextualType, locator) {} bool diagnoseAsError() override; + + bool diagnoseMergedLiteralElements(); }; class MissingContextualConformanceFailure final : public ContextualFailure { @@ -2214,6 +2224,30 @@ class MissingOptionalUnwrapKeyPathFailure final : public ContextualFailure { SourceLoc getLoc() const override; }; +/// Diagnose situations when trailing closure has been matched to a specific +/// parameter via a deprecated backward scan. +/// +/// \code +/// func multiple_trailing_with_defaults( +/// duration: Int, +/// animations: (() -> Void)? = nil, +/// completion: (() -> Void)? = nil) {} +/// +/// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` +/// \endcode +class TrailingClosureRequiresExplicitLabel final : public FailureDiagnostic { +public: + TrailingClosureRequiresExplicitLabel(const Solution &solution, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator) {} + + bool diagnoseAsError() override; + +private: + void fixIt(InFlightDiagnostic &diagnostic, + const FunctionArgApplyInfo &info) const; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index db3aadcaf1311..96f6a43872284 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -1526,3 +1526,16 @@ UnwrapOptionalBaseKeyPathApplication::attempt(ConstraintSystem &cs, Type baseTy, return new (cs.getAllocator()) UnwrapOptionalBaseKeyPathApplication(cs, baseTy, rootTy, locator); } + +bool SpecifyLabelToAssociateTrailingClosure::diagnose(const Solution &solution, + bool asNote) const { + TrailingClosureRequiresExplicitLabel failure(solution, getLocator()); + return failure.diagnose(asNote); +} + +SpecifyLabelToAssociateTrailingClosure * +SpecifyLabelToAssociateTrailingClosure::create(ConstraintSystem &cs, + ConstraintLocator *locator) { + return new (cs.getAllocator()) + SpecifyLabelToAssociateTrailingClosure(cs, locator); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index 662779f26e0da..ae232f33ff187 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -269,6 +269,10 @@ enum class FixKind : uint8_t { /// Unwrap optional base on key path application. UnwrapOptionalBaseKeyPathApplication, + + /// Explicitly specify a label to match trailing closure to a certain + /// parameter in the call. + SpecifyLabelToAssociateTrailingClosure, }; class ConstraintFix { @@ -1926,6 +1930,34 @@ class UnwrapOptionalBaseKeyPathApplication final : public ContextualMismatch { ConstraintLocator *locator); }; +/// Diagnose situations when solver used old (backward scan) rule +/// to match trailing closure to a parameter. +/// +/// \code +/// func multiple_trailing_with_defaults( +/// duration: Int, +/// animations: (() -> Void)? = nil, +/// completion: (() -> Void)? = nil) {} +/// +/// multiple_trailing_with_defaults(duration: 42) {} // picks `completion:` +/// \endcode +class SpecifyLabelToAssociateTrailingClosure final : public ConstraintFix { + SpecifyLabelToAssociateTrailingClosure(ConstraintSystem &cs, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::SpecifyLabelToAssociateTrailingClosure, + locator, /*isWarning=*/true) {} + +public: + std::string getName() const override { + return "specify a label to associate trailing closure with parameter"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + static SpecifyLabelToAssociateTrailingClosure * + create(ConstraintSystem &cs, ConstraintLocator *locator); +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 17bc2131476eb..de70a78b974ea 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1803,31 +1803,28 @@ namespace { auto locator = CS.getConstraintLocator(expr); auto contextualType = CS.getContextualType(expr); - Type contextualArrayType = nullptr; - Type contextualArrayElementType = nullptr; - + + auto joinElementTypes = [&](Optional elementType) { + const auto elements = expr->getElements(); + unsigned index = 0; + + using Iterator = decltype(elements)::iterator; + CS.addJoinConstraint(locator, elements.begin(), elements.end(), + elementType, [&](const auto it) { + auto *locator = CS.getConstraintLocator(expr, LocatorPathElt::TupleElement(index++)); + return std::make_pair(CS.getType(*it), locator); + }); + }; + // If a contextual type exists for this expression, apply it directly. Optional arrayElementType; if (contextualType && (arrayElementType = ConstraintSystem::isArrayType(contextualType))) { - // Is the array type a contextual type - contextualArrayType = contextualType; - contextualArrayElementType = *arrayElementType; - CS.addConstraint(ConstraintKind::LiteralConformsTo, contextualType, arrayProto->getDeclaredInterfaceType(), locator); - - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - contextualArrayElementType, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } - - return contextualArrayType; + joinElementTypes(arrayElementType); + return contextualType; } // Produce a specialized diagnostic if this is an attempt to initialize @@ -1893,14 +1890,7 @@ namespace { // Introduce conversions from each element to the element type of the // array. - unsigned index = 0; - for (auto element : expr->getElements()) { - CS.addConstraint(ConstraintKind::Conversion, - CS.getType(element), - arrayElementTy, - CS.getConstraintLocator( - expr, LocatorPathElt::TupleElement(index++))); - } + joinElementTypes(arrayElementTy); // The array element type defaults to 'Any'. CS.addConstraint(ConstraintKind::Defaultable, arrayElementTy, @@ -2501,23 +2491,31 @@ namespace { if (enumPattern->getParentType() || enumPattern->getParentTypeRepr()) { // Resolve the parent type. Type parentType = [&]() -> Type { - if (const auto resolvedTy = enumPattern->getParentType()) { - assert(resolvedTy->hasUnboundGenericType() == false && - "A pre-resolved type must be fully bound"); - return resolvedTy; + if (auto preTy = enumPattern->getParentType()) { + return preTy; } return resolveTypeReferenceInExpression( enumPattern->getParentTypeRepr(), - TypeResolverContext::InExpression, - OpenUnboundGenericType( - CS, CS.getConstraintLocator( - locator, {LocatorPathElt::PatternMatch(pattern), - ConstraintLocator::ParentType}))); + TypeResolverContext::InExpression, [](auto unboundTy) { + // FIXME: We ought to pass an OpenUnboundGenericType object + // rather than calling CS.openUnboundGenericType below, but + // sometimes the parent type is resolved eagerly in + // ResolvePattern::visitUnresolvedDotExpr, letting unbound + // generics escape. + return unboundTy; + }); }(); if (!parentType) return Type(); + parentType = CS.openUnboundGenericTypes( + parentType, CS.getConstraintLocator( + locator, {LocatorPathElt::PatternMatch(pattern), + ConstraintLocator::ParentType})); + + assert(parentType); + // Perform member lookup into the parent's metatype. Type parentMetaType = MetatypeType::get(parentType); CS.addValueMemberConstraint( @@ -3494,6 +3492,9 @@ namespace { } case KeyPathExpr::Component::Kind::Identity: continue; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } // By now, `base` is the result type of this component. Set it in the @@ -4013,6 +4014,9 @@ generateForEachStmtConstraints( if (cs.generateConstraints(whereTarget, FreeTypeVariableBinding::Disallow)) return None; + cs.setContextualType(forEachStmtInfo.whereExpr, + TypeLoc::withoutLoc(boolType), CTP_Condition); + forEachStmtInfo.whereExpr = whereTarget.getAsExpr(); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b85e02d509480..6468c1e5a0cc1 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1208,6 +1208,9 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( // Match up the call arguments to the parameters. SmallVector parameterBindings; + TrailingClosureMatching selectedTrailingMatching = + TrailingClosureMatching::Forward; + { ArgumentFailureTracker listener(cs, argsWithLabels, params, locator); auto callArgumentMatch = constraints::matchCallArguments( @@ -1224,10 +1227,10 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( return cs.getTypeMatchAmbiguous(); } + selectedTrailingMatching = callArgumentMatch->trailingClosureMatching; // Record the direction of matching used for this call. - cs.recordTrailingClosureMatch( - cs.getConstraintLocator(locator), - callArgumentMatch->trailingClosureMatching); + cs.recordTrailingClosureMatch(cs.getConstraintLocator(locator), + selectedTrailingMatching); // If there was a disjunction because both forward and backward were // possible, increase the score for forward matches to bias toward the @@ -1316,6 +1319,15 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments( } } + // In case solver matched trailing based on the backward scan, + // let's produce a warning which would suggest to add a label + // to disambiguate in the future. + if (selectedTrailingMatching == TrailingClosureMatching::Backward && + argIdx == *argInfo->UnlabeledTrailingClosureIndex) { + cs.recordFix(SpecifyLabelToAssociateTrailingClosure::create( + cs, cs.getConstraintLocator(loc))); + } + // If argument comes for declaration it should loose // `@autoclosure` flag, because in context it's used // as a function type represented by autoclosure. @@ -4220,6 +4232,7 @@ bool ConstraintSystem::repairFailures( conversionsOrFixes.push_back(CollectionElementContextualMismatch::create( *this, lhs, rhs, getConstraintLocator(locator))); + break; } // Drop the `tuple element` locator element so that all tuple element @@ -6590,6 +6603,14 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, baseObjTy->is() && constraintKind == ConstraintKind::UnresolvedValueMember) { if (auto objectType = instanceTy->getOptionalObjectType()) { + // If we don't have a wrapped type yet, we can't look through the optional + // type. + if (objectType->getAs()) { + MemberLookupResult result; + result.OverallResult = MemberLookupResult::Unsolved; + return result; + } + if (objectType->mayHaveMembers()) { LookupResult &optionalLookup = lookupMember(objectType, memberName); for (auto result : optionalLookup) @@ -8242,6 +8263,9 @@ ConstraintSystem::simplifyKeyPathConstraint( case KeyPathExpr::Component::Kind::TupleElement: llvm_unreachable("not implemented"); break; + case KeyPathExpr::Component::Kind::DictionaryKey: + llvm_unreachable("DictionaryKey only valid in #keyPath"); + break; } } @@ -9963,7 +9987,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowKeyPathRootTypeMismatch: case FixKind::UnwrapOptionalBaseKeyPathApplication: case FixKind::AllowCoercionToForceCast: - case FixKind::SpecifyKeyPathRootType: { + case FixKind::SpecifyKeyPathRootType: + case FixKind::SpecifyLabelToAssociateTrailingClosure: { return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved; } @@ -10432,35 +10457,6 @@ void ConstraintSystem::addContextualConversionConstraint( convertTypeLocator, /*isFavored*/ true); } -Type ConstraintSystem::addJoinConstraint( - ConstraintLocator *locator, - ArrayRef> inputs) { - switch (inputs.size()) { - case 0: - return Type(); - - case 1: - return inputs.front().first; - - default: - // Produce the join below. - break; - } - - // Create a type variable to capture the result of the join. - Type resultTy = createTypeVariable(locator, - (TVO_PrefersSubtypeBinding | - TVO_CanBindToNoEscape)); - - // Introduce conversions from each input type to the type variable. - for (const auto &input : inputs) { - addConstraint( - ConstraintKind::Conversion, input.first, resultTy, input.second); - } - - return resultTy; -} - void ConstraintSystem::addFixConstraint(ConstraintFix *fix, ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 9efa5190ffe77..7106adf24404a 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -493,6 +493,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator( case ComponentKind::OptionalChain: case ComponentKind::OptionalWrap: case ComponentKind::Identity: + case ComponentKind::DictionaryKey: // These components don't have any callee associated, so just continue. break; } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index 884357bbe5070..4e4924a0bc78b 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -306,6 +306,11 @@ class TypeVariableType::Implementation { /// Retrieve the generic parameter opened by this type variable. GenericTypeParamType *getGenericParameter() const; + /// Returns the \c ExprKind of this type variable if it's the type of an + /// atomic literal expression, meaning the literal can't be composed of subexpressions. + /// Otherwise, returns \c None. + Optional getAtomicLiteralKind() const; + /// Determine whether this type variable represents a closure type. bool isClosureType() const; @@ -554,6 +559,9 @@ class FunctionArgApplyInfo { ArgType(argType), ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), FnType(fnType), Callee(callee) {} + /// \returns The list of the arguments used for this application. + Expr *getArgListExpr() const { return ArgListExpr; } + /// \returns The argument being applied. Expr *getArgExpr() const { return ArgExpr; } @@ -581,6 +589,11 @@ class FunctionArgApplyInfo { return Identifier(); } + Identifier getParamLabel() const { + auto param = FnType->getParams()[ParamIdx]; + return param.getLabel(); + } + /// \returns A textual description of the argument suitable for diagnostics. /// For an argument with an unambiguous label, this will the label. Otherwise /// it will be its position in the argument list. @@ -3076,16 +3089,78 @@ class ConstraintSystem { Expr *expr, Type conversionType, ContextualTypePurpose purpose, bool isOpaqueReturnType); + /// Convenience function to pass an \c ArrayRef to \c addJoinConstraint + Type addJoinConstraint(ConstraintLocator *locator, + ArrayRef> inputs, + Optional supertype = None) { + return addJoinConstraint( + locator, inputs.begin(), inputs.end(), supertype, [](auto it) { return *it; }); + } + /// Add a "join" constraint between a set of types, producing the common /// supertype. /// /// Currently, a "join" is modeled by a set of conversion constraints to - /// a new type variable. At some point, we may want a new constraint kind - /// to cover the join. + /// a new type variable or a specified supertype. At some point, we may want + /// a new constraint kind to cover the join. /// - /// \returns the joined type, which is generally a new type variable. + /// \note This method will merge any input type variables for atomic literal + /// expressions of the same kind. It assumes that if same-kind literal type + /// variables are joined, there will be no differing constraints on those + /// type variables. + /// + /// \returns the joined type, which is generally a new type variable, unless there are + /// fewer than 2 input types or the \c supertype parameter is specified. + template Type addJoinConstraint(ConstraintLocator *locator, - ArrayRef> inputs); + Iterator begin, Iterator end, + Optional supertype, + std::function(Iterator)> getType) { + if (begin == end) + return Type(); + + // No need to generate a new type variable if there's only one type to join + if ((begin + 1 == end) && !supertype.hasValue()) + return getType(begin).first; + + // The type to capture the result of the join, which is either the specified supertype, + // or a new type variable. + Type resultTy = supertype.hasValue() ? supertype.getValue() : + createTypeVariable(locator, (TVO_PrefersSubtypeBinding | TVO_CanBindToNoEscape)); + + using RawExprKind = uint8_t; + llvm::SmallDenseMap representativeForKind; + + // Join the input types. + while (begin != end) { + Type type; + ConstraintLocator *locator; + std::tie(type, locator) = getType(begin++); + + // We can merge the type variables of same-kind atomic literal expressions because they + // will all have the same set of constraints and therefore can never resolve to anything + // different. + if (auto *typeVar = type->getAs()) { + if (auto literalKind = typeVar->getImpl().getAtomicLiteralKind()) { + auto *&originalRep = representativeForKind[RawExprKind(*literalKind)]; + auto *currentRep = getRepresentative(typeVar); + + if (originalRep) { + if (originalRep != currentRep) + mergeEquivalenceClasses(currentRep, originalRep); + continue; + } + + originalRep = currentRep; + } + } + + // Introduce conversions from each input type to the supertype. + addConstraint(ConstraintKind::Conversion, type, resultTy, locator); + } + + return resultTy; + } /// Add a constraint to the constraint system with an associated fix. void addFixConstraint(ConstraintFix *fix, ConstraintKind kind, diff --git a/lib/Sema/DerivedConformanceCaseIterable.cpp b/lib/Sema/DerivedConformanceCaseIterable.cpp index bc809b4e53930..14d3309936918 100644 --- a/lib/Sema/DerivedConformanceCaseIterable.cpp +++ b/lib/Sema/DerivedConformanceCaseIterable.cpp @@ -69,15 +69,6 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumDecl) { return ArraySliceType::get(enumType); } -static Type deriveCaseIterable_AllCases(DerivedConformance &derived) { - // enum SomeEnum : CaseIterable { - // @derived - // typealias AllCases = [SomeEnum] - // } - auto *rawInterfaceType = computeAllCasesType(cast(derived.Nominal)); - return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType); -} - ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { // Conformance can't be synthesized in an extension. if (checkAndDiagnoseDisallowedContext(requirement)) @@ -111,18 +102,3 @@ ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) { return propDecl; } - -Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) { - // Check that we can actually derive CaseIterable for this type. - if (!canDeriveConformance(Nominal)) - return nullptr; - - if (assocType->getName() == Context.Id_AllCases) { - return deriveCaseIterable_AllCases(*this); - } - - Context.Diags.diagnose(assocType->getLoc(), - diag::broken_case_iterable_requirement); - return nullptr; -} - diff --git a/lib/Sema/DerivedConformanceCodable.cpp b/lib/Sema/DerivedConformanceCodable.cpp index cc455dfdc6f40..701189126dc34 100644 --- a/lib/Sema/DerivedConformanceCodable.cpp +++ b/lib/Sema/DerivedConformanceCodable.cpp @@ -29,91 +29,15 @@ using namespace swift; /// Returns whether the type represented by the given ClassDecl inherits from a /// type which conforms to the given protocol. -/// -/// \param target The \c ClassDecl whose superclass to look up. -/// -/// \param proto The protocol to check conformance for. -static bool inheritsConformanceTo(ClassDecl *target, ProtocolDecl *proto) { - if (!target->hasSuperclass()) +static bool superclassConformsTo(ClassDecl *target, KnownProtocolKind kpk) { + if (!target || !target->getSuperclass() || target->hasCircularInheritance()) { return false; - - auto *superclassDecl = target->getSuperclassDecl(); - auto *superclassModule = superclassDecl->getModuleContext(); - return (bool)superclassModule->lookupConformance(target->getSuperclass(), - proto); -} - -/// Returns whether the superclass of the given class conforms to Encodable. -/// -/// \param target The \c ClassDecl whose superclass to check. -static bool superclassIsEncodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Encodable)); -} - -/// Returns whether the superclass of the given class conforms to Decodable. -/// -/// \param target The \c ClassDecl whose superclass to check. -static bool superclassIsDecodable(ClassDecl *target) { - auto &C = target->getASTContext(); - return inheritsConformanceTo(target, - C.getProtocol(KnownProtocolKind::Decodable)); -} - -/// Represents the possible outcomes of checking whether a decl conforms to -/// Encodable or Decodable. -enum CodableConformanceType { - TypeNotValidated, - DoesNotConform, - Conforms -}; - -/// Returns whether the given type conforms to the given {En,De}codable -/// protocol. -/// -/// \param context The \c DeclContext the var declarations belong to. -/// -/// \param target The \c Type to validate. -/// -/// \param proto The \c ProtocolDecl to check conformance to. -static CodableConformanceType typeConformsToCodable(DeclContext *context, - Type target, bool isIUO, - ProtocolDecl *proto) { - target = context->mapTypeIntoContext(target); - - if (isIUO) - target = target->lookThroughSingleOptionalType(); - - auto conf = TypeChecker::conformsToProtocol(target, proto, context); - return conf.isInvalid() ? DoesNotConform : Conforms; -} - -/// Returns whether the given variable conforms to the given {En,De}codable -/// protocol. -/// -/// \param DC The \c DeclContext in which to check conformance. -/// -/// \param varDecl The \c VarDecl to validate. -/// -/// \param proto The \c ProtocolDecl to check conformance to. -static CodableConformanceType -varConformsToCodable(DeclContext *DC, VarDecl *varDecl, ProtocolDecl *proto) { - // If the decl doesn't yet have a type, we may be seeing it before the type - // checker has gotten around to evaluating its type. For example: - // - // func foo() { - // let b = Bar(from: decoder) // <- evaluates Bar conformance to Codable, - // // forcing derivation - // } - // - // struct Bar : Codable { - // var x: Int // <- we get to valuate x's var decl here, but its type - // // hasn't yet been evaluated - // } - bool isIUO = varDecl->isImplicitlyUnwrappedOptional(); - return typeConformsToCodable(DC, varDecl->getValueInterfaceType(), isIUO, - proto); + } + return !target->getSuperclassDecl() + ->getModuleContext() + ->lookupConformance(target->getSuperclass(), + target->getASTContext().getProtocol(kpk)) + .isInvalid(); } /// Retrieve the variable name for the purposes of encoding/decoding. @@ -128,7 +52,7 @@ static Identifier getVarNameForCoding(VarDecl *var) { /// match with the stored vars of the given type. /// /// \param codingKeysDecl The \c CodingKeys enum decl to validate. -static bool validateCodingKeysEnum(DerivedConformance &derived, +static bool validateCodingKeysEnum(const DerivedConformance &derived, EnumDecl *codingKeysDecl) { auto conformanceDC = derived.getConformanceContext(); @@ -143,7 +67,7 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, // Here we'll hold on to properties by name -- when we've validated a property // against its CodingKey entry, it will get removed. - llvm::SmallDenseMap properties; + llvm::SmallMapVector properties; for (auto *varDecl : derived.Nominal->getStoredProperties()) { if (!varDecl->isUserAccessible()) continue; @@ -164,34 +88,20 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, } // We have a property to map to. Ensure it's {En,De}codable. - auto conformance = - varConformsToCodable(conformanceDC, it->second, derived.Protocol); - switch (conformance) { - case Conforms: - // The property was valid. Remove it from the list. - properties.erase(it); - break; - - case DoesNotConform: { - // We use a TypeLoc here so diagnostics can show the type - // as written by the user in source if possible. This is useful - // when the user has written an IUO type for example, since - // diagnostics would show the type as 'T?' instead of 'T!' if - // we use a Type instead. - TypeLoc typeLoc = { - it->second->getTypeReprOrParentPatternTypeRepr(), - it->second->getType(), - }; - it->second->diagnose(diag::codable_non_conforming_property_here, - derived.getProtocolType(), typeLoc); - LLVM_FALLTHROUGH; - } - - case TypeNotValidated: - // We don't produce a diagnostic for a type which failed to validate. - // This will produce a diagnostic elsewhere anyway. - propertiesAreValid = false; - continue; + auto target = + conformanceDC->mapTypeIntoContext(it->second->getValueInterfaceType()); + if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC) + .isInvalid()) { + TypeLoc typeLoc = { + it->second->getTypeReprOrParentPatternTypeRepr(), + it->second->getType(), + }; + it->second->diagnose(diag::codable_non_conforming_property_here, + derived.getProtocolType(), typeLoc); + propertiesAreValid = false; + } else { + // The property was valid. Remove it from the list. + properties.erase(it); } } @@ -201,25 +111,22 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, // If there are any remaining properties which the CodingKeys did not cover, // we can skip them on encode. On decode, though, we can only skip them if // they have a default value. - if (!properties.empty() && - derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) { - for (auto it = properties.begin(); it != properties.end(); ++it) { - // If the var is default initializable, then it need not have an explicit - // initial value. - auto *varDecl = it->second; - if (auto pbd = varDecl->getParentPatternBinding()) { - if (pbd->isDefaultInitializable()) - continue; + if (derived.Protocol->isSpecificProtocol(KnownProtocolKind::Decodable)) { + for (auto &entry : properties) { + const auto *pbd = entry.second->getParentPatternBinding(); + if (pbd && pbd->isDefaultInitializable()) { + continue; } - if (varDecl->isParentInitialized()) + if (entry.second->isParentInitialized()) { continue; + } // The var was not default initializable, and did not have an explicit // initial value. propertiesAreValid = false; - it->second->diagnose(diag::codable_non_decoded_property_here, - derived.getProtocolType(), it->first); + entry.second->diagnose(diag::codable_non_decoded_property_here, + derived.getProtocolType(), entry.first); } } @@ -227,11 +134,14 @@ static bool validateCodingKeysEnum(DerivedConformance &derived, } /// A type which has information about the validity of an encountered -/// CodingKeys type. -struct CodingKeysValidity { - bool hasType; - bool isValid; - CodingKeysValidity(bool ht, bool iv) : hasType(ht), isValid(iv) {} +/// \c CodingKeys type. +enum class CodingKeysClassification { + /// A \c CodingKeys declaration was found, but it is invalid. + Invalid, + /// No \c CodingKeys declaration was found, so it must be synthesized. + NeedsSynthesizedCodingKeys, + /// A valid \c CodingKeys declaration was found. + Valid, }; /// Returns whether the given type has a valid nested \c CodingKeys enum. @@ -243,12 +153,14 @@ struct CodingKeysValidity { /// enum. /// /// \returns A \c CodingKeysValidity value representing the result of the check. -static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { +static CodingKeysClassification +classifyCodingKeys(const DerivedConformance &derived) { auto &C = derived.Context; auto codingKeysDecls = derived.Nominal->lookupDirect(DeclName(C.Id_CodingKeys)); - if (codingKeysDecls.empty()) - return CodingKeysValidity(/*hasType=*/false, /*isValid=*/true); + if (codingKeysDecls.empty()) { + return CodingKeysClassification::NeedsSynthesizedCodingKeys; + } // Only ill-formed code would produce multiple results for this lookup. // This would get diagnosed later anyway, so we're free to only look at the @@ -259,7 +171,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { if (!codingKeysTypeDecl) { result->diagnose(diag::codable_codingkeys_type_is_not_an_enum_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } // CodingKeys may be a typealias. If so, follow the alias to its canonical @@ -283,7 +195,7 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { C.Diags.diagnose(loc, diag::codable_codingkeys_type_does_not_conform_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } // CodingKeys must be an enum for synthesized conformance. @@ -292,11 +204,12 @@ static CodingKeysValidity hasValidCodingKeysEnum(DerivedConformance &derived) { codingKeysTypeDecl->diagnose( diag::codable_codingkeys_type_is_not_an_enum_here, derived.getProtocolType()); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/false); + return CodingKeysClassification::Invalid; } - bool valid = validateCodingKeysEnum(derived, codingKeysEnum); - return CodingKeysValidity(/*hasType=*/true, /*isValid=*/valid); + return validateCodingKeysEnum(derived, codingKeysEnum) + ? CodingKeysClassification::Valid + : CodingKeysClassification::Invalid; } /// Synthesizes a new \c CodingKeys enum based on the {En,De}codable members of @@ -326,8 +239,8 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) { // For classes which inherit from something Encodable or Decodable, we // provide case `super` as the first key (to be used in encoding super). auto *classDecl = dyn_cast(target); - if (classDecl && - (superclassIsEncodable(classDecl) || superclassIsDecodable(classDecl))) { + if (superclassConformsTo(classDecl, KnownProtocolKind::Encodable) || + superclassConformsTo(classDecl, KnownProtocolKind::Decodable)) { // TODO: Ensure the class doesn't already have or inherit a variable named // "`super`"; otherwise we will generate an invalid enum. In that case, // diagnose and bail. @@ -340,48 +253,29 @@ static EnumDecl *synthesizeCodingKeysEnum(DerivedConformance &derived) { // Each of these vars needs a case in the enum. For each var decl, if the type // conforms to {En,De}codable, add it to the enum. bool allConform = true; + auto *conformanceDC = derived.getConformanceContext(); for (auto *varDecl : target->getStoredProperties()) { - if (!varDecl->isUserAccessible()) + if (!varDecl->isUserAccessible()) { continue; + } - // Despite creating the enum in the context of the type, we're - // concurrently checking the variables for the current protocol - // conformance being synthesized, for which we use the conformance - // context, not the type. - auto conformance = varConformsToCodable(derived.getConformanceContext(), - varDecl, derived.Protocol); - switch (conformance) { - case Conforms: - { - auto *elt = new (C) EnumElementDecl(SourceLoc(), - getVarNameForCoding(varDecl), - nullptr, SourceLoc(), nullptr, - enumDecl); - elt->setImplicit(); - enumDecl->addMember(elt); - break; - } - - case DoesNotConform: { - // We use a TypeLoc here so diagnostics can show the type - // as written by the user in source if possible. This is useful - // when the user has written an IUO type for example, since - // diagnostics would show the type as 'T?' instead of 'T!' if - // we use a Type instead. - TypeLoc typeLoc = { - varDecl->getTypeReprOrParentPatternTypeRepr(), - varDecl->getType(), - }; - varDecl->diagnose(diag::codable_non_conforming_property_here, - derived.getProtocolType(), typeLoc); - LLVM_FALLTHROUGH; - } - - case TypeNotValidated: - // We don't produce a diagnostic for a type which failed to validate. - // This will produce a diagnostic elsewhere anyway. - allConform = false; - continue; + auto target = + conformanceDC->mapTypeIntoContext(varDecl->getValueInterfaceType()); + if (TypeChecker::conformsToProtocol(target, derived.Protocol, conformanceDC) + .isInvalid()) { + TypeLoc typeLoc = { + varDecl->getTypeReprOrParentPatternTypeRepr(), + varDecl->getType(), + }; + varDecl->diagnose(diag::codable_non_conforming_property_here, + derived.getProtocolType(), typeLoc); + allConform = false; + } else { + auto *elt = + new (C) EnumElementDecl(SourceLoc(), getVarNameForCoding(varDecl), + nullptr, SourceLoc(), nullptr, enumDecl); + elt->setImplicit(); + enumDecl->addMember(elt); } } @@ -660,8 +554,8 @@ deriveBodyEncodable_encode(AbstractFunctionDecl *encodeDecl, void *) { } // Classes which inherit from something Codable should encode super as well. - auto *classDecl = dyn_cast(targetDecl); - if (classDecl && superclassIsEncodable(classDecl)) { + if (superclassConformsTo(dyn_cast(targetDecl), + KnownProtocolKind::Encodable)) { // Need to generate `try super.encode(to: container.superEncoder())` // superEncoder() @@ -743,8 +637,8 @@ static FuncDecl *deriveEncodable_encode(DerivedConformance &derived) { // This method should be marked as 'override' for classes inheriting Encodable // conformance from a parent class. - auto *classDecl = dyn_cast(derived.Nominal); - if (classDecl && superclassIsEncodable(classDecl)) { + if (superclassConformsTo(dyn_cast(derived.Nominal), + KnownProtocolKind::Encodable)) { auto *attr = new (C) OverrideAttr(/*IsImplicit=*/true); encodeDecl->getAttrs().add(attr); } @@ -951,7 +845,7 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) { // superclass is Decodable, or super.init() if it is not. if (auto *classDecl = dyn_cast(targetDecl)) { if (auto *superclassDecl = classDecl->getSuperclassDecl()) { - if (superclassIsDecodable(classDecl)) { + if (superclassConformsTo(classDecl, KnownProtocolKind::Decodable)) { // Need to generate `try super.init(from: container.superDecoder())` // container.superDecoder @@ -985,7 +879,8 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) { statements.push_back(tryExpr); } else { // The explicit constructor name is a compound name taking no arguments. - DeclName initName(C, DeclBaseName::createConstructor(), ArrayRef()); + DeclName initName(C, DeclBaseName::createConstructor(), + ArrayRef()); // We need to look this up in the superclass to see if it throws. auto result = superclassDecl->lookupDirect(initName); @@ -1157,21 +1052,18 @@ static bool canSynthesize(DerivedConformance &derived, ValueDecl *requirement) { } } - // If the target already has a valid CodingKeys enum, we won't need to - // synthesize one. - auto validity = hasValidCodingKeysEnum(derived); - - // We found a type, but it wasn't valid. - if (!validity.isValid) + switch (classifyCodingKeys(derived)) { + case CodingKeysClassification::Invalid: return false; - - // We can try to synthesize a type here. - if (!validity.hasType) { + case CodingKeysClassification::NeedsSynthesizedCodingKeys: { auto *synthesizedEnum = synthesizeCodingKeysEnum(derived); if (!synthesizedEnum) return false; } - + LLVM_FALLTHROUGH; + case CodingKeysClassification::Valid: + return true; + } return true; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 2321b59cc5967..460514f94216c 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -163,12 +163,6 @@ class DerivedConformance { /// \returns the derived member, which will also be added to the type. ValueDecl *deriveCaseIterable(ValueDecl *requirement); - /// Derive a CaseIterable type witness for an enum if it has no associated - /// values for any of its cases. - /// - /// \returns the derived member, which will also be added to the type. - Type deriveCaseIterable(AssociatedTypeDecl *assocType); - /// Determine if a RawRepresentable requirement can be derived for a type. /// /// This is implemented for non-empty enums without associated values, diff --git a/lib/Sema/PCMacro.cpp b/lib/Sema/PCMacro.cpp index 5d6075ef5b031..0ce8b28ac54a9 100644 --- a/lib/Sema/PCMacro.cpp +++ b/lib/Sema/PCMacro.cpp @@ -354,7 +354,7 @@ class Instrumenter : InstrumenterBase { if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -695,7 +695,7 @@ void swift::performPCMacro(SourceFile &SF) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); TypeChecker::contextualizeTopLevelCode(TLCD); } return false; diff --git a/lib/Sema/PlaygroundTransform.cpp b/lib/Sema/PlaygroundTransform.cpp index 7c7e9dcd1e39b..f36294ff47240 100644 --- a/lib/Sema/PlaygroundTransform.cpp +++ b/lib/Sema/PlaygroundTransform.cpp @@ -294,7 +294,7 @@ class Instrumenter : InstrumenterBase { BraceStmt *NB = transformBraceStmt(B); if (NB != B) { FD->setBody(NB); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } } } else if (auto *NTD = dyn_cast(D)) { @@ -893,7 +893,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body); if (NewBody != Body) { FD->setBody(NewBody); - TypeChecker::checkFunctionErrorHandling(FD); + TypeChecker::checkFunctionEffects(FD); } return false; } @@ -905,7 +905,7 @@ void swift::performPlaygroundTransform(SourceFile &SF, bool HighPerformance) { BraceStmt *NewBody = I.transformBraceStmt(Body, true); if (NewBody != Body) { TLCD->setBody(NewBody); - TypeChecker::checkTopLevelErrorHandling(TLCD); + TypeChecker::checkTopLevelEffects(TLCD); } return false; } diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 88661330d3ffb..7fff3ba04aa1f 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2067,6 +2067,7 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override, diagnoseExplicitUnavailability(base, override->getLoc(), override->getDeclContext(), + /*Flags*/None, [&](InFlightDiagnostic &diag) { ParsedDeclName parsedName = parseDeclName(attr->Rename); if (!parsedName || parsedName.isPropertyAccessor() || @@ -2097,10 +2098,11 @@ void swift::diagnoseUnavailableOverride(ValueDecl *override, /// Emit a diagnostic for references to declarations that have been /// marked as unavailable, either through "unavailable" or "obsoleted:". bool swift::diagnoseExplicitUnavailability(const ValueDecl *D, - SourceRange R, - const DeclContext *DC, - const ApplyExpr *call) { - return diagnoseExplicitUnavailability(D, R, DC, + SourceRange R, + const DeclContext *DC, + const ApplyExpr *call, + DeclAvailabilityFlags Flags) { + return diagnoseExplicitUnavailability(D, R, DC, Flags, [=](InFlightDiagnostic &diag) { fixItAvailableAttrRename(diag, R, D, AvailableAttr::isUnavailable(D), call); @@ -2172,6 +2174,7 @@ bool swift::diagnoseExplicitUnavailability( const ValueDecl *D, SourceRange R, const DeclContext *DC, + DeclAvailabilityFlags Flags, llvm::function_ref attachRenameFixIts) { auto *Attr = AvailableAttr::isUnavailable(D); if (!Attr) @@ -2229,6 +2232,14 @@ bool swift::diagnoseExplicitUnavailability( break; } + // TODO: Consider removing this. + // ObjC keypaths components weren't checked previously, so errors are demoted + // to warnings to avoid source breakage. In some cases unavailable or + // obsolete decls still map to valid ObjC runtime names, so behave correctly + // at runtime, even though their use would produce an error outside of a + // #keyPath expression. + bool warnInObjCKeyPath = Flags.contains(DeclAvailabilityFlag::ForObjCKeyPath); + if (!Attr->Rename.empty()) { SmallString<32> newNameBuf; Optional replaceKind = @@ -2238,7 +2249,9 @@ bool swift::diagnoseExplicitUnavailability( StringRef newName = replaceKind ? newNameBuf.str() : Attr->Rename; EncodedDiagnosticMessage EncodedMessage(Attr->Message); auto diag = - diags.diagnose(Loc, diag::availability_decl_unavailable_rename, + diags.diagnose(Loc, warnInObjCKeyPath + ? diag::availability_decl_unavailable_rename_warn + : diag::availability_decl_unavailable_rename, RawAccessorKind, Name, replaceKind.hasValue(), rawReplaceKind, newName, EncodedMessage.Message); attachRenameFixIts(diag); @@ -2253,7 +2266,9 @@ bool swift::diagnoseExplicitUnavailability( } else { EncodedDiagnosticMessage EncodedMessage(Attr->Message); diags - .diagnose(Loc, diag::availability_decl_unavailable, RawAccessorKind, + .diagnose(Loc, warnInObjCKeyPath + ? diag::availability_decl_unavailable_warn + : diag::availability_decl_unavailable, RawAccessorKind, Name, platform.empty(), platform, EncodedMessage.Message) .highlight(R); } @@ -2501,6 +2516,10 @@ class AvailabilityWalker : public ASTWalker { /// Walk a keypath expression, checking all of its components for /// availability. void maybeDiagKeyPath(KeyPathExpr *KP) { + auto flags = DeclAvailabilityFlags(); + if (KP->isObjC()) + flags = DeclAvailabilityFlag::ForObjCKeyPath; + for (auto &component : KP->getComponents()) { switch (component.getKind()) { case KeyPathExpr::Component::Kind::Property: @@ -2508,7 +2527,7 @@ class AvailabilityWalker : public ASTWalker { auto *decl = component.getDeclRef().getDecl(); auto loc = component.getLoc(); SourceRange range(loc, loc); - diagAvailability(decl, range, nullptr); + diagAvailability(decl, range, nullptr, flags); break; } @@ -2522,6 +2541,7 @@ class AvailabilityWalker : public ASTWalker { case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::OptionalForce: case KeyPathExpr::Component::Kind::Identity: + case KeyPathExpr::Component::Kind::DictionaryKey: break; } } @@ -2627,7 +2647,7 @@ AvailabilityWalker::diagAvailability(ConcreteDeclRef declRef, SourceRange R, if (TypeChecker::diagnoseInlinableDeclRef(R.Start, declRef, DC, FragileKind)) return true; - if (diagnoseExplicitUnavailability(D, R, DC, call)) + if (diagnoseExplicitUnavailability(D, R, DC, call, Flags)) return true; // Make sure not to diagnose an accessor's deprecation if we already diff --git a/lib/Sema/TypeCheckAvailability.h b/lib/Sema/TypeCheckAvailability.h index 29d3f385abfc8..526db08e892a8 100644 --- a/lib/Sema/TypeCheckAvailability.h +++ b/lib/Sema/TypeCheckAvailability.h @@ -50,6 +50,10 @@ enum class DeclAvailabilityFlag : uint8_t { /// Do not diagnose uses of declarations in versions before they were /// introduced. Used to work around availability-checker bugs. AllowPotentiallyUnavailable = 1 << 3, + + /// If an error diagnostic would normally be emitted, demote the error to a + /// warning. Used for ObjC key path components. + ForObjCKeyPath = 1 << 4 }; using DeclAvailabilityFlags = OptionSet; @@ -70,7 +74,8 @@ void diagnoseUnavailableOverride(ValueDecl *override, bool diagnoseExplicitUnavailability(const ValueDecl *D, SourceRange R, const DeclContext *DC, - const ApplyExpr *call); + const ApplyExpr *call, + DeclAvailabilityFlags Flags = None); /// Emit a diagnostic for references to declarations that have been /// marked as unavailable, either through "unavailable" or "obsoleted:". @@ -78,6 +83,7 @@ bool diagnoseExplicitUnavailability( const ValueDecl *D, SourceRange R, const DeclContext *DC, + DeclAvailabilityFlags Flags, llvm::function_ref attachRenameFixIts); /// Check if \p decl has a introduction version required by -require-explicit-availability diff --git a/lib/Sema/TypeCheckCodeCompletion.cpp b/lib/Sema/TypeCheckCodeCompletion.cpp index bb4470cca9c86..b40af172a2cd5 100644 --- a/lib/Sema/TypeCheckCodeCompletion.cpp +++ b/lib/Sema/TypeCheckCodeCompletion.cpp @@ -621,9 +621,21 @@ static Optional getTypeOfCompletionContextExpr( case CompletionTypeCheckKind::KeyPath: referencedDecl = nullptr; - if (auto keyPath = dyn_cast(parsedExpr)) - return TypeChecker::checkObjCKeyPathExpr(DC, keyPath, - /*requireResultType=*/true); + if (auto keyPath = dyn_cast(parsedExpr)) { + auto components = keyPath->getComponents(); + if (!components.empty()) { + auto &last = components.back(); + if (last.isResolved()) { + if (last.getKind() == KeyPathExpr::Component::Kind::Property) + referencedDecl = last.getDeclRef(); + Type lookupTy = last.getComponentType(); + ASTContext &Ctx = DC->getASTContext(); + if (auto bridgedClass = Ctx.getBridgedToObjC(DC, lookupTy)) + return bridgedClass; + return lookupTy; + } + } + } return None; } diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index fe8378900244f..bd6a0fc589bb1 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -82,6 +82,24 @@ TypeVariableType::Implementation::getGenericParameter() const { return locator ? locator->getGenericParameter() : nullptr; } +Optional +TypeVariableType::Implementation::getAtomicLiteralKind() const { + if (!locator || !locator->directlyAt()) + return None; + + auto kind = getAsExpr(locator->getAnchor())->getKind(); + switch (kind) { + case ExprKind::IntegerLiteral: + case ExprKind::FloatLiteral: + case ExprKind::StringLiteral: + case ExprKind::BooleanLiteral: + case ExprKind::NilLiteral: + return kind; + default: + return None; + } +} + bool TypeVariableType::Implementation::isClosureType() const { if (!(locator && locator->getAnchor())) return false; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 7fe587f4d2c0b..18b696e306054 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1066,7 +1066,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED, if (TypeChecker::typeCheckExpression(exprToCheck, ED, rawTy, CTP_EnumCaseRawValue)) { - TypeChecker::checkEnumElementErrorHandling(elt, exprToCheck); + TypeChecker::checkEnumElementEffects(elt, exprToCheck); } } diff --git a/lib/Sema/TypeCheckDeclPrimary.cpp b/lib/Sema/TypeCheckDeclPrimary.cpp index c307cca174ce5..7c4881e8d2305 100644 --- a/lib/Sema/TypeCheckDeclPrimary.cpp +++ b/lib/Sema/TypeCheckDeclPrimary.cpp @@ -881,7 +881,7 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator, return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx)); } - TypeChecker::checkInitializerErrorHandling(dc, initExpr); + TypeChecker::checkInitializerEffects(dc, initExpr); // Walk the checked initializer and contextualize any closures // we saw there. @@ -1657,7 +1657,7 @@ class DeclChecker : public DeclVisitor { PBD->getInitContext(i)); if (initContext) { // Check safety of error-handling in the declaration, too. - TypeChecker::checkInitializerErrorHandling(initContext, init); + TypeChecker::checkInitializerEffects(initContext, init); TypeChecker::contextualizeInitializer(initContext, init); } } diff --git a/lib/Sema/TypeCheckError.cpp b/lib/Sema/TypeCheckEffects.cpp similarity index 85% rename from lib/Sema/TypeCheckError.cpp rename to lib/Sema/TypeCheckEffects.cpp index 92819337f75dc..69e7d578fee17 100644 --- a/lib/Sema/TypeCheckError.cpp +++ b/lib/Sema/TypeCheckEffects.cpp @@ -1,4 +1,4 @@ -//===--- TypeCheckError.cpp - Type Checking for Error Coverage ------------===// +//===--- TypeCheckEffects.cpp - Type Checking for Effects Coverage --------===// // // This source file is part of the Swift.org open source project // @@ -10,8 +10,8 @@ // //===----------------------------------------------------------------------===// // -// This file implements semantic analysis to ensure that errors are -// caught. +// This file implements semantic analysis to ensure that various effects (such +// as throwing and async) are properly handled. // //===----------------------------------------------------------------------===// @@ -184,9 +184,9 @@ enum ShouldRecurse_t : bool { }; /// A CRTP ASTWalker implementation that looks for interesting -/// nodes for error handling. +/// nodes for effects handling. template -class ErrorHandlingWalker : public ASTWalker { +class EffectsHandlingWalker : public ASTWalker { Impl &asImpl() { return *static_cast(this); } public: bool walkToDeclPre(Decl *D) override { @@ -221,7 +221,7 @@ class ErrorHandlingWalker : public ASTWalker { } else if (auto interpolated = dyn_cast(E)) { recurse = asImpl().checkInterpolatedStringLiteral(interpolated); } - // Error handling validation (via checkTopLevelErrorHandling) happens after + // Error handling validation (via checkTopLevelEffects) happens after // type checking. If an unchecked expression is still around, the code was // invalid. #define UNCHECKED_EXPR(KIND, BASE) \ @@ -253,7 +253,7 @@ class ErrorHandlingWalker : public ASTWalker { }; /// A potential reason why something might throw. -class PotentialReason { +class PotentialThrowReason { public: enum class Kind : uint8_t { /// The function throws unconditionally. @@ -275,21 +275,21 @@ class PotentialReason { Expr *TheExpression; Kind TheKind; - explicit PotentialReason(Kind kind) : TheKind(kind) {} + explicit PotentialThrowReason(Kind kind) : TheKind(kind) {} public: - static PotentialReason forRethrowsArgument(Expr *E) { - PotentialReason result(Kind::CallRethrowsWithExplicitThrowingArgument); + static PotentialThrowReason forRethrowsArgument(Expr *E) { + PotentialThrowReason result(Kind::CallRethrowsWithExplicitThrowingArgument); result.TheExpression = E; return result; } - static PotentialReason forDefaultArgument() { - return PotentialReason(Kind::CallRethrowsWithDefaultThrowingArgument); + static PotentialThrowReason forDefaultArgument() { + return PotentialThrowReason(Kind::CallRethrowsWithDefaultThrowingArgument); } - static PotentialReason forThrowingApply() { - return PotentialReason(Kind::CallThrows); + static PotentialThrowReason forThrowingApply() { + return PotentialThrowReason(Kind::CallThrows); } - static PotentialReason forThrow() { - return PotentialReason(Kind::Throw); + static PotentialThrowReason forThrow() { + return PotentialThrowReason(Kind::Throw); } Kind getKind() const { return TheKind; } @@ -321,16 +321,16 @@ enum class ThrowingKind { }; /// A type expressing the result of classifying whether a call or function -/// throws. +/// throws or is async. class Classification { bool IsInvalid = false; // The AST is malformed. Don't diagnose. bool IsAsync = false; ThrowingKind Result = ThrowingKind::None; - Optional Reason; + Optional Reason; public: Classification() : Result(ThrowingKind::None) {} - explicit Classification(ThrowingKind result, PotentialReason reason, + explicit Classification(ThrowingKind result, PotentialThrowReason reason, bool isAsync) : IsAsync(isAsync), Result(result) { if (result == ThrowingKind::Throws || @@ -341,7 +341,7 @@ class Classification { /// Return a classification saying that there's an unconditional /// throw site. - static Classification forThrow(PotentialReason reason, bool isAsync) { + static Classification forThrow(PotentialThrowReason reason, bool isAsync) { Classification result; result.Result = ThrowingKind::Throws; result.Reason = reason; @@ -363,7 +363,7 @@ class Classification { return result; } - static Classification forRethrowingOnly(PotentialReason reason) { + static Classification forRethrowingOnly(PotentialThrowReason reason) { Classification result; result.Result = ThrowingKind::RethrowingOnly; result.Reason = reason; @@ -378,7 +378,7 @@ class Classification { bool isInvalid() const { return IsInvalid; } ThrowingKind getResult() const { return Result; } - PotentialReason getThrowsReason() const { + PotentialThrowReason getThrowsReason() const { assert(getResult() == ThrowingKind::Throws || getResult() == ThrowingKind::RethrowingOnly); return *Reason; @@ -446,7 +446,7 @@ class ApplyClassifier { assert(args.size() > fnRef.getNumArgumentsForFullApply() && "partial application was throwing?"); - return Classification::forThrow(PotentialReason::forThrowingApply(), + return Classification::forThrow(PotentialThrowReason::forThrowingApply(), isAsync); } @@ -476,7 +476,7 @@ class ApplyClassifier { // Try to classify the implementation of functions that we have // local knowledge of. Classification result = - classifyThrowingFunctionBody(fnRef, PotentialReason::forThrowingApply()); + classifyThrowingFunctionBody(fnRef, PotentialThrowReason::forThrowingApply()); assert(result.getResult() != ThrowingKind::None && "body classification decided function was no-throw"); @@ -496,7 +496,7 @@ class ApplyClassifier { /// if the function is an autoclosure that simply doesn't throw at all. Classification classifyThrowingFunctionBody(const AbstractFunction &fn, - PotentialReason reason) { + PotentialThrowReason reason) { // If we're not checking a 'rethrows' context, we don't need to // distinguish between 'throws' and 'rethrows'. But don't even // trust 'throws' for autoclosures. @@ -517,7 +517,7 @@ class ApplyClassifier { } Classification classifyThrowingParameterBody(ParamDecl *param, - PotentialReason reason) { + PotentialThrowReason reason) { assert(param->getType() ->lookThroughAllOptionalTypes() ->castTo() @@ -542,7 +542,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractFunctionDecl *fn, - PotentialReason reason) { + PotentialThrowReason reason) { // Functions can't be rethrowing-only unless they're defined // within the rethrows context. if (!isLocallyDefinedInRethrowsContext(fn) || !fn->hasBody()) @@ -556,7 +556,7 @@ class ApplyClassifier { } Classification classifyThrowingFunctionBody(AbstractClosureExpr *closure, - PotentialReason reason) { + PotentialThrowReason reason) { bool isAutoClosure = isa(closure); // Closures can't be rethrowing-only unless they're defined @@ -580,7 +580,7 @@ class ApplyClassifier { } class FunctionBodyClassifier - : public ErrorHandlingWalker { + : public EffectsHandlingWalker { ApplyClassifier &Self; public: bool IsInvalid = false; @@ -705,7 +705,7 @@ class ApplyClassifier { if (isa(arg)) { return classifyArgumentByType(arg->getType(), - PotentialReason::forDefaultArgument()); + PotentialThrowReason::forDefaultArgument()); } // If this argument is `nil` literal, it doesn't cause the call to throw. @@ -736,7 +736,7 @@ class ApplyClassifier { // parameter type included a throwing function type. return classifyArgumentByType( paramType, - PotentialReason::forRethrowsArgument(arg)); + PotentialThrowReason::forRethrowsArgument(arg)); } // FIXME: There's a case where we can end up with an ApplyExpr that @@ -751,7 +751,7 @@ class ApplyClassifier { if (!paramFnType || !paramFnType->isThrowing()) return Classification(); - PotentialReason reason = PotentialReason::forRethrowsArgument(arg); + PotentialThrowReason reason = PotentialThrowReason::forRethrowsArgument(arg); // TODO: partial applications? @@ -793,7 +793,7 @@ class ApplyClassifier { /// a throwing function in a way that is permitted to cause a /// 'rethrows' function to throw. static Classification classifyArgumentByType(Type paramType, - PotentialReason reason) { + PotentialThrowReason reason) { if (!paramType || paramType->hasError()) return Classification::forInvalidCode(); if (auto fnType = paramType->getAs()) { @@ -816,24 +816,12 @@ class ApplyClassifier { } }; -/// An error-handling context. +/// An context in which effects might be handled. class Context { public: enum class Kind : uint8_t { - /// A context that handles errors. - Handled, - - /// A non-throwing function. - NonThrowingFunction, - - /// A rethrowing function. - RethrowingFunction, - - /// A non-throwing autoclosure. - NonThrowingAutoClosure, - - /// A non-exhaustive catch within a non-throwing function. - NonExhaustiveCatch, + /// A context that potentially handles errors or async calls. + PotentiallyHandled, /// A default argument expression. DefaultArgument, @@ -858,26 +846,6 @@ class Context { }; private: - static Kind getKindForFunctionBody(Type type, unsigned numArgs) { - /// Determine whether calling a function of the specified type with the - /// specified number of arguments would throw. - if (!type) return Kind::Handled; - - assert(numArgs > 0); - while (true) { - auto fnType = type->getAs(); - if (!fnType) return Kind::Handled; - - if (fnType->getExtInfo().isThrowing()) - return Kind::Handled; - - if (--numArgs == 0) - return Kind::NonThrowingFunction; - - type = fnType->getResult(); - } - } - static Context getContextForPatternBinding(PatternBindingDecl *pbd) { if (!pbd->isStatic() && pbd->getDeclContext()->isTypeContext()) { return Context(Kind::IVarInitializer); @@ -887,29 +855,65 @@ class Context { } Kind TheKind; + Optional Function; + bool HandlesErrors = false; + + /// Whether error-handling queries should ignore the function context, e.g., + /// for autoclosure and rethrows checks. + bool ErrorHandlingIgnoresFunction = false; + bool IsNonExhaustiveCatch = false; bool DiagnoseErrorOnTry = false; - DeclContext *RethrowsDC = nullptr; InterpolatedStringLiteralExpr *InterpolatedString = nullptr; - explicit Context(Kind kind) : TheKind(kind) {} + explicit Context(Kind kind) + : TheKind(kind), Function(None), HandlesErrors(false) { + assert(TheKind != Kind::PotentiallyHandled); + } + + explicit Context(bool handlesErrors, Optional function) + : TheKind(Kind::PotentiallyHandled), Function(function), + HandlesErrors(handlesErrors) { } public: - static Context getHandled() { - return Context(Kind::Handled); + /// Whether this is a function that rethrows. + bool isRethrows() const { + if (!HandlesErrors) + return false; + + if (ErrorHandlingIgnoresFunction) + return false; + + if (!Function) + return false; + + auto fn = Function->getAbstractFunctionDecl(); + if (!fn) + return false; + + return fn->getAttrs().hasAttribute(); + } + + /// Whether this is an autoclosure. + bool isAutoClosure() const { + if (!Function) + return false; + + if (ErrorHandlingIgnoresFunction) + return false; + + auto closure = Function->getAbstractClosureExpr(); + if (!closure) + return false; + + return isa(closure); } static Context forTopLevelCode(TopLevelCodeDecl *D) { - // Top-level code implicitly handles errors. - return Context(Kind::Handled); + // Top-level code implicitly handles errors and 'async' calls. + return Context(/*handlesErrors=*/true, None); } static Context forFunction(AbstractFunctionDecl *D) { - if (D->getAttrs().hasAttribute()) { - Context result(Kind::RethrowingFunction); - result.RethrowsDC = D; - return result; - } - // HACK: If the decl is the synthesized getter for a 'lazy' property, then // treat the context as a property initializer in order to produce a better // diagnostic; the only code we should be diagnosing on is within the @@ -926,8 +930,8 @@ class Context { } } - return Context(getKindForFunctionBody( - D->getInterfaceType(), D->getNumCurryLevels())); + bool handlesErrors = D->hasThrows(); + return Context(handlesErrors, AnyFunctionRef(D)); } static Context forDeferBody() { @@ -950,14 +954,14 @@ class Context { } static Context forClosure(AbstractClosureExpr *E) { - auto kind = getKindForFunctionBody(E->getType(), 1); - if (kind != Kind::Handled && isa(E)) - kind = Kind::NonThrowingAutoClosure; - return Context(kind); - } + // Determine whether the closure has throwing function type. + bool closureTypeThrows = true; + if (auto closureType = E->getType()) { + if (auto fnType = closureType->getAs()) + closureTypeThrows = fnType->isThrowing(); + } - static Context forNonExhaustiveCatch(DoCatchStmt *S) { - return Context(Kind::NonExhaustiveCatch); + return Context(closureTypeThrows, AnyFunctionRef(E)); } static Context forCatchPattern(CaseStmt *S) { @@ -978,11 +982,19 @@ class Context { return copy; } + /// Form a subcontext that handles all errors, e.g., for the body of a + /// do-catch with exhaustive catch clauses. + Context withHandlesErrors() const { + Context copy = *this; + copy.HandlesErrors = true; + copy.ErrorHandlingIgnoresFunction = true; + return copy; + } + Kind getKind() const { return TheKind; } bool handlesNothing() const { - return getKind() != Kind::Handled && - getKind() != Kind::RethrowingFunction; + return !HandlesErrors; } bool handles(ThrowingKind errorKind) const { switch (errorKind) { @@ -991,49 +1003,59 @@ class Context { // A call that's rethrowing-only can be handled by 'rethrows'. case ThrowingKind::RethrowingOnly: - return !handlesNothing(); + return HandlesErrors; // An operation that always throws can only be handled by an // all-handling context. case ThrowingKind::Throws: - return getKind() == Kind::Handled; + return HandlesErrors && !isRethrows(); } llvm_unreachable("bad error kind"); } - DeclContext *getRethrowsDC() const { return RethrowsDC; } + DeclContext *getRethrowsDC() const { + if (!isRethrows()) + return nullptr; + + return Function->getAbstractFunctionDecl(); + } + InterpolatedStringLiteralExpr * getInterpolatedString() const { return InterpolatedString; } + void setNonExhaustiveCatch(bool value) { + IsNonExhaustiveCatch = value; + } + static void diagnoseThrowInIllegalContext(DiagnosticEngine &Diags, ASTNode node, - StringRef description) { + Kind kind) { if (auto *e = node.dyn_cast()) { if (isa(e)) { Diags.diagnose(e->getLoc(), diag::throwing_call_in_illegal_context, - description); + static_cast(kind)); return; } } Diags.diagnose(node.getStartLoc(), diag::throw_in_illegal_context, - description); + static_cast(kind)); } static void maybeAddRethrowsNote(DiagnosticEngine &Diags, SourceLoc loc, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (reason.getKind()) { - case PotentialReason::Kind::Throw: + case PotentialThrowReason::Kind::Throw: llvm_unreachable("should already have been covered"); - case PotentialReason::Kind::CallThrows: + case PotentialThrowReason::Kind::CallThrows: // Already fully diagnosed. return; - case PotentialReason::Kind::CallRethrowsWithExplicitThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithExplicitThrowingArgument: Diags.diagnose(reason.getThrowingArgument()->getLoc(), diag::because_rethrows_argument_throws); return; - case PotentialReason::Kind::CallRethrowsWithDefaultThrowingArgument: + case PotentialThrowReason::Kind::CallRethrowsWithDefaultThrowingArgument: Diags.diagnose(loc, diag::because_rethrows_default_argument_throws); return; } @@ -1041,7 +1063,7 @@ class Context { } void diagnoseUncoveredThrowSite(ASTContext &ctx, ASTNode E, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { auto &Diags = ctx.Diags; auto message = diag::throwing_call_without_try; auto loc = E.getStartLoc(); @@ -1077,7 +1099,7 @@ class Context { // // Let's suggest couple of alternative fix-its // because complete context is unavailable. - if (reason.getKind() != PotentialReason::Kind::CallThrows) + if (reason.getKind() != PotentialThrowReason::Kind::CallThrows) return; Diags.diagnose(loc, diag::note_forgot_try) @@ -1090,7 +1112,7 @@ class Context { void diagnoseThrowInLegalContext(DiagnosticEngine &Diags, ASTNode node, bool isTryCovered, - const PotentialReason &reason, + const PotentialThrowReason &reason, Diag<> diagForThrow, Diag<> diagForThrowingCall, Diag<> diagForTrylessThrowingCall) { @@ -1103,8 +1125,7 @@ class Context { // Allow the diagnostic to fire on the 'try' if we don't have // anything else to say. if (isTryCovered && !reason.isRethrowsCall() && - (getKind() == Kind::NonThrowingFunction || - getKind() == Kind::NonExhaustiveCatch)) { + !isRethrows() && !isAutoClosure()) { DiagnoseErrorOnTry = true; return; } @@ -1119,91 +1140,64 @@ class Context { void diagnoseUnhandledThrowSite(DiagnosticEngine &Diags, ASTNode E, bool isTryCovered, - const PotentialReason &reason) { + const PotentialThrowReason &reason) { switch (getKind()) { - case Kind::Handled: - llvm_unreachable("throw site is handled!"); + case Kind::PotentiallyHandled: + if (IsNonExhaustiveCatch) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonexhaustive_catch, + diag::throwing_call_in_nonexhaustive_catch, + diag::tryless_throwing_call_in_nonexhaustive_catch); + return; + } - // TODO: Doug suggested that we could generate one error per - // non-throwing function with throw sites within it, possibly with - // notes for the throw sites. + if (isAutoClosure()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_nonthrowing_autoclosure, + diag::throwing_call_in_nonthrowing_autoclosure, + diag::tryless_throwing_call_in_nonthrowing_autoclosure); + return; + } - case Kind::RethrowingFunction: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_rethrows_function, - diag::throwing_call_in_rethrows_function, - diag::tryless_throwing_call_in_rethrows_function); - return; + if (isRethrows()) { + diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, + diag::throw_in_rethrows_function, + diag::throwing_call_in_rethrows_function, + diag::tryless_throwing_call_in_rethrows_function); + return; + } - case Kind::NonThrowingFunction: diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, diag::throw_in_nonthrowing_function, diag::throwing_call_unhandled, diag::tryless_throwing_call_unhandled); return; - case Kind::NonThrowingAutoClosure: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonthrowing_autoclosure, - diag::throwing_call_in_nonthrowing_autoclosure, - diag::tryless_throwing_call_in_nonthrowing_autoclosure); - return; - - case Kind::NonExhaustiveCatch: - diagnoseThrowInLegalContext(Diags, E, isTryCovered, reason, - diag::throw_in_nonexhaustive_catch, - diag::throwing_call_in_nonexhaustive_catch, - diag::tryless_throwing_call_in_nonexhaustive_catch); - return; - case Kind::EnumElementInitializer: - diagnoseThrowInIllegalContext(Diags, E, "an enum case raw value"); - return; - case Kind::GlobalVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a global variable initializer"); - return; - case Kind::IVarInitializer: - diagnoseThrowInIllegalContext(Diags, E, "a property initializer"); - return; - case Kind::DefaultArgument: - diagnoseThrowInIllegalContext(Diags, E, "a default argument"); - return; - case Kind::CatchPattern: - diagnoseThrowInIllegalContext(Diags, E, "a catch pattern"); - return; - case Kind::CatchGuard: - diagnoseThrowInIllegalContext(Diags, E, "a catch guard expression"); - return; case Kind::DeferBody: - diagnoseThrowInIllegalContext(Diags, E, "a defer body"); + diagnoseThrowInIllegalContext(Diags, E, getKind()); return; + } llvm_unreachable("bad context kind"); } void diagnoseUnhandledTry(DiagnosticEngine &Diags, TryExpr *E) { switch (getKind()) { - case Kind::Handled: - case Kind::RethrowingFunction: - llvm_unreachable("try is handled!"); - - case Kind::NonThrowingFunction: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), diag::try_unhandled); - return; - - case Kind::NonExhaustiveCatch: - if (DiagnoseErrorOnTry) - Diags.diagnose(E->getTryLoc(), - diag::try_unhandled_in_nonexhaustive_catch); + case Kind::PotentiallyHandled: + if (DiagnoseErrorOnTry) { + Diags.diagnose( + E->getTryLoc(), + IsNonExhaustiveCatch ? diag::try_unhandled_in_nonexhaustive_catch + : diag::try_unhandled); + } return; - case Kind::NonThrowingAutoClosure: case Kind::EnumElementInitializer: case Kind::GlobalVarInitializer: case Kind::IVarInitializer: @@ -1221,13 +1215,12 @@ class Context { /// A class to walk over a local context and validate the correctness /// of its error coverage. -class CheckErrorCoverage : public ErrorHandlingWalker { - friend class ErrorHandlingWalker; +class CheckEffectsCoverage : public EffectsHandlingWalker { + friend class EffectsHandlingWalker; ASTContext &Ctx; - ApplyClassifier Classifier; - + DeclContext *RethrowsDC = nullptr; Context CurContext; class ContextFlags { @@ -1288,15 +1281,15 @@ class CheckErrorCoverage : public ErrorHandlingWalker { /// An RAII object for restoring all the interesting state in an /// error-coverage. class ContextScope { - CheckErrorCoverage &Self; + CheckEffectsCoverage &Self; Context OldContext; DeclContext *OldRethrowsDC; ContextFlags OldFlags; ThrowingKind OldMaxThrowingKind; public: - ContextScope(CheckErrorCoverage &self, Optional newContext) + ContextScope(CheckEffectsCoverage &self, Optional newContext) : Self(self), OldContext(self.CurContext), - OldRethrowsDC(self.Classifier.RethrowsDC), + OldRethrowsDC(self.RethrowsDC), OldFlags(self.Flags), OldMaxThrowingKind(self.MaxThrowingKind) { if (newContext) self.CurContext = *newContext; @@ -1306,7 +1299,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ContextScope &operator=(const ContextScope &) = delete; void enterSubFunction() { - Self.Classifier.RethrowsDC = nullptr; + Self.RethrowsDC = nullptr; } void enterTry() { @@ -1372,19 +1365,19 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ~ContextScope() { Self.CurContext = OldContext; - Self.Classifier.RethrowsDC = OldRethrowsDC; + Self.RethrowsDC = OldRethrowsDC; Self.Flags = OldFlags; Self.MaxThrowingKind = OldMaxThrowingKind; } }; public: - CheckErrorCoverage(ASTContext &ctx, Context initialContext) + CheckEffectsCoverage(ASTContext &ctx, Context initialContext) : Ctx(ctx), CurContext(initialContext), MaxThrowingKind(ThrowingKind::None) { if (auto rethrowsDC = initialContext.getRethrowsDC()) { - Classifier.RethrowsDC = rethrowsDC; + RethrowsDC = rethrowsDC; } } @@ -1422,8 +1415,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { } ThrowingKind checkExhaustiveDoBody(DoCatchStmt *S) { - // This is a handled context. - ContextScope scope(*this, Context::getHandled()); + // This is a context where errors are handled. + ContextScope scope(*this, CurContext.withHandlesErrors()); assert(!Flags.has(ContextFlags::IsInTry) && "do/catch within try?"); scope.resetCoverageForDoCatch(); @@ -1442,7 +1435,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // If the enclosing context doesn't handle anything, use a // specialized diagnostic about non-exhaustive catches. if (CurContext.handlesNothing()) { - scope.refineLocalContext(Context::forNonExhaustiveCatch(S)); + CurContext.setNonExhaustiveCatch(true); } S->getBody()->walk(*this); @@ -1478,11 +1471,11 @@ class CheckErrorCoverage : public ErrorHandlingWalker { auto savedContext = CurContext; if (doThrowingKind != ThrowingKind::Throws && - CurContext.getKind() == Context::Kind::RethrowingFunction) { + CurContext.isRethrows()) { // If this catch clause is reachable at all, it's because a function - // parameter throws. So let's temporarily set our context to Handled so - // the catch body is allowed to throw. - CurContext = Context::getHandled(); + // parameter throws. So let's temporarily state that the body is allowed + // to throw. + CurContext = CurContext.withHandlesErrors(); } // The catch body just happens in the enclosing context. @@ -1494,7 +1487,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkApply(ApplyExpr *E) { // An apply expression is a potential throw site if the function throws. // But if the expression didn't type-check, suppress diagnostics. - auto classification = Classifier.classifyApply(E); + ApplyClassifier classifier; + classifier.RethrowsDC = RethrowsDC; + auto classification = classifier.classifyApply(E); checkThrowAsyncSite(E, /*requiresTry*/ true, classification); @@ -1528,8 +1523,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker { // Check the inactive regions of a #if block to disable warnings that may // be due to platform specific code. struct ConservativeThrowChecker : public ASTWalker { - CheckErrorCoverage &CEC; - ConservativeThrowChecker(CheckErrorCoverage &CEC) : CEC(CEC) {} + CheckEffectsCoverage &CEC; + ConservativeThrowChecker(CheckEffectsCoverage &CEC) : CEC(CEC) {} Expr *walkToExprPost(Expr *E) override { if (isa(E)) @@ -1557,7 +1552,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkThrow(ThrowStmt *S) { checkThrowAsyncSite(S, /*requiresTry*/ false, - Classification::forThrow(PotentialReason::forThrow(), + Classification::forThrow(PotentialThrowReason::forThrow(), /*async*/false)); return ShouldRecurse; } @@ -1665,7 +1660,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkForceTry(ForceTryExpr *E) { // Walk the operand. 'try!' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1679,7 +1674,7 @@ class CheckErrorCoverage : public ErrorHandlingWalker { ShouldRecurse_t checkOptionalTry(OptionalTryExpr *E) { // Walk the operand. 'try?' handles errors. - ContextScope scope(*this, Context::getHandled()); + ContextScope scope(*this, CurContext.withHandlesErrors()); scope.enterTry(); E->getSubExpr()->walk(*this); @@ -1694,9 +1689,9 @@ class CheckErrorCoverage : public ErrorHandlingWalker { } // end anonymous namespace -void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { +void TypeChecker::checkTopLevelEffects(TopLevelCodeDecl *code) { auto &ctx = code->getDeclContext()->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forTopLevelCode(code)); + CheckEffectsCoverage checker(ctx, Context::forTopLevelCode(code)); // In some language modes, we allow top-level code to omit 'try' marking. if (ctx.LangOpts.EnableThrowWithoutTry) @@ -1705,16 +1700,16 @@ void TypeChecker::checkTopLevelErrorHandling(TopLevelCodeDecl *code) { code->getBody()->walk(checker); } -void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { +void TypeChecker::checkFunctionEffects(AbstractFunctionDecl *fn) { #ifndef NDEBUG - PrettyStackTraceDecl debugStack("checking error handling for", fn); + PrettyStackTraceDecl debugStack("checking effects handling for", fn); #endif auto isDeferBody = isa(fn) && cast(fn)->isDeferBody(); auto context = isDeferBody ? Context::forDeferBody() : Context::forFunction(fn); auto &ctx = fn->getASTContext(); - CheckErrorCoverage checker(ctx, context); + CheckEffectsCoverage checker(ctx, context); // If this is a debugger function, suppress 'try' marking at the top level. if (fn->getAttrs().hasAttribute()) @@ -1728,14 +1723,14 @@ void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) { superInit->walk(checker); } -void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, +void TypeChecker::checkInitializerEffects(Initializer *initCtx, Expr *init) { auto &ctx = initCtx->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forInitializer(initCtx)); + CheckEffectsCoverage checker(ctx, Context::forInitializer(initCtx)); init->walk(checker); } -/// Check the correctness of error handling within the given enum +/// Check the correctness of effects within the given enum /// element's raw value expression. /// /// The syntactic restrictions on such expressions should make it @@ -1743,15 +1738,15 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx, /// ensures correctness if those restrictions are ever loosened, /// perhaps accidentally, and (2) allows the verifier to assert that /// all calls have been checked. -void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt, Expr *E) { +void TypeChecker::checkEnumElementEffects(EnumElementDecl *elt, Expr *E) { auto &ctx = elt->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forEnumElementInitializer(elt)); + CheckEffectsCoverage checker(ctx, Context::forEnumElementInitializer(elt)); E->walk(checker); } -void TypeChecker::checkPropertyWrapperErrorHandling( +void TypeChecker::checkPropertyWrapperEffects( PatternBindingDecl *binding, Expr *expr) { auto &ctx = binding->getASTContext(); - CheckErrorCoverage checker(ctx, Context::forPatternBinding(binding)); + CheckEffectsCoverage checker(ctx, Context::forPatternBinding(binding)); expr->walk(checker); } diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index 8fcd77a4de05c..324e044ce1a75 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -221,6 +221,7 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, case KeyPathExpr::Component::Kind::OptionalWrap: case KeyPathExpr::Component::Kind::Property: case KeyPathExpr::Component::Kind::Subscript: + case KeyPathExpr::Component::Kind::DictionaryKey: llvm_unreachable("already resolved!"); } @@ -241,6 +242,9 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, // From here, we're resolving a property. Use the current type. updateState(/*isProperty=*/true, currentType); + auto resolved = KeyPathExpr::Component:: + forDictionaryKey(componentName, currentType, componentNameLoc); + resolvedComponents.push_back(resolved); continue; } @@ -321,10 +325,14 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, if (auto var = dyn_cast(found)) { // Resolve this component to the variable we found. auto varRef = ConcreteDeclRef(var); - auto resolved = - KeyPathExpr::Component::forProperty(varRef, Type(), componentNameLoc); + Type varTy = var->getInterfaceType(); + + // Updates currentType + updateState(/*isProperty=*/true, varTy); + + auto resolved = KeyPathExpr::Component::forProperty(varRef, currentType, + componentNameLoc); resolvedComponents.push_back(resolved); - updateState(/*isProperty=*/true, var->getInterfaceType()); // Check that the property is @objc. if (!var->isObjC()) { @@ -390,7 +398,15 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, break; } + // Updates currentType based on newType. updateState(/*isProperty=*/false, newType); + + // Resolve this component to the type we found. + auto typeRef = ConcreteDeclRef(type); + auto resolved = KeyPathExpr::Component::forProperty(typeRef, currentType, + componentNameLoc); + resolvedComponents.push_back(resolved); + continue; } diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 91fe6781d56ef..6a5ec66b76cb1 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -467,26 +467,31 @@ class ResolvePattern : public ASTVisitorgetBase())) return nullptr; - auto *const repr = IdentTypeRepr::create(Context, components); + const auto options = + TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors; - // See first if the repr unambiguously references an enum declaration. - bool anyObject = false; - const auto &referencedDecls = - getDirectlyReferencedNominalTypeDecls(Context, repr, DC, anyObject); - if (referencedDecls.size() != 1) - return nullptr; + auto *repr = IdentTypeRepr::create(Context, components); - auto *const enumDecl = dyn_cast(referencedDecls.front()); + // See if the repr resolves to a type. + const auto resolution = + TypeResolution::forContextual(DC, options, [](auto unboundTy) { + // FIXME: Don't let unbound generic types escape type resolution. + // For now, just return the unbound generic type. + return unboundTy; + }); + const auto ty = resolution.resolveType(repr); + auto *enumDecl = dyn_cast_or_null(ty->getAnyNominal()); if (!enumDecl) return nullptr; - EnumElementDecl *referencedElement = - lookupEnumMemberElement(DC, enumDecl->getDeclaredInterfaceType(), - ude->getName(), ude->getLoc()); + EnumElementDecl *referencedElement + = lookupEnumMemberElement(DC, ty, ude->getName(), ude->getLoc()); if (!referencedElement) return nullptr; - auto *const base = new (Context) TypeExpr(repr); + auto *base = + TypeExpr::createForMemberDecl(repr, ude->getNameLoc(), enumDecl); + base->setType(MetatypeType::get(ty)); return new (Context) EnumElementPattern(base, ude->getDotLoc(), ude->getNameLoc(), ude->getName(), referencedElement, nullptr); @@ -564,31 +569,37 @@ class ResolvePattern : public ASTVisitorgetDeclaredTypeInContext(), Context); } else { + const auto options = + TypeResolutionOptions(None) | TypeResolutionFlags::SilenceErrors; + // Otherwise, see whether we had an enum type as the penultimate // component, and look up an element inside it. - auto *const prefixRepr = IdentTypeRepr::create(Context, components); - - // See first if the repr unambiguously references an enum declaration. - bool anyObject = false; - const auto &referencedDecls = getDirectlyReferencedNominalTypeDecls( - Context, prefixRepr, DC, anyObject); - if (referencedDecls.size() != 1) - return nullptr; - - auto *const enumDecl = dyn_cast(referencedDecls.front()); + auto *prefixRepr = IdentTypeRepr::create(Context, components); + + // See first if the entire repr resolves to a type. + const Type enumTy = + TypeResolution::forContextual(DC, options, [](auto unboundTy) { + // FIXME: Don't let unbound generic types escape type resolution. + // For now, just return the unbound generic type. + return unboundTy; + }).resolveType(prefixRepr); + auto *enumDecl = dyn_cast_or_null(enumTy->getAnyNominal()); if (!enumDecl) return nullptr; - referencedElement = lookupEnumMemberElement( - DC, enumDecl->getDeclaredInterfaceType(), tailComponent->getNameRef(), - tailComponent->getLoc()); + referencedElement + = lookupEnumMemberElement(DC, enumTy, + tailComponent->getNameRef(), + tailComponent->getLoc()); if (!referencedElement) return nullptr; - baseTE = new (Context) TypeExpr(prefixRepr); + baseTE = TypeExpr::createForMemberDecl( + prefixRepr, tailComponent->getNameLoc(), enumDecl); + baseTE->setType(MetatypeType::get(enumTy)); } - assert(baseTE && "Didn't initialize base expression?"); + assert(baseTE && baseTE->getType() && "Didn't initialize base expression?"); assert(!isa(tailComponent) && "should be handled above"); @@ -1426,25 +1437,11 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern, enumTy = type; } else { - // Validate the parent type if we haven't done so yet. - if (EEP->getParentType().isNull()) { - const auto resolution = - TypeResolution::forContextual(dc, options, [](auto unboundTy) { - // FIXME: Don't let unbound generic types escape type resolution. - // For now, just return the unbound generic type. - return unboundTy; - }); - const auto ty = resolution.resolveType(EEP->getParentTypeRepr()); - EEP->setParentType(ty); - - if (ty->hasError()) { - return nullptr; - } - } - // Check if the explicitly-written enum type matches the type we're // coercing to. - const Type parentTy = EEP->getParentType(); + assert(!EEP->getParentType().isNull() + && "enum with resolved element doesn't specify parent type?!"); + auto parentTy = EEP->getParentType(); // If the type matches exactly, use it. if (parentTy->isEqual(type)) { enumTy = type; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index a13a8094d2599..8d94d9da4e941 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5717,8 +5717,6 @@ TypeChecker::deriveTypeWitness(DeclContext *DC, switch (*knownKind) { case KnownProtocolKind::RawRepresentable: return std::make_pair(derived.deriveRawRepresentable(AssocType), nullptr); - case KnownProtocolKind::CaseIterable: - return std::make_pair(derived.deriveCaseIterable(AssocType), nullptr); case KnownProtocolKind::Differentiable: return derived.deriveDifferentiable(AssocType); // SWIFT_ENABLE_TENSORFLOW diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index fb9eda0f8947f..21fe9d350ff71 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -805,25 +805,31 @@ Type AssociatedTypeInference::computeFixedTypeWitness( AssociatedTypeDecl *assocType) { // Look at all of the inherited protocols to determine whether they // require a fixed type for this associated type. - Type dependentType = assocType->getDeclaredInterfaceType(); Type resultType; for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) { - if (!conformedProto->inheritsFrom(assocType->getProtocol())) + if (conformedProto != assocType->getProtocol() && + !conformedProto->inheritsFrom(assocType->getProtocol())) continue; - auto genericSig = conformedProto->getGenericSignature(); + const auto genericSig = conformedProto->getGenericSignature(); if (!genericSig) return Type(); - Type concreteType = genericSig->getConcreteType(dependentType); - if (!concreteType) continue; + const auto nestedType = genericSig->getCanonicalTypeInContext( + DependentMemberType::get(conformedProto->getSelfInterfaceType(), + assocType->getName())); + if (nestedType->isEqual(conformedProto->getSelfInterfaceType())) { + // Self is a valid fixed type witness. + } else if (nestedType->isTypeParameter()) { + continue; + } if (!resultType) { - resultType = concreteType; + resultType = nestedType; continue; } // FIXME: Bailing out on ambiguity. - if (!resultType->isEqual(concreteType)) + if (!resultType->isEqual(nestedType)) return Type(); } @@ -887,7 +893,7 @@ AssociatedTypeInference::computeAbstractTypeWitness( return AbstractTypeWitness::forFixed(assocType, concreteType); // If we can form a default type, do so. - if (auto typeWitness = computeDefaultTypeWitness(assocType)) + if (const auto &typeWitness = computeDefaultTypeWitness(assocType)) return typeWitness; // If there is a generic parameter of the named type, use that. diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 6ff98713a9fe8..507b87edfee13 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -1698,7 +1698,7 @@ static Type getFunctionBuilderType(FuncDecl *FD) { bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) { auto res = evaluateOrDefault(AFD->getASTContext().evaluator, TypeCheckFunctionBodyRequest{AFD}, true); - TypeChecker::checkFunctionErrorHandling(AFD); + TypeChecker::checkFunctionEffects(AFD); TypeChecker::computeCaptures(AFD); // SWIFT_ENABLE_TENSORFLOW // Check `@compilerEvaluable` function body correctness. @@ -2159,7 +2159,7 @@ void TypeChecker::typeCheckTopLevelCodeDecl(TopLevelCodeDecl *TLCD) { BraceStmt *Body = TLCD->getBody(); StmtChecker(TLCD).typeCheckStmt(Body); TLCD->setBody(Body); - checkTopLevelErrorHandling(TLCD); + checkTopLevelEffects(TLCD); performTopLevelDeclDiagnostics(TLCD); } diff --git a/lib/Sema/TypeCheckStorage.cpp b/lib/Sema/TypeCheckStorage.cpp index eca917211a065..01c82f7583890 100644 --- a/lib/Sema/TypeCheckStorage.cpp +++ b/lib/Sema/TypeCheckStorage.cpp @@ -2491,7 +2491,7 @@ static void typeCheckSynthesizedWrapperInitializer( dyn_cast_or_null(pbd->getInitContext(i))) { TypeChecker::contextualizeInitializer(initializerContext, initializer); } - TypeChecker::checkPropertyWrapperErrorHandling(pbd, initializer); + TypeChecker::checkPropertyWrapperEffects(pbd, initializer); } static PropertyWrapperMutability::Value diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index d89241b7d2122..b52dfd6c63e82 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1147,11 +1147,11 @@ void diagnoseIfDeprecated(SourceRange SourceRange, void checkForForbiddenPrefix(ASTContext &C, DeclBaseName Name); /// Check error handling in the given type-checked top-level code. -void checkTopLevelErrorHandling(TopLevelCodeDecl *D); -void checkFunctionErrorHandling(AbstractFunctionDecl *D); -void checkInitializerErrorHandling(Initializer *I, Expr *E); -void checkEnumElementErrorHandling(EnumElementDecl *D, Expr *expr); -void checkPropertyWrapperErrorHandling(PatternBindingDecl *binding, +void checkTopLevelEffects(TopLevelCodeDecl *D); +void checkFunctionEffects(AbstractFunctionDecl *D); +void checkInitializerEffects(Initializer *I, Expr *E); +void checkEnumElementEffects(EnumElementDecl *D, Expr *expr); +void checkPropertyWrapperEffects(PatternBindingDecl *binding, Expr *expr); void checkFunctionBodyCompilerEvaluable(AbstractFunctionDecl *D); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 8e4d8fa7f0b87..ddbc8f9a513d0 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -2006,7 +2006,8 @@ ModuleDecl *ModuleFile::getModule(ModuleID MID) { llvm_unreachable("implementation detail only"); } } - return getModule(getIdentifier(MID)); + return getModule(getIdentifier(MID), + getContext().LangOpts.AllowDeserializingImplementationOnly); } ModuleDecl *ModuleFile::getModule(ArrayRef name, diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 86565d2ee9314..97c84001d009c 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -53,7 +53,6 @@ fromStableStringEncoding(unsigned value) { switch (value) { case SIL_BYTES: return StringLiteralInst::Encoding::Bytes; case SIL_UTF8: return StringLiteralInst::Encoding::UTF8; - case SIL_UTF16: return StringLiteralInst::Encoding::UTF16; case SIL_OBJC_SELECTOR: return StringLiteralInst::Encoding::ObjCSelector; default: return None; } @@ -511,14 +510,14 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, specialPurpose, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, @@ -627,6 +626,11 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, MF->fatal(); } + if (fn->isAsync() != isAsync) { + LLVM_DEBUG(llvm::dbgs() << "SILFunction type mismatch.\n"); + MF->fatal(); + } + } else { // Otherwise, create a new function. fn = builder.createDeclaration(name, ty, loc); @@ -635,6 +639,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setSerialized(IsSerialized_t(isSerialized)); fn->setThunk(IsThunk_t(isThunk)); fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk)); + fn->setAsync((bool)isAsync); fn->setInlineStrategy(Inline_t(inlineStrategy)); fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose)); fn->setEffectsKind(EffectsKind(effect)); @@ -2824,14 +2829,14 @@ bool SILDeserializer::hasSILFunction(StringRef Name, IdentifierID replacedFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutactuallyEscapingThunk, isAsync, isGlobal, inlineStrategy, optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), isDynamic, isExactSelfClass, diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 351721a916022..b3a7a893f0932 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -55,7 +55,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 566; // async +const uint16_t SWIFTMODULE_VERSION_MINOR = 568; // removed UTF16 /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index ec16f5e92b975..dfa1ea155b886 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -31,7 +31,6 @@ using SILTypeCategoryField = BCFixed<2>; enum SILStringEncoding : uint8_t { SIL_UTF8, - SIL_UTF16, SIL_OBJC_SELECTOR, SIL_BYTES }; @@ -278,6 +277,7 @@ namespace sil_block { BCFixed<2>, // serialized BCFixed<2>, // thunks: signature optimized/reabstraction BCFixed<1>, // without_actually_escaping + BCFixed<1>, // async BCFixed<3>, // specialPurpose BCFixed<2>, // inlineStrategy BCFixed<2>, // optimizationMode diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 285db801310ff..00e9443213ea0 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -49,7 +49,6 @@ static unsigned toStableStringEncoding(StringLiteralInst::Encoding encoding) { switch (encoding) { case StringLiteralInst::Encoding::Bytes: return SIL_BYTES; case StringLiteralInst::Encoding::UTF8: return SIL_UTF8; - case StringLiteralInst::Encoding::UTF16: return SIL_UTF16; case StringLiteralInst::Encoding::ObjCSelector: return SIL_OBJC_SELECTOR; } llvm_unreachable("bad string encoding"); @@ -434,13 +433,13 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage), (unsigned)F.isTransparent(), (unsigned)F.isSerialized(), (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(), - (unsigned)F.getSpecialPurpose(), (unsigned)F.getInlineStrategy(), - (unsigned)F.getOptimizationMode(), (unsigned)F.getEffectsKind(), - (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), - F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), - (unsigned)F.isDynamicallyReplaceable(), - (unsigned)F.isExactSelfClass(), - FnID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); + (unsigned)F.isAsync(), (unsigned)F.getSpecialPurpose(), + (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(), + (unsigned)F.getEffectsKind(), (unsigned)numSpecAttrs, + (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), + LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), + (unsigned)F.isExactSelfClass(), FnID, replacedFunctionID, genericSigID, + clangNodeOwnerID, SemanticsIDs); if (NoBody) return; diff --git a/localization/CMakeLists.txt b/localization/CMakeLists.txt index 8ef1584ac29b6..764b378f97b44 100644 --- a/localization/CMakeLists.txt +++ b/localization/CMakeLists.txt @@ -1,14 +1,17 @@ -add_custom_target(diagnostic-translation-database) +add_custom_target(diagnostic-database) -add_custom_command( - TARGET diagnostic-translation-database - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS diagnostics - COMMAND "${CMAKE_COMMAND}" -E copy_directory diagnostics/ "${SWIFT_BINARY_DIR}/share/swift/diagnostics/") +add_custom_command(TARGET diagnostic-database + COMMAND + ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/diagnostics/ ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + COMMAND + $ + --input-file-path ${CMAKE_BINARY_DIR}/share/swift/diagnostics/en.yaml + --output-directory ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ +) -add_dependencies(swift-frontend diagnostic-translation-database) +add_dependencies(swift-frontend diagnostic-database) swift_install_in_component( - DIRECTORY diagnostics - DESTINATION "share/swift" + DIRECTORY ${CMAKE_BINARY_DIR}/share/swift/diagnostics/ + DESTINATION "share/swift/diagnostics" COMPONENT compiler) diff --git a/localization/diagnostics/en.yaml b/localization/diagnostics/en.yaml index 466a970fd2f1d..8c3be67b2c0db 100644 --- a/localization/diagnostics/en.yaml +++ b/localization/diagnostics/en.yaml @@ -147,10 +147,10 @@ msg: >- unrecognized accessor kind '%0' in SDK node -- id: pound_source_location_creates_pound_file_conflicts +- id: source_location_creates_file_id_conflicts msg: >- - '#sourceLocation' directive produces '#file' string of '%0', which - conflicts with '#file' strings produced by other paths in the module + '#sourceLocation' directive produces '#fileID' string of '%0', which + conflicts with '#fileID' strings produced by other paths in the module - id: fixit_correct_source_location_file msg: >- @@ -1343,13 +1343,9 @@ only function declarations may be marked 'rethrows'; did you mean 'throws'? -- id: throws_in_wrong_position +- id: async_or_throws_in_wrong_position msg: >- - 'throws' may only occur before '->' - -- id: rethrows_in_wrong_position - msg: >- - 'rethrows' may only occur before '->' + %select{'throws'|'rethrows'|'async'}0 may only occur before '->' - id: throw_in_function_type msg: >- @@ -2971,6 +2967,14 @@ value of type %0 has no property or method named 'subscript'; did you mean to use the subscript operator? +- id: could_not_find_subscript_member_tuple + msg: >- + cannot access element using subscript for tuple type %0; use '.' notation instead + +- id: could_not_find_subscript_member_tuple_did_you_mean_use_dot + msg: >- + cannot access element using subscript for tuple type %0; did you mean to use '.%1'? + - id: could_not_find_enum_case msg: >- enum type %0 has no case %1; did you mean %2? @@ -7132,14 +7136,6 @@ %0 is not a 'func', 'init', 'subscript', or 'var' computed property declaration -- id: autodiff_attr_accessor_not_found - msg: >- - %0 does not have a '%1' accessor - -- id: autodiff_attr_original_decl_none_valid_found - msg: >- - could not find function %0 with expected type %1 - - id: autodiff_attr_original_decl_not_same_type_context msg: >- %0 is not defined in the current type context @@ -9244,11 +9240,21 @@ %select{getter for |setter for |}0%1 is unavailable%select{ in %3|}2%select{|: %4}4 +- id: availability_decl_unavailable_warn + msg: >- + %select{getter for |setter for |}0%1 is unavailable%select{ in + %3|}2%select{|: %4}4 + - id: availability_decl_unavailable_rename msg: >- %select{getter for |setter for |}0%1 has been %select{renamed to|replaced by}2%select{| instance method| property}3 '%4'%select{|: %5}5 +- id: availability_decl_unavailable_rename_warn + msg: >- + %select{getter for |setter for |}0%1 has been %select{renamed to|replaced + by}2%select{| instance method| property}3 '%4'%select{|: %5}5 + - id: availability_marked_unavailable msg: >- %select{getter for |setter for |}0%1 has been explicitly marked diff --git a/stdlib/private/DifferentiationUnittest/CMakeLists.txt b/stdlib/private/DifferentiationUnittest/CMakeLists.txt index bb6284b191310..33da12b9b766a 100644 --- a/stdlib/private/DifferentiationUnittest/CMakeLists.txt +++ b/stdlib/private/DifferentiationUnittest/CMakeLists.txt @@ -1,6 +1,6 @@ add_swift_target_library(swiftDifferentiationUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES} IS_STDLIB # This file should be listed first. Module name is inferred from the filename. - DifferentiationUnittest.swift + GYB_SOURCES DifferentiationUnittest.swift.gyb SWIFT_MODULE_DEPENDS _Differentiation StdlibUnittest INSTALL_IN_COMPONENT stdlib-experimental diff --git a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb similarity index 50% rename from stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift rename to stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb index f24dd18a7925e..282f89f93324f 100644 --- a/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift +++ b/stdlib/private/DifferentiationUnittest/DifferentiationUnittest.swift.gyb @@ -1,4 +1,4 @@ -//===--- DifferentiationUnittest.swift ------------------------------------===// +//===--- DifferentiationUnittest.swift.gyb --------------------------------===// // // This source file is part of the Swift.org open source project // @@ -43,19 +43,21 @@ public extension TestSuite { _ testFunction: @escaping () -> Void ) { test(name, file: file, line: line) { - withLeakChecking(expectedLeakCount: expectedLeakCount, file: file, - line: line, testFunction) + withLeakChecking( + expectedLeakCount: expectedLeakCount, file: file, + line: line, testFunction) } } } -/// A type that tracks the number of live instances of a wrapped value type. +/// A resilient type that tracks the number of live instances of a wrapped +/// value type. /// /// `Tracked` is used to check for memory leaks in functions created via /// automatic differentiation. public struct Tracked { - fileprivate class Box { - fileprivate var value : T + internal class Box { + fileprivate var value: T init(_ value: T) { self.value = value _GlobalLeakCount.count += 1 @@ -64,71 +66,109 @@ public struct Tracked { _GlobalLeakCount.count -= 1 } } - private var handle: Box + internal var handle: Box - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public init(_ value: T) { self.handle = Box(value) } - @differentiable(where T : Differentiable, T == T.TangentVector) + @differentiable(where T: Differentiable, T == T.TangentVector) public var value: T { get { handle.value } set { handle.value = newValue } } } -extension Tracked : ExpressibleByFloatLiteral where T : ExpressibleByFloatLiteral { +/// A non-resilient type that tracks the number of live instances of a wrapped +/// value type. +/// +/// `NonresilientTracked` is used to check for memory leaks in functions +/// created via automatic differentiation. +@frozen +public struct NonresilientTracked { + @usableFromInline + internal class Box { + fileprivate var value: T + init(_ value: T) { + self.value = value + _GlobalLeakCount.count += 1 + } + deinit { + _GlobalLeakCount.count -= 1 + } + } + @usableFromInline + internal var handle: Box + + @differentiable(where T: Differentiable, T == T.TangentVector) + public init(_ value: T) { + self.handle = Box(value) + } + + @differentiable(where T: Differentiable, T == T.TangentVector) + public var value: T { + get { handle.value } + set { handle.value = newValue } + } +} + +% for Self in ['Tracked', 'NonresilientTracked']: + +extension ${Self}: ExpressibleByFloatLiteral +where T: ExpressibleByFloatLiteral { public init(floatLiteral value: T.FloatLiteralType) { self.handle = Box(T(floatLiteral: value)) } } -extension Tracked : CustomStringConvertible { - public var description: String { return "Tracked(\(value))" } +extension ${Self}: CustomStringConvertible { + public var description: String { return "${Self}(\(value))" } } -extension Tracked : ExpressibleByIntegerLiteral where T : ExpressibleByIntegerLiteral { +extension ${Self}: ExpressibleByIntegerLiteral +where T: ExpressibleByIntegerLiteral { public init(integerLiteral value: T.IntegerLiteralType) { self.handle = Box(T(integerLiteral: value)) } } -extension Tracked : Comparable where T : Comparable { - public static func < (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Comparable where T: Comparable { + public static func < (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value < rhs.value } - public static func <= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func <= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value <= rhs.value } - public static func > (lhs: Tracked, rhs: Tracked) -> Bool { + public static func > (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value > rhs.value } - public static func >= (lhs: Tracked, rhs: Tracked) -> Bool { + public static func >= (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value >= rhs.value } } -extension Tracked : AdditiveArithmetic where T : AdditiveArithmetic { - public static var zero: Tracked { return Tracked(T.zero) } - public static func + (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value + rhs.value) +extension ${Self}: AdditiveArithmetic where T: AdditiveArithmetic { + public static var zero: ${Self} { return ${Self}(T.zero) } + public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value + rhs.value) } - public static func - (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value - rhs.value) + public static func - (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value - rhs.value) } } -extension Tracked : Equatable where T : Equatable { - public static func == (lhs: Tracked, rhs: Tracked) -> Bool { +extension ${Self}: Equatable where T: Equatable { + public static func == (lhs: ${Self}, rhs: ${Self}) -> Bool { return lhs.value == rhs.value } } -extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magnitude { - public typealias Magnitude = Tracked +extension ${Self}: SignedNumeric & Numeric +where T: SignedNumeric, T == T.Magnitude { + public typealias Magnitude = ${Self} - public init?(exactly source: U) where U : BinaryInteger { + public init?(exactly source: U) where U: BinaryInteger { if let t = T(exactly: source) { self.init(t) } @@ -136,169 +176,191 @@ extension Tracked : SignedNumeric & Numeric where T : SignedNumeric, T == T.Magn } public var magnitude: Magnitude { return Magnitude(value.magnitude) } - public static func * (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value * rhs.value) + public static func * (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value * rhs.value) } - public static func *= (lhs: inout Tracked, rhs: Tracked) { + public static func *= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs * rhs } } -extension Tracked where T : FloatingPoint { - public static func / (lhs: Tracked, rhs: Tracked) -> Tracked { - return Tracked(lhs.value / rhs.value) +extension ${Self} where T: FloatingPoint { + public static func / (lhs: ${Self}, rhs: ${Self}) -> ${Self} { + return ${Self}(lhs.value / rhs.value) } - public static func /= (lhs: inout Tracked, rhs: Tracked) { + public static func /= (lhs: inout ${Self}, rhs: ${Self}) { lhs = lhs / rhs } } -extension Tracked : Strideable where T : Strideable, T.Stride == T.Stride.Magnitude { - public typealias Stride = Tracked +extension ${Self}: Strideable +where T: Strideable, T.Stride == T.Stride.Magnitude { + public typealias Stride = ${Self} - public func distance(to other: Tracked) -> Stride { + public func distance(to other: ${Self}) -> Stride { return Stride(value.distance(to: other.value)) } - public func advanced(by n: Stride) -> Tracked { - return Tracked(value.advanced(by: n.value)) + public func advanced(by n: Stride) -> ${Self} { + return ${Self}(value.advanced(by: n.value)) } } // For now, `T` must be restricted to trivial types (like `Float` or `Tensor`). -extension Tracked : Differentiable where T : Differentiable, T == T.TangentVector { - public typealias TangentVector = Tracked +extension ${Self}: Differentiable +where T: Differentiable, T == T.TangentVector { + public typealias TangentVector = ${Self} } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: init) internal static func _vjpInit(_ value: T) - -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) { - return (Tracked(value), { v in v.value }) + -> (value: Self, pullback: (Self.TangentVector) -> (T.TangentVector)) + { + return (${Self}(value), { v in v.value }) } @usableFromInline @derivative(of: init) internal static func _jvpInit(_ value: T) - -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) { - return (Tracked(value), { v in Tracked(v) }) + -> (value: Self, differential: (T.TangentVector) -> (Self.TangentVector)) + { + return (${Self}(value), { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _vjpValue() -> (value: T, pullback: (T.TangentVector) -> Self.TangentVector) { - return (value, { v in Tracked(v) }) + internal func _vjpValue() -> ( + value: T, pullback: (T.TangentVector) -> Self.TangentVector + ) { + return (value, { v in ${Self}(v) }) } @usableFromInline @derivative(of: value) - internal func _jvpValue() -> (value: T, differential: (Self.TangentVector) -> T.TangentVector) { + internal func _jvpValue() -> ( + value: T, differential: (Self.TangentVector) -> T.TangentVector + ) { return (value, { v in v.value }) } } -extension Tracked where T : Differentiable, T == T.TangentVector { +extension ${Self} where T: Differentiable, T == T.TangentVector { @usableFromInline @derivative(of: +) internal static func _vjpAdd(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs + rhs, { v in (v, v) }) } @usableFromInline @derivative(of: +) internal static func _jvpAdd(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs + rhs, { $0 + $1 }) } @usableFromInline @derivative(of: -) internal static func _vjpSubtract(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs - rhs, { v in (v, .zero - v) }) } @usableFromInline @derivative(of: -) internal static func _jvpSubtract(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> Self) { + -> (value: Self, differential: (Self, Self) -> Self) + { return (lhs - rhs, { $0 - $1 }) } } -extension Tracked where T : Differentiable & SignedNumeric, T == T.Magnitude, - T == T.TangentVector { +extension ${Self} +where + T: Differentiable & SignedNumeric, T == T.Magnitude, + T == T.TangentVector +{ @usableFromInline @derivative(of: *) internal static func _vjpMultiply(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs * rhs, { v in (v * rhs, v * lhs) }) } @usableFromInline @derivative(of: *) internal static func _jvpMultiply(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs * rhs, { (dx, dy) in dx * rhs + dy * lhs }) } } -extension Tracked where T : Differentiable & FloatingPoint, T == T.TangentVector { +extension ${Self} +where T: Differentiable & FloatingPoint, T == T.TangentVector { @usableFromInline @derivative(of: /) internal static func _vjpDivide(lhs: Self, rhs: Self) - -> (value: Self, pullback: (Self) -> (Self, Self)) { + -> (value: Self, pullback: (Self) -> (Self, Self)) + { return (lhs / rhs, { v in (v / rhs, -lhs / (rhs * rhs) * v) }) } @usableFromInline @derivative(of: /) internal static func _jvpDivide(lhs: Self, rhs: Self) - -> (value: Self, differential: (Self, Self) -> (Self)) { + -> (value: Self, differential: (Self, Self) -> (Self)) + { return (lhs / rhs, { (dx, dy) in dx / rhs - lhs / (rhs * rhs) * dy }) } } -// Differential operators for `Tracked`. +// Differential operators for `${Self}`. public func gradient( - at x: T, in f: @differentiable (T) -> Tracked + at x: T, in f: @differentiable (T) -> ${Self} ) -> T.TangentVector where R.TangentVector == R { return pullback(at: x, in: f)(1) } public func gradient( - at x: T, _ y: U, in f: @differentiable (T, U) -> Tracked + at x: T, _ y: U, in f: @differentiable (T, U) -> ${Self} ) -> (T.TangentVector, U.TangentVector) where R.TangentVector == R { return pullback(at: x, y, in: f)(1) } public func derivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> R.TangentVector where T.TangentVector == T { return differential(at: x, in: f)(1) } public func derivative( - at x: Tracked, _ y: Tracked, - in f: @differentiable (Tracked, Tracked) -> R + at x: ${Self}, _ y: ${Self}, + in f: @differentiable (${Self}, ${Self}) -> R ) -> R.TangentVector where T.TangentVector == T, U.TangentVector == U { return differential(at: x, y, in: f)(1, 1) } public func valueWithGradient( - at x: T, in f: @differentiable (T) -> Tracked -) -> (value: Tracked, gradient: T.TangentVector) { + at x: T, in f: @differentiable (T) -> ${Self} +) -> (value: ${Self}, gradient: T.TangentVector) { let (y, pullback) = valueWithPullback(at: x, in: f) return (y, pullback(1)) } public func valueWithDerivative( - at x: Tracked, in f: @differentiable (Tracked) -> R + at x: ${Self}, in f: @differentiable (${Self}) -> R ) -> (value: R, derivative: R.TangentVector) { let (y, differential) = valueWithDifferential(at: x, in: f) return (y, differential(1)) } + +% end diff --git a/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift b/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift index 11780b57d713b..427ceb44cb4b8 100644 --- a/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift +++ b/stdlib/public/Darwin/Dispatch/Schedulers+DispatchQueue.swift @@ -45,8 +45,8 @@ extension DispatchTime /* : Strideable */ { typealias Stride = DispatchTimeInterval public func distance(to other: DispatchTime) -> DispatchTimeInterval { - let lhs = other.rawValue - let rhs = rawValue + let lhs = other.uptimeNanoseconds + let rhs = uptimeNanoseconds if lhs >= rhs { return DispatchTimeInterval.nanoseconds(Int(lhs - rhs)) } else { diff --git a/stdlib/public/Darwin/Foundation/DataProtocol.swift b/stdlib/public/Darwin/Foundation/DataProtocol.swift index 00f3a032cf43a..4a920511435bf 100644 --- a/stdlib/public/Darwin/Foundation/DataProtocol.swift +++ b/stdlib/public/Darwin/Foundation/DataProtocol.swift @@ -142,60 +142,56 @@ extension DataProtocol { return self.copyBytes(to: UnsafeMutableRawBufferPointer(start: ptr.baseAddress, count: ptr.count * MemoryLayout.stride), from: range) } + private func matches(_ data: D, from index: Index) -> Bool { + var haystackIndex = index + var needleIndex = data.startIndex + + while true { + guard self[haystackIndex] == data[needleIndex] else { return false } + + haystackIndex = self.index(after: haystackIndex) + needleIndex = data.index(after: needleIndex) + if needleIndex == data.endIndex { + // i.e. needle is found. + return true + } else if haystackIndex == endIndex { + return false + } + } + } + public func firstRange(of data: D, in range: R) -> Range? where R.Bound == Index { let r = range.relative(to: self) - let rangeCount = distance(from: r.lowerBound, to: r.upperBound) - if rangeCount < data.count { + let length = data.count + + if length == 0 || length > distance(from: r.lowerBound, to: r.upperBound) { return nil } - var haystackIndex = r.lowerBound - let haystackEnd = index(r.upperBound, offsetBy: -data.count) - while haystackIndex < haystackEnd { - var compareIndex = haystackIndex - var needleIndex = data.startIndex - let needleEnd = data.endIndex - var matched = true - while compareIndex < haystackEnd && needleIndex < needleEnd { - if self[compareIndex] != data[needleIndex] { - matched = false - break - } - needleIndex = data.index(after: needleIndex) - compareIndex = index(after: compareIndex) + + var position = r.lowerBound + while position < r.upperBound && distance(from: position, to: r.upperBound) >= length { + if matches(data, from: position) { + return position..(of data: D, in range: R) -> Range? where R.Bound == Index { let r = range.relative(to: self) - let rangeCount = distance(from: r.lowerBound, to: r.upperBound) - if rangeCount < data.count { + let length = data.count + + if length == 0 || length > distance(from: r.lowerBound, to: r.upperBound) { return nil } - var haystackIndex = r.upperBound - let haystackStart = index(r.lowerBound, offsetBy: data.count) - while haystackIndex > haystackStart { - var compareIndex = haystackIndex - var needleIndex = data.endIndex - let needleStart = data.startIndex - var matched = true - while compareIndex > haystackStart && needleIndex > needleStart { - if self[compareIndex] != data[needleIndex] { - matched = false - break - } - needleIndex = data.index(before: needleIndex) - compareIndex = index(before: compareIndex) - } - if matched { - return compareIndex..= r.lowerBound { + if matches(data, from: position) { + return position.. ClosedRange { _precondition( - minimum <= maximum, "Can't form Range with upperBound < lowerBound") + minimum <= maximum, "Range requires lowerBound <= upperBound") return ClosedRange(uncheckedBounds: (lower: minimum, upper: maximum)) } } diff --git a/stdlib/public/core/CompilerProtocols.swift b/stdlib/public/core/CompilerProtocols.swift index ca92b3d2b94cb..784fee1d14507 100644 --- a/stdlib/public/core/CompilerProtocols.swift +++ b/stdlib/public/core/CompilerProtocols.swift @@ -249,7 +249,7 @@ extension RawRepresentable where RawValue: Hashable, Self: Hashable { /// demonstrates this automatic implementation. public protocol CaseIterable { /// A type that can represent a collection of all values of this type. - associatedtype AllCases: Collection + associatedtype AllCases: Collection = [Self] where AllCases.Element == Self /// A collection of all values of this type. diff --git a/stdlib/public/core/Range.swift b/stdlib/public/core/Range.swift index 85e7db7b7c9c2..4bcde92bf8153 100644 --- a/stdlib/public/core/Range.swift +++ b/stdlib/public/core/Range.swift @@ -723,10 +723,12 @@ extension Comparable { /// - Parameters: /// - minimum: The lower bound for the range. /// - maximum: The upper bound for the range. + /// + /// - Precondition: `minimum <= maximum`. @_transparent public static func ..< (minimum: Self, maximum: Self) -> Range { _precondition(minimum <= maximum, - "Can't form Range with upperBound < lowerBound") + "Range requires lowerBound <= upperBound") return Range(uncheckedBounds: (lower: minimum, upper: maximum)) } @@ -752,8 +754,12 @@ extension Comparable { /// // Prints "[10, 20, 30]" /// /// - Parameter maximum: The upper bound for the range. + /// + /// - Precondition: `maximum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static prefix func ..< (maximum: Self) -> PartialRangeUpTo { + _precondition(maximum == maximum, + "Range cannot have an unordered upper bound.") return PartialRangeUpTo(maximum) } @@ -779,8 +785,12 @@ extension Comparable { /// // Prints "[10, 20, 30, 40]" /// /// - Parameter maximum: The upper bound for the range. + /// + /// - Precondition: `maximum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static prefix func ... (maximum: Self) -> PartialRangeThrough { + _precondition(maximum == maximum, + "Range cannot have an unordered upper bound.") return PartialRangeThrough(maximum) } @@ -806,8 +816,12 @@ extension Comparable { /// // Prints "[40, 50, 60, 70]" /// /// - Parameter minimum: The lower bound for the range. + /// + /// - Precondition: `minimum` must compare equal to itself (i.e. cannot be NaN). @_transparent public static postfix func ... (minimum: Self) -> PartialRangeFrom { + _precondition(minimum == minimum, + "Range cannot have an unordered lower bound.") return PartialRangeFrom(minimum) } } diff --git a/stdlib/public/core/StaticString.swift b/stdlib/public/core/StaticString.swift index 2f5c1ce03e549..d314b4c990431 100644 --- a/stdlib/public/core/StaticString.swift +++ b/stdlib/public/core/StaticString.swift @@ -172,20 +172,7 @@ public struct StaticString { return body(UnsafeBufferPointer( start: utf8Start, count: utf8CodeUnitCount)) } else { - var buffer: UInt64 = 0 - var i = 0 - let sink: (UInt8) -> Void = { -#if _endian(little) - buffer = buffer | (UInt64($0) << (UInt64(i) * 8)) -#else - buffer = buffer | (UInt64($0) << (UInt64(7-i) * 8)) -#endif - i += 1 - } - UTF8.encode(unicodeScalar, into: sink) - return body(UnsafeBufferPointer( - start: UnsafePointer(Builtin.addressof(&buffer)), - count: i)) + return unicodeScalar.withUTF8CodeUnits { body($0) } } } diff --git a/stdlib/public/runtime/Private.h b/stdlib/public/runtime/Private.h index 21c8e2906f104..4be3fb6bdb025 100644 --- a/stdlib/public/runtime/Private.h +++ b/stdlib/public/runtime/Private.h @@ -103,9 +103,11 @@ class TypeInfo { // value here. # define SWIFT_ISA_MASK 0xfffffffffffffff8ULL # elif __arm64__ +// The ISA mask used when ptrauth is available. +# define SWIFT_ISA_MASK_PTRAUTH 0x007ffffffffffff8ULL // ARM64 simulators always use the ARM64e mask. # if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR -# define SWIFT_ISA_MASK 0x007ffffffffffff8ULL +# define SWIFT_ISA_MASK SWIFT_ISA_MASK_PTRAUTH # else # if TARGET_OS_OSX # define SWIFT_ISA_MASK 0x00007ffffffffff8ULL diff --git a/stdlib/public/runtime/SwiftObject.mm b/stdlib/public/runtime/SwiftObject.mm index af7489d33cb11..f377a77d6f106 100644 --- a/stdlib/public/runtime/SwiftObject.mm +++ b/stdlib/public/runtime/SwiftObject.mm @@ -198,18 +198,18 @@ static id _getClassDescription(Class cls) { @implementation SwiftObject + (void)initialize { -#if SWIFT_HAS_ISA_MASKING && !NDEBUG - // Older OSes may not have this variable, or it may not match. This code only - // runs on older OSes in certain testing scenarios, so that doesn't matter. - // Only perform the check on newer OSes where the value should definitely - // match. -# if SWIFT_BUILD_HAS_BACK_DEPLOYMENT - if (!_swift_isBackDeploying()) +#if SWIFT_HAS_ISA_MASKING && !TARGET_OS_SIMULATOR && !NDEBUG + uintptr_t libObjCMask = (uintptr_t)&objc_absolute_packed_isa_class_mask; + assert(libObjCMask); + +# if __arm64__ && !__has_feature(ptrauth_calls) + // When we're built ARM64 but running on ARM64e hardware, we will get an + // ARM64e libobjc with an ARM64e ISA mask. This mismatch is harmless and we + // shouldn't assert. + assert(libObjCMask == SWIFT_ISA_MASK || libObjCMask == SWIFT_ISA_MASK_PTRAUTH); +# else + assert(libObjCMask == SWIFT_ISA_MASK); # endif - { - assert(&objc_debug_isa_class_mask); - assert(objc_debug_isa_class_mask == SWIFT_ISA_MASK); - } #endif } diff --git a/test/AutoDiff/SILOptimizer/activity_analysis.swift b/test/AutoDiff/SILOptimizer/activity_analysis.swift index bb177b0d5bc97..fe8fd1a7785c1 100644 --- a/test/AutoDiff/SILOptimizer/activity_analysis.swift +++ b/test/AutoDiff/SILOptimizer/activity_analysis.swift @@ -200,7 +200,7 @@ func checked_cast_addr_nonactive_result(_ x: T) -> T { @differentiable // expected-note @+1 {{when differentiating this function definition}} func checked_cast_addr_active_result(x: T) -> T { - // expected-note @+1 {{differentiating enum values is not yet supported}} + // expected-note @+1 {{expression is not differentiable}} if let y = x as? Float { // Use `y: Float?` value in an active way. return y as! T @@ -744,8 +744,8 @@ func testClassModifyAccessor(_ c: inout C) { @differentiable // expected-note @+1 {{when differentiating this function definition}} func testActiveOptional(_ x: Float) -> Float { - // expected-note @+1 {{differentiating enum values is not yet supported}} var maybe: Float? = 10 + // expected-note @+1 {{expression is not differentiable}} maybe = x return maybe! } diff --git a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift index 13c23dcc656da..9473311a62247 100644 --- a/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift +++ b/test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift @@ -157,8 +157,8 @@ class C: Differentiable { @differentiable // expected-note @+1 {{when differentiating this function definition}} func usesOptionals(_ x: Float) -> Float { - // expected-note @+1 {{differentiating enum values is not yet supported}} var maybe: Float? = 10 + // expected-note @+1 {{expression is not differentiable}} maybe = x return maybe! } diff --git a/test/AutoDiff/stdlib/differential_operators.swift.gyb b/test/AutoDiff/stdlib/differential_operators.swift.gyb index 5376a5d9adb87..36378874e36cf 100644 --- a/test/AutoDiff/stdlib/differential_operators.swift.gyb +++ b/test/AutoDiff/stdlib/differential_operators.swift.gyb @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s -o %t/differential_operators.swift // RUN: %target-build-swift %t/differential_operators.swift -o %t/differential_operators +// RUN: %target-codesign %t/differential_operators // RUN: %target-run %t/differential_operators // REQUIRES: executable_test diff --git a/test/AutoDiff/validation-test/optional.swift b/test/AutoDiff/validation-test/optional.swift new file mode 100644 index 0000000000000..4aeb60ba42762 --- /dev/null +++ b/test/AutoDiff/validation-test/optional.swift @@ -0,0 +1,514 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import DifferentiationUnittest +import StdlibUnittest + +var OptionalTests = TestSuite("OptionalDifferentiation") + +//===----------------------------------------------------------------------===// +// Basic tests. +//===----------------------------------------------------------------------===// + +/* +// TODO(TF-433): operator `??` lowers to `try_apply` instead of `switch_enum`, +// which is not yet supported by differentiation. +@differentiable +func optional1(_ maybeX: Float?) -> Float { + return maybeX ?? 10 +} +*/ + +OptionalTests.test("Let") { + @differentiable + func optional_let(_ maybeX: Float?) -> Float { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_let), .init(0.0)) + + @differentiable + func optional_let_tracked(_ maybeX: Tracked?) -> Tracked { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_let_tracked), .init(0.0)) + + @differentiable + func optional_let_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_let_nonresilient_tracked), .init(0.0)) + + @differentiable + func optional_let_nested(_ nestedMaybeX: Float??) -> Float { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_let_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_let_nested), .init(.init(0.0))) + + @differentiable + func optional_let_nested_tracked(_ nestedMaybeX: Tracked??) -> Tracked< + Float + > { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_let_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_let_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_let_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_let_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { + if let x = maybeX { + return x + } + return defaultValue + } + expectEqual(gradient(at: 10, 20, in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_generic), (.init(0.0), 1.0)) + + expectEqual( + gradient( + at: Tracked.init(10), Tracked.init(20), + in: optional_let_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, Tracked.init(20), in: optional_let_generic), + (.init(0.0), 1.0)) + + @differentiable + func optional_let_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { + if let maybeX = nestedMaybeX { + if let x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + + expectEqual( + gradient(at: 10.0, 20.0, in: optional_let_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_let_nested_generic), + (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Switch") { + @differentiable + func optional_switch(_ maybeX: Float?) -> Float { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual(gradient(at: 10, in: optional_switch), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_switch), .init(0.0)) + + @differentiable + func optional_switch_tracked(_ maybeX: Tracked?) -> Tracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual(gradient(at: 10, in: optional_switch_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_switch_tracked), .init(0.0)) + + @differentiable + func optional_switch_nonresilient_tracked( + _ maybeX: NonresilientTracked? + ) -> NonresilientTracked { + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_switch_nonresilient_tracked), .init(0.0)) + + @differentiable + func optional_switch_nested(_ nestedMaybeX: Float??) -> Float { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual(gradient(at: 10, in: optional_switch_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_switch_nested), .init(.init(0.0))) + + @differentiable + func optional_switch_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_switch_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + switch nestedMaybeX { + case nil: return 10 + case let .some(maybeX): + switch maybeX { + case nil: return 10 + case let .some(x): return x * x + } + } + } + expectEqual( + gradient(at: 10, in: optional_switch_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_switch_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_switch_generic( + _ maybeX: T?, _ defaultValue: T + ) -> T { + switch maybeX { + case nil: return defaultValue + case let .some(x): return x + } + } + expectEqual( + gradient(at: 10, 20, in: optional_switch_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_switch_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { + switch nestedMaybeX { + case nil: return defaultValue + case let .some(maybeX): + switch maybeX { + case nil: return defaultValue + case let .some(x): return x + } + } + } + expectEqual( + gradient(at: 10, 20, in: optional_switch_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_switch_nested_generic), + (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Var1") { + @differentiable + func optional_var1(_ maybeX: Float?) -> Float { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var1), .init(0.0)) + + @differentiable + func optional_var1_tracked(_ maybeX: Tracked?) -> Tracked { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var1_tracked), .init(0.0)) + + @differentiable + func optional_var1_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + var maybeX = maybeX + if let x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var1_nonresilient_tracked), .init(0.0)) + + @differentiable + func optional_var1_nested(_ nestedMaybeX: Float??) -> Float { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var1_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var1_nested), .init(.init(0.0))) + + @differentiable + func optional_var1_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var1_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var1_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var1_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_var1_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { + var maybeX = maybeX + if let x = maybeX { + return x + } + return defaultValue + } + expectEqual( + gradient(at: 10, 20, in: optional_var1_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_var1_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { + var nestedMaybeX = nestedMaybeX + if let maybeX = nestedMaybeX { + if var x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + expectEqual( + gradient(at: 10, 20, in: optional_var1_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var1_nested_generic), + (.init(.init(0.0)), 1.0)) +} + +OptionalTests.test("Var2") { + @differentiable + func optional_var2(_ maybeX: Float?) -> Float { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var2), .init(0.0)) + + @differentiable + func optional_var2_tracked(_ maybeX: Tracked?) -> Tracked { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2_tracked), .init(20.0)) + expectEqual(gradient(at: nil, in: optional_var2_tracked), .init(0.0)) + + @differentiable + func optional_var2_nonresilient_tracked(_ maybeX: NonresilientTracked?) + -> NonresilientTracked + { + if var x = maybeX { + return x * x + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nonresilient_tracked), .init(20.0)) + expectEqual( + gradient(at: nil, in: optional_var2_nonresilient_tracked), .init(0.0)) + + @differentiable + func optional_var2_nested(_ nestedMaybeX: Float??) -> Float { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual(gradient(at: 10, in: optional_var2_nested), .init(.init(20.0))) + expectEqual(gradient(at: nil, in: optional_var2_nested), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_tracked(_ nestedMaybeX: Tracked??) + -> Tracked + { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nested_tracked), .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_tracked), .init(.init(0.0))) + + @differentiable + func optional_var2_nested_nonresilient_tracked( + _ nestedMaybeX: NonresilientTracked?? + ) -> NonresilientTracked { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x * x + } + return 10 + } + return 10 + } + expectEqual( + gradient(at: 10, in: optional_var2_nested_nonresilient_tracked), + .init(.init(20.0))) + expectEqual( + gradient(at: nil, in: optional_var2_nested_nonresilient_tracked), + .init(.init(0.0))) + + @differentiable + func optional_var2_generic(_ maybeX: T?, _ defaultValue: T) + -> T + { + if var x = maybeX { + return x + } + return defaultValue + } + expectEqual( + gradient(at: 10, 20, in: optional_var2_generic), (.init(1.0), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_generic), (.init(0.0), 1.0)) + + @differentiable + func optional_var2_nested_generic( + _ nestedMaybeX: T??, _ defaultValue: T + ) -> T { + if var maybeX = nestedMaybeX { + if var x = maybeX { + return x + } + return defaultValue + } + return defaultValue + } + expectEqual( + gradient(at: 10, 20, in: optional_var2_nested_generic), + (.init(.init(1.0)), 0.0)) + expectEqual( + gradient(at: nil, 20, in: optional_var2_nested_generic), + (.init(.init(0.0)), 1.0)) +} + +runAllTests() diff --git a/test/ClangImporter/enum-error-execute.swift b/test/ClangImporter/enum-error-execute.swift index 263571febb3fd..c7038c00037ad 100644 --- a/test/ClangImporter/enum-error-execute.swift +++ b/test/ClangImporter/enum-error-execute.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-clang %S/Inputs/enum-error.m -c -o %t/enum-error.o // RUN: %target-build-swift -import-objc-header %S/Inputs/enum-error.h -Xlinker %t/enum-error.o %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Constraints/enum_cases.swift b/test/Constraints/enum_cases.swift index 392104bdbd681..e567f89496070 100644 --- a/test/Constraints/enum_cases.swift +++ b/test/Constraints/enum_cases.swift @@ -153,3 +153,21 @@ func rdar_49159472() { func baz(e: E) {} } } + +struct EnumElementPatternFromContextualType { + enum E { + case plain + case payload(T) + } + + func foo(x: Any) where T == EnumElementPatternFromContextualType.E { + switch x { + case T.plain: // Ok + break + case T.payload(true): // Ok + break + default: + break + } + } +} diff --git a/test/Constraints/members.swift b/test/Constraints/members.swift index 3f35c02bf6b01..55ada2a99b4a6 100644 --- a/test/Constraints/members.swift +++ b/test/Constraints/members.swift @@ -674,3 +674,47 @@ _ = [.e: 1] // expected-error {{reference to member 'e' cannot be resolved witho let _ : [Int: Any] = [1 : .e] // expected-error {{type 'Any' has no member 'e'}} let _ : (Int, Any) = (1, .e) // expected-error {{type 'Any' has no member 'e'}} _ = (1, .e) // expected-error {{cannot infer contextual base in reference to member 'e'}} + +// SR-13359 +typealias Pair = (Int, Int) +func testSR13359(_ pair: (Int, Int), _ alias: Pair, _ void: Void, labeled: (a: Int, b: Int)) { + _ = pair[0] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; did you mean to use '.0'?}} {{11-14=.0}} + _ = pair[1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; did you mean to use '.1'?}} {{11-14=.1}} + _ = pair[2] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[100] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair["strting"] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[-1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[1, 1] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = void[0] // expected-error {{value of type 'Void' has no subscripts}} + // Other representations of literals + _ = pair[0x00] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + _ = pair[0b00] // expected-error {{cannot access element using subscript for tuple type '(Int, Int)'; use '.' notation instead}} {{none}} + + _ = alias[0] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); did you mean to use '.0'?}} {{12-15=.0}} + _ = alias[1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); did you mean to use '.1'?}} {{12-15=.1}} + _ = alias[2] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[100] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias["strting"] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[-1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[1, 1] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[0x00] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + _ = alias[0b00] // expected-error {{cannot access element using subscript for tuple type 'Pair' (aka '(Int, Int)'); use '.' notation instead}} {{none}} + + // Labeled tuple base + _ = labeled[0] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.0'?}} {{14-17=.0}} + _ = labeled[1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.1'?}} {{14-17=.1}} + _ = labeled[2] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[100] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled["strting"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[-1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[1, 1] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[0x00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[0b00] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + + // Suggesting use label access + _ = labeled["a"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.a'?}} {{14-19=.a}} + _ = labeled["b"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; did you mean to use '.b'?}} {{14-19=.b}} + _ = labeled["c"] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + _ = labeled[""] // expected-error {{cannot access element using subscript for tuple type '(a: Int, b: Int)'; use '.' notation instead}} {{none}} + +} diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift index 2250343a9e666..a709fb5f8096e 100644 --- a/test/Constraints/patterns.swift +++ b/test/Constraints/patterns.swift @@ -296,8 +296,7 @@ switch staticMembers { // expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} case .prop: break - // TODO: repeated error message - case .optProp: break // expected-error* {{not unwrapped}} + case .optProp: break case .method: break // expected-error{{member 'method' expects argument of type 'Int'}} case .method(0): break @@ -311,9 +310,6 @@ switch staticMembers { case .optMethod: break // expected-error{{member 'optMethod' expects argument of type 'Int'}} case .optMethod(0): break - // expected-error@-1 {{value of optional type 'StaticMembers?' must be unwrapped to a value of type 'StaticMembers'}} - // expected-note@-2 {{coalesce}} - // expected-note@-3 {{force-unwrap}} } _ = 0 @@ -343,14 +339,10 @@ func rdar32241441() { // SR-6100 struct One { // expected-note{{'Two' declared as parameter to type 'One'}} - public enum E: Error { - // if you remove associated value, everything works - case SomeError(String) - - static func foo(error: Error) { - if case SomeError = error {} + public enum E: Error { + // if you remove associated value, everything works + case SomeError(String) } - } } func testOne() { diff --git a/test/Constraints/sr12365.swift b/test/Constraints/sr12365.swift index 368985a4ac7eb..09a97afb320d8 100644 --- a/test/Constraints/sr12365.swift +++ b/test/Constraints/sr12365.swift @@ -16,8 +16,22 @@ func check(a: Double, b: Int64) -> Bool { return a != 0 && b != 0 // Okay } -func check() { +func check1() { let x: Int = 1 let _ = UInt(1) << x - 1 // Okay let _ = UInt(1) << (x + 1) - 1 // Okay } + +func check2() { + let a: UInt32 = 0 + let b: UInt32 = 1 << (a + 16) + let _ = a & b // Okay +} + +func check3() { + let a: UInt32 = 0 + let b = 1 << (a + 16) + let _ = a & b // Not okay, because 'b: Int'! + // expected-error@-1 {{binary operator '&' cannot be applied to operands of type 'UInt32' and 'Int'}} + // expected-note@-2 {{overloads for '&' exist with these partially matching parameter lists: (Int, Int), (UInt32, UInt32)}} +} diff --git a/test/Driver/SourceRanges/range-incremental-no-build-record.swift b/test/Driver/SourceRanges/range-incremental-no-build-record.swift index 3fb929a7a6cb0..9aa0897be8f00 100644 --- a/test/Driver/SourceRanges/range-incremental-no-build-record.swift +++ b/test/Driver/SourceRanges/range-incremental-no-build-record.swift @@ -51,4 +51,5 @@ // RUN: %FileCheck -match-full-lines -check-prefix=CHECK-COMPARE-DISABLED-NO-BUILD-RECORD %s < %t/output1 // CHECK-COMPARE-DISABLED-NO-BUILD-RECORD: *** Incremental build disabled because could not read build record, cannot compare *** +// RUN: %target-codesign %t/main // RUN: %target-run %t/main | tee run1 | grep Any > /dev/null && rm %t/main diff --git a/test/IDE/complete_opaque_result.swift b/test/IDE/complete_opaque_result.swift index 03a95395d1276..a760894b6828f 100644 --- a/test/IDE/complete_opaque_result.swift +++ b/test/IDE/complete_opaque_result.swift @@ -143,7 +143,7 @@ class TestClass : // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintAndDefault() -> ConcreteMyProtocol {|}; // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithAnyObjectConstraint() -> some MyProtocol & AnyObject {|} // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConstraintOnProto() -> some MyProtocol {|} -// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithSameTypeConstraint() -> AssocWithSameTypeConstraint {|} +// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithSameTypeConstraint() -> ConcreteMyProtocol {|} // OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraintGeneric(arg: T) -> AssocWithConformanceConstraintGeneric {|} // OVERRIDE: End completions } diff --git a/test/IDE/complete_override.swift b/test/IDE/complete_override.swift index 4213dfa1df6ee..7f186a8aafaa6 100644 --- a/test/IDE/complete_override.swift +++ b/test/IDE/complete_override.swift @@ -896,11 +896,10 @@ struct SynthesizedConformance3: Hashable { enum SynthesizedConformance4: CaseIterable { case a, b, c, d #^OVERRIDE_SYNTHESIZED_4^# -// OVERRIDE_SYNTHESIZED_4: Begin completions, 4 items +// OVERRIDE_SYNTHESIZED_4: Begin completions, 3 items // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceVar]/Super/IsSystem: var hashValue: Int // OVERRIDE_SYNTHESIZED_4-DAG: Decl[InstanceMethod]/Super/IsSystem: func hash(into hasher: inout Hasher) {|}; // OVERRIDE_SYNTHESIZED_4-DAG: Decl[StaticVar]/Super/IsSystem: static var allCases: [SynthesizedConformance4]; -// OVERRIDE_SYNTHESIZED_4-DAG: Decl[AssociatedType]/Super/IsSystem: typealias AllCases = {#(Type)#}; } class SynthesizedConformance5: SynthesizedConformance2 { diff --git a/test/IDE/complete_pound_keypath.swift b/test/IDE/complete_pound_keypath.swift index 8a7b84ced7f67..6dc428a36344a 100644 --- a/test/IDE/complete_pound_keypath.swift +++ b/test/IDE/complete_pound_keypath.swift @@ -6,6 +6,16 @@ // RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_2 | %FileCheck -check-prefix=CHECK-IN_KEYPATH %s +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_3 | %FileCheck -check-prefix=CHECK-IN_KEYPATH_BRIDGED_STRING %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_4 | %FileCheck -check-prefix=CHECK-IN_KEYPATH_BRIDGED_STRING %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_5 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH,CHECK-IN_KEYPATH_OPT %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_6 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH,CHECK-IN_KEYPATH_OPT %s + +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_7 | %FileCheck -check-prefixes=CHECK-IN_KEYPATH_BRIDGED_STRING %s + // REQUIRES: objc_interop @@ -21,9 +31,11 @@ func selectorArg1(obj: NSObject) { acceptKeyPath(#^KEYPATH_ARG^# } -class ObjCClass : NSObject { +@objcMembers class ObjCClass : NSObject { var prop1: String = "" var prop2: ObjCClass? + var prop3: [ObjCClass]? = [] + var prop4: [String: String] = [:] func completeInKeyPath1() { _ = #keyPath(#^IN_KEYPATH_1^# @@ -34,12 +46,42 @@ func completeInKeyPath2() { _ = #keyPath(ObjCClass.#^IN_KEYPATH_2^# } +func completeInKeyPath3() { + _ = #keyPath(ObjCClass.prop1.#^IN_KEYPATH_3^# +} +func completeInKeyPath3() { + _ = #keyPath(String.#^IN_KEYPATH_4^# +} + +func completeInKeyPath4() { + _ = #keyPath(ObjCClass.prop2.#^IN_KEYPATH_5^# +} + +func completeInKeyPath5() { + _ = #keyPath(ObjCClass.prop3.#^IN_KEYPATH_6^# +} + +func completeInKeyPath6() { + _ = #keyPath(ObjCClass.prop4.anythingHere.#^IN_KEYPATH_7^# +} + // CHECK-AFTER_POUND-NOT: keyPath // CHECK-KEYPATH_ARG: Keyword/None/TypeRelation[Identical]: #keyPath({#@objc property sequence#})[#String#]; name=#keyPath(@objc property sequence) // CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop1[#String#]; name=prop1 // CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop2[#ObjCClass?#]; name=prop2 +// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop3[#[ObjCClass]?#]; name=prop3 // CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hashValue[#Int#]; name=hashValue +// Make sure we unwrap optionals (members of Optional itself are invalid in this context) +// +// CHECK-IN_KEYPATH_OPT-NOT: name=map + +// Make sure we handle bridged types (i.e. show NSString members rather than String members) +// +// CHECK-IN_KEYPATH_BRIDGED_STRING: Decl[InstanceVar]/CurrNominal/IsSystem: urlsInText[#[URL]#]; name=urlsInText +// CHECK-IN_KEYPATH_BRIDGED_STRING: Decl[InstanceVar]/CurrNominal/IsSystem: uppercased[#String!#]; name=uppercased +// CHECK-IN_KEYPATH_BRIDGED_STRING-NOT: name=count + diff --git a/test/IDE/print_clang_header_i386.swift b/test/IDE/print_clang_header_i386.swift index 4774771e3fb83..d78436f712305 100644 --- a/test/IDE/print_clang_header_i386.swift +++ b/test/IDE/print_clang_header_i386.swift @@ -4,5 +4,7 @@ // XFAIL: linux, freebsd // RUN: echo '#include "header-to-print.h"' > %t.i386.m -// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt +// RUN: %empty-directory(%t) +// RUN: %build-clang-importer-objc-overlays +// RUN: %target-swift-ide-test -source-filename %s -print-header -header-to-print %S/Inputs/print_clang_header/header-to-print.h -print-regular-comments -I %t --cc-args -arch i386 -isysroot %clang-importer-sdk-path -fsyntax-only %t.i386.m -I %S/Inputs/print_clang_header > %t.i386.txt // RUN: diff -u %S/Inputs/print_clang_header/header-to-print.h.printed.txt %t.i386.txt diff --git a/test/IRGen/casts.sil b/test/IRGen/casts.sil index 3458ef87cab62..fa2dbf9f2df85 100644 --- a/test/IRGen/casts.sil +++ b/test/IRGen/casts.sil @@ -54,7 +54,7 @@ entry(%n : $Builtin.NativeObject): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8** } @u_cast_to_class_existential(%objc_object* %0) // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2) {{.*}} { +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2) {{.*}} { // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -80,7 +80,7 @@ entry(%a : $@thick Any.Type): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8**, i8** } @u_cast_to_class_existential_2(%objc_object* %0) // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp"{{[^,]*}}, {{.*}} @"$s5casts3CP2Mp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8**, i8** } @dynamic_cast_existential_2_unconditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -122,7 +122,7 @@ entry(%a : $@thick Any.Type): // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8** } @c_cast_to_class_existential(%objc_object* %0) // CHECK: call { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* {{.*}}, %swift.type* %.Type, {{.*}} @"$s5casts2CPMp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont @@ -152,7 +152,7 @@ nay: // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { %objc_object*, i8**, i8** } @c_cast_to_class_existential_2(%objc_object* %0) // CHECK: call { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* {{%.*}}, %swift.type* {{%.*}}, {{.*}} @"$s5casts2CPMp" {{[^,]*}}, {{.*}} @"$s5casts3CP2Mp" -// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} private { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) +// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} linkonce_odr hidden { i8*, i8**, i8** } @dynamic_cast_existential_2_conditional(i8* %0, %swift.type* %1, %swift.protocol* %2, %swift.protocol* %3) // CHECK: [[WITNESS:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, %swift.protocol* %2) // CHECK: [[IS_NULL:%.*]] = icmp eq i8** [[WITNESS]], null // CHECK: br i1 [[IS_NULL]], label %fail, label %cont diff --git a/test/IRGen/class_update_callback_with_fixed_layout.sil b/test/IRGen/class_update_callback_with_fixed_layout.sil index c7d5629e5d716..ad1f1a4df28d3 100644 --- a/test/IRGen/class_update_callback_with_fixed_layout.sil +++ b/test/IRGen/class_update_callback_with_fixed_layout.sil @@ -51,7 +51,7 @@ sil_vtable SubclassOfClassWithResilientField {} // -- the update callback // CHECK-SAME: @"$s39class_update_callback_with_fixed_layout23ClassWithResilientFieldCMU" -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // Class has static metadata: // CHECK-LABEL: @"$s39class_update_callback_with_fixed_layout23ClassWithResilientFieldCMf" diff --git a/test/IRGen/class_update_callback_without_fixed_layout.sil b/test/IRGen/class_update_callback_without_fixed_layout.sil index 1a06330329bd2..c8e212c9baf62 100644 --- a/test/IRGen/class_update_callback_without_fixed_layout.sil +++ b/test/IRGen/class_update_callback_without_fixed_layout.sil @@ -5,8 +5,7 @@ // RUN: %target-swift-frontend -I %t -emit-ir -enable-library-evolution -O %s -target %target-pre-stable-abi-triple // REQUIRES: objc_interop -// UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // With the old deployment target, these classes use the 'singleton' metadata // initialization pattern. The class is not statically visible to Objective-C, @@ -63,7 +62,7 @@ sil_vtable SubclassOfClassWithResilientField {} // -- the update callback // CHECK-NEW-SAME: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMU{{(\.ptrauth)?}}" -// CHECK-SAME: }, section "__DATA, __objc_const" +// CHECK-SAME: }, section "__DATA, {{.*}}" // Class has static metadata: // CHECK-LABEL: @"$s42class_update_callback_without_fixed_layout23ClassWithResilientFieldCMf" diff --git a/test/IRGen/default_function_ir_attributes.swift b/test/IRGen/default_function_ir_attributes.swift new file mode 100644 index 0000000000000..e41e97be4acc5 --- /dev/null +++ b/test/IRGen/default_function_ir_attributes.swift @@ -0,0 +1,175 @@ +// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-runtime --check-prefix=CHECK -DINT=i%target-ptrsize + +protocol P0 {} +protocol P1 {} +struct P0Conformer: P0, Hashable {} +protocol CP0 : AnyObject {} +protocol CP1 : AnyObject {} +class C {} + +struct S { + var stored: Int + var computed: Int { + get { stored } + set {} + } + subscript(t: T) -> Int { + get { 0 } + set {} + } +} + +enum SinglePayloadEnum { + case value(T) + case different + case otherwise +} + +struct OutlinedOperations { + var first: T + var second: T + var third: T + var fourth: T +} +struct StructHoldingOutlined { + var outlined: OutlinedOperations + var element: T +} + +// main +// CHECK-LABEL: define {{.*}} @main( +// CHECK-SAME: [[ATTRS_SIMPLE:#[0-9]+]] + +// class deinit +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1CCfd"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// outlined operation +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes18OutlinedOperationsVyxGlWOc"( +// CHECK-SAME: [[ATTRS_NOINLINE_NOUNWIND:#[0-9]+]] + +// normal function +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes3fooyyF"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func foo() {} + +// helper function: __swift_instantiateConcreteTypeFromMangledName +// CHECK-LABEL: define {{.*}} @__swift_instantiateConcreteTypeFromMangledName( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME:#[0-9]+]] + +func use_metadata() -> Any.Type { + return ((C) -> Int).self +} + +// helper function: dynamic_cast_existential_1_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND:#[0-9]+]] + +func test_class_existential_cast_0(value: AnyObject) -> CP0 { + value as! CP0 +} + +// helper function: dynamic_cast_existential_2_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_2_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_1(value: AnyObject) -> CP0 & CP1 { + value as! CP0 & CP1 +} + +// helper function: dynamic_cast_existential_2_conditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_2_conditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_2(value: AnyObject) -> (CP0 & CP1)? { + value as? CP0 & CP1 +} + +// helper function: dynamic_cast_existential_1_superclass_unconditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_superclass_unconditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_3(value: AnyObject) -> C & CP0 { + value as! C & CP0 +} + +// metadata accessor +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1CCMa"( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] + +// helper function: dynamic_cast_existential_1_superclass_conditional +// CHECK-LABEL: define {{.*}} @dynamic_cast_existential_1_superclass_conditional( +// CHECK-SAME: [[ATTRS_NOUNWIND]] + +func test_class_existential_cast_4(value: AnyObject) -> (C & CP0)? { + value as? C & CP0 +} + +// helper function: SIL-generated key path getter +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1SV8computedSivpACTK"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: SIL-generated key path setter +// CHECK-LABEL: define {{.*}} @"$s30default_function_ir_attributes1SV8computedSivpACTk"( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func test_computed_key_path_sil_thunks() -> KeyPath { + \S.computed +} + +// helper function: IR-generated key path getter +// CHECK-LABEL: define {{.*}} @keypath_get( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path setter +// CHECK-LABEL: define {{.*}} @keypath_set( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path arg layout accessor +// CHECK-LABEL: define {{.*}} @keypath_get_arg_layout( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path destroy function +// CHECK-LABEL: define {{.*}} @keypath_destroy( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path copy function +// CHECK-LABEL: define {{.*}} @keypath_copy( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path equals function +// CHECK-LABEL: define {{.*}} @keypath_equals( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path hash function +// CHECK-LABEL: define {{.*}} @keypath_hash( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: IR-generated key path argument initializer +// CHECK-LABEL: define {{.*}} @keypath_arg_init( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +func test_computed_key_path_generic_thunks(value: T) -> KeyPath { + return \S[value] +} + +// helper function: __swift_get_extra_inhabitant_index( +// CHECK-LABEL: define {{.*}} @__swift_get_extra_inhabitant_index( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: __swift_store_extra_inhabitant_index( +// CHECK-LABEL: define {{.*}} @__swift_store_extra_inhabitant_index( +// CHECK-SAME: [[ATTRS_SIMPLE]] + +// helper function: __swift_instantiateGenericMetadata +// CHECK-LABEL: define {{.*}} @__swift_instantiateGenericMetadata( +// CHECK-SAME: [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] + +// Use the presence of a target-cpu attribute as a litmus for +// whether constructInitialAttributes was called, since it's very +// unlikely that handrolled code generation would think to add one. +// CHECK: attributes [[ATTRS_SIMPLE]] = { [[CUSTOM_ATTRS:.*target-cpu.*]] }{{$}} +// CHECK-DAG: attributes [[ATTRS_NOINLINE_NOUNWIND]] = { noinline nounwind {{.*target-cpu.*}} } +// CHECK-DAG: attributes [[ATTRS_NOINLINE_READNONE_NOUNWIND_NOFRAME]] = { noinline nounwind readnone {{.*}}"frame-pointer"="none"{{.*target-cpu.*}} } +// CHECK-DAG: attributes [[ATTRS_NOUNWIND]] = { nounwind [[CUSTOM_ATTRS]] }{{$}} diff --git a/test/IRGen/eager-class-initialization.swift b/test/IRGen/eager-class-initialization.swift index 53b172256bca3..d1cbaac3b228b 100644 --- a/test/IRGen/eager-class-initialization.swift +++ b/test/IRGen/eager-class-initialization.swift @@ -3,8 +3,7 @@ // RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) %s -emit-ir -target %target-pre-stable-abi-triple | %FileCheck %s -DINT=i%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-OLD // REQUIRES: objc_interop -// UNSUPPORTED: OS=iosmac -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // See also eager-class-initialization-stable-abi.swift, for the stable ABI // deployment target test. diff --git a/test/IRGen/entrypoint-section-run.cpp b/test/IRGen/entrypoint-section-run.cpp index 2158b77e7ea85..efb009823a7b2 100644 --- a/test/IRGen/entrypoint-section-run.cpp +++ b/test/IRGen/entrypoint-section-run.cpp @@ -1,10 +1,11 @@ // RUN: %empty-directory(%t) -// RUN: %clang %s -isysroot %sdk -o %t/main +// RUN: %target-clang %s -std=c++11 -isysroot %sdk -o %t/main // RUN: %target-codesign %t/main // RUN: %target-build-swift %S/Inputs/at-main-struct-simple.swift -O -parse-as-library -emit-library -o %t/libHowdy.dylib -module-name Howdy +// RUN: %target-codesign %t/libHowdy.dylib // RUN: %target-run %t/main %t/libHowdy.dylib | %FileCheck %s -// REQUIRES: OS=macosx,CPU=x86_64 +// REQUIRES: VENDOR=apple // REQUIRES: executable_test // UNSUPPORTED: remote_run @@ -13,6 +14,13 @@ #include #include #include +#include + +#if __POINTER_WIDTH__ == 64 +using mach_header_platform = mach_header_64; +#else +using mach_header_platform = mach_header; +#endif int main(int argc, char *argv[]) { if (argc != 2) { @@ -35,12 +43,19 @@ int main(int argc, char *argv[]) { continue; } auto *header = - reinterpret_cast(_dyld_get_image_header(index)); + reinterpret_cast(_dyld_get_image_header(index)); size_t size; auto *data = getsectiondata(header, "__TEXT", "__swift5_entry", &size); int32_t offset = *reinterpret_cast(data); mainFunction = reinterpret_cast( - reinterpret_cast(data) + offset); + ptrauth_sign_unauthenticated( + reinterpret_cast( + reinterpret_cast(data) + offset + ), + ptrauth_key_function_pointer, + ptrauth_function_pointer_type_discriminator(MainFunction) + ) + ); break; } diff --git a/test/IRGen/jit-debugging.swift b/test/IRGen/jit-debugging.swift new file mode 100644 index 0000000000000..6a8a8a5243ee7 --- /dev/null +++ b/test/IRGen/jit-debugging.swift @@ -0,0 +1,17 @@ +// %empty-directory(%t) +// RUN: not %target-swift-frontend -use-jit -dump-jit invalid -interpret %s 2>&1 | %FileCheck -check-prefix CHECK-INVALID %s +// CHECK-INVALID: error: invalid value 'invalid' in 'dump-jit' + +// RUN: %empty-directory(%t) +// RUN: cd %t && %target-swift-frontend -use-jit -dump-jit llvm-ir -interpret %s +// RUN: %FileCheck -check-prefix CHECK-LLIR %s < %t/main.ll +// CHECK-LLIR: ; ModuleID = 'main' + +// RUN: %empty-directory(%t) +// RUN: cd %t && %target-swift-frontend -use-jit -dump-jit object -interpret %s +// RUN: %llvm-nm --defined-only --extern-only %t/main-jitted-objectbuffer.o | %FileCheck -check-prefix CHECK-OBJ %s +// CHECK-OBJ: T {{_?}}main + +// REQUIRES: rdar66644853 + +let zero = 0 diff --git a/test/IRGen/keypaths_objc.sil b/test/IRGen/keypaths_objc.sil index 91c31c8055139..4e8cb200f4e6f 100644 --- a/test/IRGen/keypaths_objc.sil +++ b/test/IRGen/keypaths_objc.sil @@ -45,7 +45,7 @@ entry(%0 : $@objc_metatype C.Type): unreachable } -// CHECK: define private i8* [[SELECTOR_FN]] +// CHECK: define linkonce_odr hidden i8* [[SELECTOR_FN]] // CHECK-NEXT: entry: // CHECK-NEXT: %1 = load {{.*}}selector(x) // CHECK-NEXT: ret i8* %1 diff --git a/test/IRGen/literals.sil b/test/IRGen/literals.sil index 193bf812b86ce..24c2b9450780d 100644 --- a/test/IRGen/literals.sil +++ b/test/IRGen/literals.sil @@ -4,8 +4,6 @@ // CHECK: [[U8_0:@.*]] = private unnamed_addr constant [8 x i8] c"help\09me\00" // CHECK: [[U8_1:@.*]] = private unnamed_addr constant [5 x i8] c"\00x\C6\AB\00" -// CHECK: [[U16_0:@.*]] = private unnamed_addr constant [8 x i16] [i16 104, i16 101, i16 108, i16 112, i16 9, i16 109, i16 101, i16 0] -// CHECK: [[U16_1:@.*]] = private unnamed_addr constant [4 x i16] [i16 0, i16 120, i16 427, i16 0] sil_stage canonical @@ -27,16 +25,3 @@ bb0: // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @utf8_literal_with_nul() {{.*}} { // CHECK: ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[U8_1]], i64 0, i64 0) -sil @utf16_literal : $@convention(thin) () -> Builtin.RawPointer { -bb0: - %0 = string_literal utf16 "help\tme" - return %0 : $Builtin.RawPointer -} -// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8* @utf16_literal() {{.*}} { -// CHECK: ret i8* bitcast ([8 x i16]* [[U16_0]] to i8*) - -sil @utf16_literal_with_nul : $@convention(thin) () -> Builtin.RawPointer { -bb0: - %0 = string_literal utf16 "\u{00}x\u{01ab}" - return %0 : $Builtin.RawPointer -} diff --git a/test/IRGen/objc_bridge.swift b/test/IRGen/objc_bridge.swift index 89b60f9b0e017..7843ed5054a0d 100644 --- a/test/IRGen/objc_bridge.swift +++ b/test/IRGen/objc_bridge.swift @@ -96,7 +96,7 @@ import Foundation // CHECK: i8* bitcast (void ([[OPAQUE:.*]]*, i8*)* @"$s11objc_bridge3BasCfETo" to i8*) // CHECK: } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_PROPERTIES__TtC11objc_bridge3Bas = internal constant { i32, i32, [5 x { i8*, i8* }] } { diff --git a/test/IRGen/objc_class_export.swift b/test/IRGen/objc_class_export.swift index 7dc4848a16a1e..07c5a10c8d895 100644 --- a/test/IRGen/objc_class_export.swift +++ b/test/IRGen/objc_class_export.swift @@ -34,7 +34,7 @@ // CHECK-SAME: i8* null, // CHECK-SAME: i8* null, // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: @_DATA__TtC17objc_class_export3Foo = internal constant {{.*\*}} } { // CHECK-SAME: i32 128, // CHECK-SAME: i32 16, @@ -47,7 +47,7 @@ // CHECK-SAME: @_IVARS__TtC17objc_class_export3Foo, // CHECK-SAME: i8* null, // CHECK-SAME: _PROPERTIES__TtC17objc_class_export3Foo -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: @"$s17objc_class_export3FooCMf" = internal global <{{.*}} }> <{ // CHECK-SAME: void ([[FOO]]*)* @"$s17objc_class_export3FooCfD", // CHECK-SAME: i8** @"$sBOWV", diff --git a/test/IRGen/objc_extensions.swift b/test/IRGen/objc_extensions.swift index e275e9fbf9276..6d4df434ae06f 100644 --- a/test/IRGen/objc_extensions.swift +++ b/test/IRGen/objc_extensions.swift @@ -27,7 +27,7 @@ import objc_extension_base // CHECK-SAME: @"_CATEGORY_CLASS_METHODS_Gizmo_$_objc_extensions", // CHECK-SAME: @"_CATEGORY_PROTOCOLS_Gizmo_$_objc_extensions", // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 @objc protocol NewProtocol { func brandNewInstanceMethod() @@ -67,7 +67,7 @@ extension Gizmo: NewProtocol { // CHECK: {{.*}} @"_CATEGORY_CLASS_METHODS_Gizmo_$_objc_extensions1", // CHECK: i8* null, // CHECK: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 extension Gizmo { @objc func brandSpankingNewInstanceMethod() { @@ -92,7 +92,7 @@ class Hoozit : NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR:@.*]], i64 0, i64 0), // CHECK: i8* bitcast (void ([[OPAQUE:%.*]]*, i8*)* @"$s15objc_extensions6HoozitC7blibbleyyFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-LABEL: @"_CATEGORY_CLASS_METHODS__TtC15objc_extensions6Hoozit_$_objc_extensions" = internal constant // CHECK: i32 24, @@ -102,7 +102,7 @@ class Hoozit : NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR]], i64 0, i64 0), // CHECK: i8* bitcast (void (i8*, i8*)* @"$s15objc_extensions6HoozitC7blobbleyyFZTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-LABEL: @"_CATEGORY__TtC15objc_extensions6Hoozit_$_objc_extensions" = internal constant // CHECK: i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[CATEGORY_NAME]], i64 0, i64 0), @@ -111,7 +111,7 @@ class Hoozit : NSObject { // CHECK: {{.*}} @"_CATEGORY_CLASS_METHODS__TtC15objc_extensions6Hoozit_$_objc_extensions", // CHECK: i8* null, // CHECK: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 extension Hoozit { @objc func blibble() { } @@ -127,7 +127,7 @@ class SwiftOnly { } // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(wibble)", i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[STR]], i64 0, i64 0), // CHECK: i8* bitcast (void (i8*, i8*)* @"$s15objc_extensions9SwiftOnlyC6wibbleyyFTo" to i8*) -// CHECK: }] }, section "__DATA, __objc_const", align 8 +// CHECK: }] }, section "__DATA, {{.*}}", align 8 extension SwiftOnly { @objc func wibble() { } } @@ -157,7 +157,7 @@ extension NSObject { // CHECK-SAME: i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[CATEGORY_NAME]], i64 0, i64 0), // CHECK-SAME: @"_CATEGORY_INSTANCE_METHODS__TtCC15objc_extensions5Outer5Inner_$_objc_extensions", // CHECK-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 class Outer : NSObject { class Inner : NSObject {} @@ -175,7 +175,7 @@ class NSDogcow : NSObject {} // CHECK: [[NAME:@.*]] = private unnamed_addr constant [5 x i8] c"woof\00" // CHECK: [[ATTR:@.*]] = private unnamed_addr constant [7 x i8] c"Tq,N,D\00" -// CHECK: @"_CATEGORY_PROPERTIES__TtC15objc_extensions8NSDogcow_$_objc_extensions" = internal constant {{.*}} [[NAME]], {{.*}} [[ATTR]], {{.*}}, section "__DATA, __objc_const", align 8 +// CHECK: @"_CATEGORY_PROPERTIES__TtC15objc_extensions8NSDogcow_$_objc_extensions" = internal constant {{.*}} [[NAME]], {{.*}} [[ATTR]], {{.*}}, section "__DATA, {{.*}}", align 8 extension NSDogcow { @NSManaged var woof: Int } diff --git a/test/IRGen/objc_methods.swift b/test/IRGen/objc_methods.swift index 0179649e064d3..4f517c9608339 100644 --- a/test/IRGen/objc_methods.swift +++ b/test/IRGen/objc_methods.swift @@ -79,7 +79,7 @@ class ObjcDestructible: NSObject { // CHECK-macosx: i8* bitcast (i8 (i8*, i8*, %4**)* @"$s12objc_methods3FooC4failyyKFTo" to i8*) // CHECK-ios: i8* bitcast (i1 (i8*, i8*, %4**)* @"$s12objc_methods3FooC4failyyKFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_INSTANCE_METHODS__TtC12objc_methods16ObjcDestructible = internal constant { {{.*}}] } { // CHECK: i32 24, // CHECK: i32 2, @@ -88,7 +88,7 @@ class ObjcDestructible: NSObject { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[NO_ARGS_SIGNATURE]], i64 0, i64 0), // CHECK: i8* bitcast (void (%6*, i8*)* @"$s12objc_methods16ObjcDestructibleCfETo" to i8*) }] // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[BLOCK_SIGNATURE_EXT_1:@.*]] = private unnamed_addr constant [18 x i8] c"v24@0:8@?16\00" // CHECK: [[BLOCK_SIGNATURE_EXT_2:@.*]] = private unnamed_addr constant [19 x i8] c"v24@0:8@?16\00" // CHECK: [[STRING_SIGNATURE_EXT:@.*]] = private unnamed_addr constant [31 x i8] c"@\22NSString\2224@0:8@\22NSString\2216\00" diff --git a/test/IRGen/objc_properties.swift b/test/IRGen/objc_properties.swift index d126722124edd..d8f4273216ecf 100644 --- a/test/IRGen/objc_properties.swift +++ b/test/IRGen/objc_properties.swift @@ -112,7 +112,7 @@ class SomeWrapperTests { // CHECK-NEW: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[SHARED_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[SHARED_ATTRS]], i64 0, i64 0) // CHECK-NEW: }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 // CHECK: @_METACLASS_DATA__TtC15objc_properties10SomeObject = internal constant { {{.*}} } { // CHECK-SAME: i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, @@ -122,7 +122,7 @@ class SomeWrapperTests { // CHECK-SAME: i8* null, i8* null, i8* null, // CHECK-NEW-SAME: { {{.+}} }* @_CLASS_PROPERTIES__TtC15objc_properties10SomeObject // CHECK-OLD-SAME: i8* null -// CHECK-SAME: }, section "__DATA, __objc_const", align 8 +// CHECK-SAME: }, section "__DATA, {{.*}}", align 8 // CHECK: [[GETTER_SIGNATURE:@.*]] = private unnamed_addr constant [8 x i8] c"@16@0:8\00" // CHECK: [[SETTER_SIGNATURE:@.*]] = private unnamed_addr constant [11 x i8] c"v24@0:8@16\00" @@ -163,7 +163,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[GETTER_SIGNATURE]], i64 0, i64 0), // CHECK: @"$s15objc_properties10SomeObjectCACycfcTo{{(.ptrauth)?}}" // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // This appears earlier because it's also used in an ivar description. // CHECK: [[BAREIVAR_NAME:@.*]] = private unnamed_addr constant [9 x i8] c"bareIvar\00" @@ -195,7 +195,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[WIBBLE_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([50 x i8], [50 x i8]* [[WIBBLE_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_DATA__TtC15objc_properties10SomeObject = internal constant { {{.+}} } { // CHECK: i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, i32 {{[0-9]+}}, @@ -206,7 +206,7 @@ class SomeWrapperTests { // CHECK: { {{.+}} }* @_IVARS__TtC15objc_properties10SomeObject, // CHECK: i8* null, // CHECK: { {{.+}} }* @_PROPERTIES__TtC15objc_properties10SomeObject -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @"_CATEGORY_INSTANCE_METHODS__TtC15objc_properties10SomeObject_$_objc_properties" = internal constant { {{.*}}] } { // CHECK: i32 24, @@ -220,7 +220,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[SETTER_SIGNATURE]], i64 0, i64 0), // CHECK: @"$s15objc_properties10SomeObjectC17extensionPropertyACvsTo{{(.ptrauth)?}}" // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[EXTENSIONPROPERTY_NAME:@.*]] = private unnamed_addr constant [18 x i8] c"extensionProperty\00" @@ -231,7 +231,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[EXTENSIONPROPERTY_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([42 x i8], [42 x i8]* [[READWRITE_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-NEW: [[EXTENSIONCLASSPROPERTY_NAME:@.*]] = private unnamed_addr constant [19 x i8] c"extensionClassProp\00" // CHECK-NEW: [[EXTENSIONCLASSPROPERTY_ATTRS:@.*]] = private unnamed_addr constant [7 x i8] c"T#,N,R\00" @@ -246,7 +246,7 @@ class SomeWrapperTests { // CHECK-NEW: }, { // CHECK-NEW: i8* getelementptr inbounds ([26 x i8], [26 x i8]* [[EXTENSIONSTATICPROPERTY_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[SHARED_ATTRS]], i64 0, i64 0) }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 // CHECK: @"_CATEGORY__TtC15objc_properties10SomeObject_$_objc_properties" = internal constant { {{.+}} } { // CHECK: i8* getelementptr inbounds ([{{.+}} x i8], [{{.+}} x i8]* {{@.+}}, i64 0, i64 0), @@ -258,7 +258,7 @@ class SomeWrapperTests { // CHECK-NEW: { {{.+}} }* @"_CATEGORY_CLASS_PROPERTIES__TtC15objc_properties10SomeObject_$_objc_properties", // CHECK-OLD: i8* null, // CHECK: i32 60 -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: @_INSTANCE_METHODS__TtC15objc_properties4Tree = @@ -283,7 +283,7 @@ class SomeWrapperTests { // CHECK: i8* null, // CHECK-NEW: { {{.+}} }* @_PROTOCOL_CLASS_PROPERTIES__TtP15objc_properties5Proto_ // CHECK-OLD: i8* null -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK: [[PROTOCOLPROPERTY_NAME:@.+]] = private unnamed_addr constant [6 x i8] c"value\00" @@ -296,7 +296,7 @@ class SomeWrapperTests { // CHECK: i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[PROTOCOLPROPERTY_NAME]], i64 0, i64 0), // CHECK: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[PROTOCOLPROPERTY_ATTRS]], i64 0, i64 0) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // CHECK-NEW: [[PROTOCOLCLASSPROPERTY_NAME:@.+]] = private unnamed_addr constant [15 x i8] c"sharedInstance\00" // CHECK-NEW: [[PROTOCOLCLASSPROPERTY_ATTRS:@.+]] = private unnamed_addr constant [7 x i8] c"T@,N,&\00" @@ -308,4 +308,4 @@ class SomeWrapperTests { // CHECK-NEW: i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[PROTOCOLCLASSPROPERTY_NAME]], i64 0, i64 0), // CHECK-NEW: i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[PROTOCOLCLASSPROPERTY_ATTRS]], i64 0, i64 0) // CHECK-NEW: }] -// CHECK-NEW: }, section "__DATA, __objc_const", align 8 +// CHECK-NEW: }, section "__DATA, {{.*}}", align 8 diff --git a/test/IRGen/objc_protocols.swift b/test/IRGen/objc_protocols.swift index 8a7a237bd37da..60dec14632ed5 100644 --- a/test/IRGen/objc_protocols.swift +++ b/test/IRGen/objc_protocols.swift @@ -32,7 +32,7 @@ class Foo : NSRuncing, NSFunging, Ansible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3FooC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3FooC3fooyyFTo" to i8*) // CHECK: }] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 class Bar { func bar() {} @@ -57,7 +57,7 @@ extension Bar : NSRuncing, NSFunging { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3BarC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3BarC3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // class Bas from objc_protocols_Bas module extension Bas : NSRuncing { @@ -71,7 +71,7 @@ extension Bas : NSRuncing { // CHECK: [1 x { i8*, i8*, i8* }] [ // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas0C0C0a1_B0E3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // -- Swift protocol refinement of ObjC protocols. protocol Frungible : NSRuncing, NSFunging { @@ -93,7 +93,7 @@ class Zim : Frungible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(funge)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3ZimC5fungeyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s14objc_protocols3ZimC3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 // class Zang from objc_protocols_Bas module extension Zang : Frungible { @@ -112,7 +112,7 @@ extension Zang : Frungible { // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_selector_data(runce)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas4ZangC0a1_B0E5runceyyFTo" to i8*) }, // CHECK: { i8*, i8*, i8* } { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_selector_data(foo)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[ENC]], i64 0, i64 0), i8* bitcast (void (i8*, i8*)* @"$s18objc_protocols_Bas4ZangC0a1_B0E3fooyyFTo" to i8*) } // CHECK: ] -// CHECK: }, section "__DATA, __objc_const", align 8 +// CHECK: }, section "__DATA, {{.*}}", align 8 @objc protocol BaseProtocol { } protocol InheritingProtocol : BaseProtocol { } diff --git a/test/IRGen/objc_runtime_name_local_class_opaque_type.swift b/test/IRGen/objc_runtime_name_local_class_opaque_type.swift new file mode 100644 index 0000000000000..deef2463abef2 --- /dev/null +++ b/test/IRGen/objc_runtime_name_local_class_opaque_type.swift @@ -0,0 +1,19 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend %s -disable-availability-checking -emit-ir | %FileCheck %s + +// REQUIRES: objc_interop + +protocol MyProtocol {} + +func returnsClass1() -> some MyProtocol { + class MyClass1: MyProtocol {} + return MyClass1() +} + +var returnsClass2: some MyProtocol { + class MyClass2: MyProtocol {} + return MyClass2() +} + +// CHECK: @_DATA__TtCF41objc_runtime_name_local_class_opaque_type13returnsClass1FT_QuL_8MyClass1 = internal constant +// CHECK: @_DATA__TtCF41objc_runtime_name_local_class_opaque_typeg13returnsClass2QuL_8MyClass2 = internal constant diff --git a/test/IRGen/objc_subclass.swift b/test/IRGen/objc_subclass.swift index 3fa2541722ef3..f2fa4d2395be3 100644 --- a/test/IRGen/objc_subclass.swift +++ b/test/IRGen/objc_subclass.swift @@ -35,7 +35,7 @@ // CHECK-32: i8* null, // CHECK-32: i8* null, // CHECK-32: i8* null -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_METACLASS_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-64: i32 129, @@ -49,7 +49,7 @@ // CHECK-64: i8* null, // CHECK-64: i8* null, // CHECK-64: i8* null -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-32: [[METHOD_TYPE_ENCODING1:@.*]] = private unnamed_addr constant [7 x i8] c"l8@0:4\00" // CHECK-64: [[METHOD_TYPE_ENCODING1:@.*]] = private unnamed_addr constant [8 x i8] c"q16@0:8\00" @@ -110,7 +110,7 @@ // CHECK-32: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i32 0, i32 0), // CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-32: }] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_INSTANCE_METHODS__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}] } { // CHECK-64: i32 24, @@ -160,7 +160,7 @@ // CHECK-64: i8* getelementptr inbounds ([{{[0-9]+}} x i8], [{{[0-9]+}} x i8]* {{@[0-9]+}}, i64 0, i64 0), // CHECK-64: i8* bitcast ({{.*}}* @"$s13objc_subclass10SwiftGizmoCfeTo{{(\.ptrauth)?}}" to i8*) // CHECK-64: }] -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK: [[STRING_X:@.*]] = private unnamed_addr constant [2 x i8] c"x\00" // CHECK-64: [[STRING_EMPTY:@.*]] = private unnamed_addr constant [1 x i8] zeroinitializer @@ -174,7 +174,7 @@ // CHECK-32: i8* getelementptr inbounds ([1 x i8], [1 x i8]* {{.*}}, i32 0, i32 0), // CHECK-32: i32 2, // CHECK-32: i32 4 }] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_IVARS__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}] } { // CHECK-64: i32 32, @@ -185,7 +185,7 @@ // CHECK-64: i8* getelementptr inbounds ([1 x i8], [1 x i8]* [[STRING_EMPTY]], i64 0, i64 0), // CHECK-64: i32 3, // CHECK-64: i32 8 }] -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-32: @_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-32: i32 132, @@ -198,7 +198,7 @@ // CHECK-32: @_IVARS__TtC13objc_subclass10SwiftGizmo, // CHECK-32: i8* null, // CHECK-32: @_PROPERTIES__TtC13objc_subclass10SwiftGizmo -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_DATA__TtC13objc_subclass10SwiftGizmo = internal constant { {{.*}}* } { // CHECK-64: i32 132, @@ -212,7 +212,7 @@ // CHECK-64: @_IVARS__TtC13objc_subclass10SwiftGizmo, // CHECK-64: i8* null, // CHECK-64: @_PROPERTIES__TtC13objc_subclass10SwiftGizmo -// CHECK-64: }, section "__DATA, __objc_const", align 8 +// CHECK-64: }, section "__DATA, {{.*}}", align 8 // CHECK-NOT: @_TMCSo13SwiftGizmo = {{.*NSObject}} @@ -247,7 +247,7 @@ // CHECK-32: i8* bitcast ({{.*}}* @"$s13objc_subclass11SwiftGizmo2CfETo{{(\.ptrauth)?}}" to i8*) // CHECK-32: } // CHECK-32: ] -// CHECK-32: }, section "__DATA, __objc_const", align 4 +// CHECK-32: }, section "__DATA, {{.*}}", align 4 // CHECK-64: @_INSTANCE_METHODS__TtC13objc_subclass11SwiftGizmo2 = internal constant { i32, {{.*}}] } { // CHECK-64: i32 24, diff --git a/test/IRGen/objc_super.swift b/test/IRGen/objc_super.swift index 72b045bd7ea2f..645e75c53cc53 100644 --- a/test/IRGen/objc_super.swift +++ b/test/IRGen/objc_super.swift @@ -136,5 +136,5 @@ class GenericRuncer : Gizmo { } // CHECK: define internal swiftcc void [[PARTIAL_FORWARDING_THUNK]](%swift.refcounted* swiftself %0) {{.*}} { -// CHECK: @"$ss12StaticStringV14withUTF8BufferyxxSRys5UInt8VGXElFyAEcfU_" +// CHECK: @"$ss12StaticStringV14withUTF8BufferyxxSRys5UInt8VGXElFxAFXEfU_" // CHECK: } diff --git a/test/IRGen/objc_type_encoding.swift b/test/IRGen/objc_type_encoding.swift index 571aedaa01f3c..8a685138398fe 100644 --- a/test/IRGen/objc_type_encoding.swift +++ b/test/IRGen/objc_type_encoding.swift @@ -188,4 +188,4 @@ class C: P { } // CHECK-macosx: [[ENC5:@.*]] = private unnamed_addr constant [9 x i8] c"Vv16@0:8\00" -// CHECK-macosx: @_PROTOCOL_INSTANCE_METHODS_P = {{.*}}@"\01L_selector_data(stuff)"{{.*}}[[ENC5]]{{.*}}, section "__DATA, __objc_const", align 8 +// CHECK-macosx: @_PROTOCOL_INSTANCE_METHODS_P = {{.*}}@"\01L_selector_data(stuff)"{{.*}}[[ENC5]]{{.*}} diff --git a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift index 2663a2cca72e6..55ff2d6fcc035 100644 --- a/test/IRGen/prespecialized-metadata/class-class-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/class-class-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift index 95a5442e2b714..14b4cc981df34 100644 --- a/test/IRGen/prespecialized-metadata/enum-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/enum-extra-data-fields.swift -emit-library -emit-module -enable-library-evolution -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift index ea75b7539bce4..227b8f31f23ec 100644 --- a/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/enum-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift index f19d12e904ccc..4c17598420c26 100644 --- a/test/IRGen/prespecialized-metadata/struct-extradata-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-extradata-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/extraDataFields.cpp -o %t/extraDataFields.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsNoTrailingFlags -target %module-target-future -Xfrontend -disable-generic-metadata-prespecialization -emit-module-path %t/ExtraDataFieldsNoTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsNoTrailingFlags) // RUN: %target-build-swift -c %S/Inputs/struct-extra-data-fields.swift -emit-library -emit-module -module-name ExtraDataFieldsTrailingFlags -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/ExtraDataFieldsTrailingFlags.swiftmodule -o %t/%target-library-name(ExtraDataFieldsTrailingFlags) diff --git a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift index 6b5673c8ce58a..2eadbb46f97ca 100644 --- a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift +++ b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift @@ -5,7 +5,7 @@ // RUN: %target-build-swift -c %s -DCONFORMANCE_2 -emit-library -emit-module -module-name Conformance2 -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Conformance2.swiftmodule -o %t/%target-library-name(Conformance2) -lBase -I %t -L %t // RUN: %target-build-swift -c %s -DGENERIC -emit-library -emit-module -module-name Generic -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Generic.swiftmodule -o %t/%target-library-name(Generic) -lBase -lConformance1 -I %t -L %t // RUN: %target-build-swift -c %s -DERASE -emit-library -emit-module -module-name Erase -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Erase.swiftmodule -o %t/%target-library-name(Erase) -lBase -lConformance2 -I %t -L %t -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %s %S/Inputs/main.swift %S/Inputs/consume-logging-metadata-value.swift %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -DMAIN -target %module-target-future -Xfrontend -prespecialize-generic-metadata -lBase -lConformance1 -lConformance2 -lGeneric -lErase -lc++ -I %t -L %t -L %clang-include-dir/../lib/swift/macosx -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift index d1358133b9288..d91573301b7ed 100644 --- a/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-outmodule-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift %S/Inputs/struct-public-nonfrozen-1argument.swift -emit-module -emit-library -module-name Module -Xfrontend -prespecialize-generic-metadata -target %module-target-future -emit-module-path %t/Module.swiftmodule -o %t/%target-library-name(Module) diff --git a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift index 97001c01108c2..a896e21db6e9f 100644 --- a/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift +++ b/test/IRGen/prespecialized-metadata/struct-trailing-flags-run.swift @@ -1,5 +1,5 @@ // RUN: %empty-directory(%t) -// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %llvm_src_root/include -I %llvm_obj_root/include -L %clang-include-dir/../lib/swift/macosx // RUN: %target-build-swift -v %mcp_opt %s %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -Xfrontend -prespecialize-generic-metadata -target %module-target-future -lc++ -L %clang-include-dir/../lib/swift/macosx -sdk %sdk -o %t/main // RUN: %target-codesign %t/main diff --git a/test/IRGen/subclass_existentials.sil b/test/IRGen/subclass_existentials.sil index 28295cc27dfa1..efbea61883f6b 100644 --- a/test/IRGen/subclass_existentials.sil +++ b/test/IRGen/subclass_existentials.sil @@ -109,7 +109,7 @@ bb0(%0 : @owned $C, %1 : @owned $C & P): return %result : $() } -// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* %0, %swift.type* %1, %swift.type* +// CHECK-LABEL: define linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_superclass_unconditional(i8* %0, %swift.type* %1, %swift.type* // CHECK: entry: // CHECK-NEXT: [[RESULT:%.*]] = call %swift.type* @swift_dynamicCastMetatype(%swift.type* %1, %swift.type* %2) // CHECK-NEXT: [[IS_SUBCLASS:%.*]] = icmp ne %swift.type* [[RESULT]], null @@ -150,7 +150,7 @@ bb0(%0 : @owned $C): return %result : $() } -// CHECK-LABEL: define private { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* +// CHECK-LABEL: define linkonce_odr hidden { i8*, i8** } @dynamic_cast_existential_1_unconditional(i8* %0, %swift.type* // CHECK: entry: // CHECK-NEXT: [[WTABLE:%.*]] = call i8** @swift_conformsToProtocol(%swift.type* %1, {{.*}} %2) // CHECK-NEXT: [[IS_NOT_CONFORMING:%.*]] = icmp eq i8** [[WTABLE]], null diff --git a/test/Index/index_keypaths.swift b/test/Index/index_keypaths.swift index 2405032541afa..96b8d367934bb 100644 --- a/test/Index/index_keypaths.swift +++ b/test/Index/index_keypaths.swift @@ -1,27 +1,47 @@ -// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s +// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -print-indexed-symbols -source-filename %s | %FileCheck %s // REQUIRES: objc_interop +import Foundation + struct MyStruct { struct Inner { let myProp = 1 } } -class MyClass { - class Inner { - @objc var myProp = 1 - } -} - let a = \MyStruct.Inner.myProp // CHECK: [[@LINE-1]]:25 | {{.*}} | myProp // CHECK: [[@LINE-2]]:10 | {{.*}} | MyStruct // CHECK: [[@LINE-3]]:19 | {{.*}} | Inner let b: KeyPath = \.myProp // CHECK: [[@LINE-1]]:41 | {{.*}} | myProp -let c = \MyClass.Inner.myProp + +@objc class MyClass: NSObject { + @objc class Inner: NSObject { + @objc var myProp = 1 + @objc var otherProp:[String: MyClass.Inner] = [:] + func method() { + let c: String = #keyPath(myProp) + // CHECK: [[@LINE-1]]:32 | {{.*}} | myProp + } + } +} + +let d: String = #keyPath(MyClass.Inner.myProp) +// CHECK: [[@LINE-1]]:26 | {{.*}} | MyClass +// CHECK: [[@LINE-2]]:34 | {{.*}} | Inner +// CHECK: [[@LINE-3]]:40 | {{.*}} | myProp + +let e = \MyClass.Inner.myProp // CHECK: [[@LINE-1]]:24 | {{.*}} | myProp // CHECK: [[@LINE-2]]:10 | {{.*}} | MyClass // CHECK: [[@LINE-3]]:18 | {{.*}} | Inner -let d: KeyPath = \.myProp + +let f: KeyPath = \.myProp // CHECK: [[@LINE-1]]:40 | {{.*}} | myProp + +let g: String = #keyPath(MyClass.Inner.otherProp.someDictKey.myProp) +// CHECK: [[@LINE-1]]:26 | {{.*}} | MyClass +// CHECK: [[@LINE-2]]:34 | {{.*}} | Inner +// CHECK: [[@LINE-3]]:40 | {{.*}} | otherProp +// CHECK: [[@LINE-4]]:62 | {{.*}} | myProp diff --git a/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift b/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift index 960250708c027..8c447d83713de 100644 --- a/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift +++ b/test/Inputs/clang-importer-sdk/swift-modules/CoreFoundation.swift @@ -1,3 +1,3 @@ @_exported import CoreFoundation -protocol _CFObject {} +protocol _CFObject: Hashable {} diff --git a/test/Interop/Cxx/class/Inputs/type-classification.h b/test/Interop/Cxx/class/Inputs/type-classification.h index 785c5ef278a73..09322bb5d0d1e 100644 --- a/test/Interop/Cxx/class/Inputs/type-classification.h +++ b/test/Interop/Cxx/class/Inputs/type-classification.h @@ -155,4 +155,22 @@ struct StructDeletedDestructor { ~StructDeletedDestructor() = delete; }; +struct StructWithCopyConstructorAndValue { + int value; + StructWithCopyConstructorAndValue( + const StructWithCopyConstructorAndValue &other) + : value(other.value) {} +}; + +struct StructWithSubobjectCopyConstructorAndValue { + StructWithCopyConstructorAndValue member; +}; + +struct StructWithCopyConstructorAndSubobjectCopyConstructorAndValue { + StructWithCopyConstructorAndValue member; + StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + const StructWithCopyConstructorAndSubobjectCopyConstructorAndValue &other) + : member(other.member) {} +}; + #endif diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift new file mode 100644 index 0000000000000..fcbf32cff73d5 --- /dev/null +++ b/test/Interop/Cxx/class/type-classification-non-trivial-irgen.swift @@ -0,0 +1,99 @@ +// RUN: %target-swift-frontend -enable-cxx-interop -I %S/Inputs %s -emit-ir | %FileCheck %s + +// Verify that non-trival/address-only C++ classes are constructed and accessed +// correctly. Make sure that we correctly IRGen functions that construct +// non-trivial C++ classes, take those classes as a parameter, and access those +// classes members. + +import TypeClassification + +// TODO: C++ objects with destructors should be tested here once we fully +// support them. + +// CHECK-LABEL: define {{.*}}i1 @"$s4main37testStructWithCopyConstructorAndValueSbyF" +// CHECK: [[OBJ:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[VAL_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 +// CHECK: [[VAL_INT:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL_ELEMENT]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[VAL_INT]] +// CHECK: ret i1 true +public func testStructWithCopyConstructorAndValue() -> Bool { + let obj = StructWithCopyConstructorAndValue(value: 42) + return obj.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF"() +// CHECK: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[OBJ:%.*]] = alloca %TSo42StructWithSubobjectCopyConstructorAndValueV +// CHECK: alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER_ELEMENT:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 +// CHECK: [[MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_ELEMENT]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[MEMBER_VALUE]] +// CHECK: %obj.member = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* [[OBJ]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER_VALUE:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VALUE]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF"() +// CHECK: [[MEMBER:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: alloca %TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV +// CHECK: alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER_VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[MEMBER]], i32 0, i32 0 +// CHECK: [[MEMBER_VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[MEMBER_VAL]], i32 0, i32 0 +// CHECK: store i32 42, i32* [[MEMBER_VAL_VAL]] +// CHECK: [[TEMP_MEMBER:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP]], i32 0, i32 0 +// CHECK: [[TEMP_MEMBER_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[TEMP_MEMBER]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[TEMP_MEMBER_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +-> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF"(%TSo33StructWithCopyConstructorAndValueV* noalias nocapture dereferenceable(4) %0) +// CHECK: [[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* %0, i32 0, i32 0 +// CHECK: [[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 %1, 42 +// CHECK: ret i1 [[OUT]] +public func test(obj: StructWithCopyConstructorAndValue) -> Bool { + return obj.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF"(%TSo42StructWithSubobjectCopyConstructorAndValueV* noalias nocapture dereferenceable(4) %0) +// CHECK: [[TMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK: [[MEMBER:%.*]] = getelementptr inbounds %TSo42StructWithSubobjectCopyConstructorAndValueV, %TSo42StructWithSubobjectCopyConstructorAndValueV* %0, i32 0, i32 0 +// CHECK: [[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TMP]], i32 0, i32 0 +// CHECK: [[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK: [[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK: [[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK: ret i1 [[OUT]] +public func test(obj: StructWithSubobjectCopyConstructorAndValue) -> Bool { + return obj.member.value == 42 +} + +// CHECK-LABEL: define {{.*}}i1 @"$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF"(%TSo037StructWithCopyConstructorAndSubobjectcdE5ValueV* noalias nocapture dereferenceable(4) %0) +// CHECK:[[TEMP:%.*]] = alloca %TSo33StructWithCopyConstructorAndValueV +// CHECK:[[VAL:%.*]] = getelementptr inbounds %TSo33StructWithCopyConstructorAndValueV, %TSo33StructWithCopyConstructorAndValueV* [[TEMP]], i32 0, i32 0 +// CHECK:[[VAL_VAL:%.*]] = getelementptr inbounds %Ts5Int32V, %Ts5Int32V* [[VAL]], i32 0, i32 0 +// CHECK:[[LHS:%.*]] = load i32, i32* [[VAL_VAL]] +// CHECK:[[OUT:%.*]] = icmp eq i32 [[LHS]], 42 +// CHECK:ret i1 [[OUT]] +public func test( + obj: StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +) -> Bool { + return obj.member.value == 42 +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift index 3ed07447a4cfe..87766b5a01bdb 100644 --- a/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift +++ b/test/Interop/Cxx/class/type-classification-non-trivial-silgen.swift @@ -1,25 +1,212 @@ -// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-sil %s | %FileCheck %s +// RUN: %target-swift-frontend -I %S/Inputs -enable-cxx-interop -emit-silgen %s | %FileCheck %s import TypeClassification // Make sure that "StructWithDestructor" is marked as non-trivial by checking for a // "destroy_addr". -// CHECK-LABEL: @$s4main24testStructWithDestructoryyF +// CHECK-LABEL: sil [ossa] @$s4main24testStructWithDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithDestructor +// CHECK: [[META:%.*]] = metatype $@thin StructWithDestructor.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor // CHECK: destroy_addr [[AS]] +// CHECK: dealloc_stack %0 : $*StructWithDestructor // CHECK-LABEL: end sil function '$s4main24testStructWithDestructoryyF' public func testStructWithDestructor() { let d = StructWithDestructor() } -// Make sure that "StructWithSubobjectDestructor" is marked as non-trivial by checking +// StructWithDestructor.init() +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo20StructWithDestructorVABycfC : $@convention(method) (@thin StructWithDestructor.Type) -> @out StructWithDestructor +// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithDestructor } +// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithDestructor } +// CHECK: [[BOX_ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithDestructor }, 0 +// CHECK: [[SA:%.*]] = alloc_stack $StructWithDestructor +// CHECK: builtin "zeroInitializer"([[SA]] : $*StructWithDestructor) : $() +// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[BOX_ADDR]] : $*StructWithDestructor +// CHECK: copy_addr [take] [[SA]] to [[BA]] : $*StructWithDestructor +// CHECK: copy_addr [[BOX_ADDR]] to [initialization] %0 : $*StructWithDestructor +// CHECK: destroy_value [[UBOX]] : ${ var StructWithDestructor } +// CHECK-LABEL: end sil function '$sSo20StructWithDestructorVABycfC' + +// Make sure that "HasMemberWithDestructor" is marked as non-trivial by checking // for a "destroy_addr". -// CHECK-LABEL: @$s4main33testStructWithSubobjectDestructoryyF +// CHECK-LABEL: sil [ossa] @$s4main33testStructWithSubobjectDestructoryyF // CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor +// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectDestructor.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: apply [[FN]]([[AS]], [[META]]) : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor // CHECK: destroy_addr [[AS]] // CHECK-LABEL: end sil function '$s4main33testStructWithSubobjectDestructoryyF' public func testStructWithSubobjectDestructor() { let d = StructWithSubobjectDestructor() } +// StructWithSubobjectDestructor.init() +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo29StructWithSubobjectDestructorVABycfC : $@convention(method) (@thin StructWithSubobjectDestructor.Type) -> @out StructWithSubobjectDestructor +// CHECK: [[BOX:%.*]] = alloc_box ${ var StructWithSubobjectDestructor } +// CHECK: [[UBOX:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructWithSubobjectDestructor } +// CHECK: [[ADDR:%.*]] = project_box [[UBOX]] : ${ var StructWithSubobjectDestructor }, 0 +// CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectDestructor +// CHECK: builtin "zeroInitializer"([[AS]] : $*StructWithSubobjectDestructor) : $() +// CHECK: [[BA:%.*]] = begin_access [modify] [unknown] [[ADDR]] : $*StructWithSubobjectDestructor +// CHECK: copy_addr [take] [[AS]] to [[BA]] : $*StructWithSubobjectDestructor +// CHECK: copy_addr [[ADDR]] to [initialization] %0 : $*StructWithSubobjectDestructor +// CHECK: destroy_value [[UBOX]] : ${ var StructWithSubobjectDestructor } +// CHECK-LABEL: end sil function '$sSo29StructWithSubobjectDestructorVABycfC' + +// CHECK-LABLE: sil [ossa] @$s4main37testStructWithCopyConstructorAndValueSbyF +// CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], %{{.*}}, [[META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], %{{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[CMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[CMP_FN]]([[OBJ_VAL]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: destroy_addr [[AS]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABLE: end sil function '$s4main37testStructWithCopyConstructorAndValueSbyF' +public func testStructWithCopyConstructorAndValue() -> Bool { + let obj = StructWithCopyConstructorAndValue(value: 42) + return obj.value == 42 +} + +// StructWithCopyConstructorAndValue.init(value:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[VAL:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: store %1 to [trivial] [[VAL]] : $*Int32 +// CHECK-LABEL: end sil function '$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC' + +// CHECK-LABEL: sil [ossa] @$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[MEMBER_META:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[MAKE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[MAKE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[MEMBER_META]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack $StructWithSubobjectCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithSubobjectCopyConstructorAndValue.Type +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr %0 to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr [[AS]] : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VALUE:%.*]] = load [trivial] [[OBJ_VALUE_ADDR]] : $*Int32 +// CHECK: [[MAKE_INT:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT]]({{.*}}) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_VALUE]], [[INT_42]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main46testStructWithSubobjectCopyConstructorAndValueSbyF' +public func testStructWithSubobjectCopyConstructorAndValue() -> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + return obj.member.value == 42 +} + +// StructWithSubobjectCopyConstructorAndValue.init(member:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithSubobjectCopyConstructorAndValue.Type) -> @out StructWithSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: copy_addr [take] %1 to [initialization] [[MEMBER]] : $*StructWithCopyConstructorAndValue +// CHECK-LABEL: end sil function '$sSo42StructWithSubobjectCopyConstructorAndValueV6memberABSo0abdefG0V_tcfC' +// testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +// CHECK-LABEL: sil [ossa] @$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF : $@convention(thin) () -> Bool +// CHECK: [[MEMBER_0:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: [[META_MEMBER:%.*]] = metatype $@thin StructWithCopyConstructorAndValue.Type +// CHECK: [[CREATE_MEMBER_FN:%.*]] = function_ref @$sSo33StructWithCopyConstructorAndValueV5valueABs5Int32V_tcfC : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: apply [[CREATE_MEMBER_FN]]([[MEMBER_0]], %{{.*}}, [[META_MEMBER]]) : $@convention(method) (Int32, @thin StructWithCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndValue +// CHECK: [[AS:%.*]] = alloc_stack $StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[META:%.*]] = metatype $@thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type +// CHECK: [[MEMBER_1:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[MEMBER_0]] to [initialization] [[MEMBER_1]] : $*StructWithCopyConstructorAndValue +// CHECK: [[FN:%.*]] = function_ref @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: apply [[FN]]([[AS]], [[MEMBER_1]], [[META]]) : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_ADDR:%.*]] = struct_element_addr [[AS]] : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_2:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER_ADDR]] to [initialization] [[MEMBER_2]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_2]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: [[ICMP:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP]]([[OBJ_MEMBER_VALUE]], %{{.*}}) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main041testStructWithCopyConstructorAndSubobjectefG5ValueSbyF' +public func testStructWithCopyConstructorAndSubobjectCopyConstructorAndValue() +-> Bool { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + return obj.member.value == 42 +} + +// StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.init(member:) +// CHECK-LABEL: sil shared [transparent] [serializable] [ossa] @$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC : $@convention(method) (@in StructWithCopyConstructorAndValue, @thin StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.Type) -> @out StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +// CHECK: [[MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: copy_addr [take] %1 to [initialization] [[MEMBER]] : $*StructWithCopyConstructorAndValue +// CHECK-LABEL: end sil function '$sSo037StructWithCopyConstructorAndSubobjectcdE5ValueV6memberABSo0abcdeG0V_tcfC' + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithCopyConstructorAndValue) -> Bool +// CHECK: [[META_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_VAL_ADDR:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_VAL:%.*]] = load [trivial] [[OBJ_VAL_ADDR]] : $*Int32 +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT:%.*]] = apply [[FN]]([[IL_42]], [[META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN_2:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN_2]]([[OBJ_VAL]], [[INT]], [[META_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo33StructWithCopyConstructorAndValueV_tF' +public func test(obj: StructWithCopyConstructorAndValue) -> Bool { + return obj.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF : $@convention(thin) (@in_guaranteed StructWithSubobjectCopyConstructorAndValue) -> Bool +// CHECK: [[INT_META:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithSubobjectCopyConstructorAndValue, #StructWithSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VALUE_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VALUE:%.*]] = load [trivial] [[OBJ_MEMBER_VALUE_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[INT_META_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[INT_META_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[FN]]([[OBJ_MEMBER_VALUE]], [[INT_42]], [[INT_META]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo42StructWithSubobjectCopyConstructorAndValueV_tF' +public func test(obj: StructWithSubobjectCopyConstructorAndValue) -> Bool { + return obj.member.value == 42 +} + +// CHECK-LABEL: sil [ossa] @$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF +// CHECK: [[META_INT_1:%.*]] = metatype $@thin Int32.Type +// CHECK: [[OBJ_MEMBER:%.*]] = struct_element_addr %0 : $*StructWithCopyConstructorAndSubobjectCopyConstructorAndValue, #StructWithCopyConstructorAndSubobjectCopyConstructorAndValue.member +// CHECK: [[MEMBER_TMP:%.*]] = alloc_stack $StructWithCopyConstructorAndValue +// CHECK: copy_addr [[OBJ_MEMBER]] to [initialization] [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[OBJ_MEMBER_VAL_ADDR:%.*]] = struct_element_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue, #StructWithCopyConstructorAndValue.value +// CHECK: [[OBJ_MEMBER_VAL:%.*]] = load [trivial] [[OBJ_MEMBER_VAL_ADDR]] : $*Int32 +// CHECK: destroy_addr [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: [[IL_42:%.*]] = integer_literal $Builtin.IntLiteral, 42 +// CHECK: [[META_INT_2:%.*]] = metatype $@thin Int32.Type +// CHECK: [[MAKE_INT_FN:%.*]] = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[INT_42:%.*]] = apply [[MAKE_INT_FN]]([[IL_42]], [[META_INT_2]]) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 +// CHECK: [[ICMP_FN:%.*]] = function_ref @$ss5Int32V2eeoiySbAB_ABtFZ : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: [[OUT:%.*]] = apply [[ICMP_FN]]([[OBJ_MEMBER_VAL]], [[INT_42]], [[META_INT_1]]) : $@convention(method) (Int32, Int32, @thin Int32.Type) -> Bool +// CHECK: dealloc_stack [[MEMBER_TMP]] : $*StructWithCopyConstructorAndValue +// CHECK: return [[OUT]] : $Bool +// CHECK-LABEL: end sil function '$s4main4test3objSbSo037StructWithCopyConstructorAndSubobjectfgH5ValueV_tF' +public func test( + obj: StructWithCopyConstructorAndSubobjectCopyConstructorAndValue +) -> Bool { + return obj.member.value == 42 +} diff --git a/test/Interop/Cxx/class/type-classification-non-trivial.swift b/test/Interop/Cxx/class/type-classification-non-trivial.swift new file mode 100644 index 0000000000000..489e6f71c7a40 --- /dev/null +++ b/test/Interop/Cxx/class/type-classification-non-trivial.swift @@ -0,0 +1,35 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %s -I %S/Inputs -o %t/address_only -Xfrontend -enable-cxx-interop +// RUN: %target-codesign %t/address_only +// RUN: %target-run %t/address_only 2&>1 + +// REQUIRES: executable_test + +import TypeClassification +import StdlibUnittest + +var AddressOnlyTestSuite = TestSuite("Address Only Types") + +AddressOnlyTestSuite.test("Test struct with copy constructor") { + let obj = StructWithCopyConstructorAndValue(value: 42) + expectEqual(obj.value, 42) +} + +AddressOnlyTestSuite.test("Test struct with member with copy constructor") { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithSubobjectCopyConstructorAndValue(member: member) + expectEqual(obj.member.value, 42) +} + +AddressOnlyTestSuite.test( + "Test struct with copy constructor and member with copy constructor" +) { + let member = StructWithCopyConstructorAndValue(value: 42) + let obj = StructWithCopyConstructorAndSubobjectCopyConstructorAndValue( + member: member + ) + expectEqual(obj.member.value, 42) +} + +runAllTests() + diff --git a/test/Interpreter/SDK/Inputs/libTestLoad.dylib b/test/Interpreter/SDK/Inputs/libTestLoad.dylib deleted file mode 100755 index d3d552658f1a3..0000000000000 Binary files a/test/Interpreter/SDK/Inputs/libTestLoad.dylib and /dev/null differ diff --git a/test/Interpreter/SDK/interpret_with_options.swift b/test/Interpreter/SDK/interpret_with_options.swift index 22e95023c2a8f..794dfbe5d8c07 100644 --- a/test/Interpreter/SDK/interpret_with_options.swift +++ b/test/Interpreter/SDK/interpret_with_options.swift @@ -1,8 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: echo "@interface ClassFromLibrary @end; @implementation ClassFromLibrary @end" | %clang -isysroot %sdk -Wno-objc-root-class -shared -o %t/libTestLoad.dylib -lobjc -x objective-c - // RUN: %swift_driver -sdk %sdk %s | %FileCheck -check-prefix=WITHOUT-LIB %s -// RUN: %swift_driver -sdk %sdk -L %S/Inputs/ -lTestLoad %s | %FileCheck -check-prefix=WITH-LIB %s -// RUN: %swift_driver -sdk %sdk -L %S/Inputs/ -llibTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s -// RUN: %swift_driver -sdk %sdk -l%S/Inputs/libTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s -// RUN: cd %S && %swift_driver -sdk %sdk -lInputs/libTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s +// RUN: %swift_driver -sdk %sdk -L %t -lTestLoad %s | %FileCheck -check-prefix=WITH-LIB %s +// RUN: %swift_driver -sdk %sdk -L %t -llibTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s +// RUN: %swift_driver -sdk %sdk -l%t/libTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s +// RUN: cd %S && %swift_driver -sdk %sdk -l%t/libTestLoad.dylib %s | %FileCheck -check-prefix=WITH-LIB %s + // REQUIRES: OS=macosx // REQUIRES: executable_test // REQUIRES: swift_interpreter diff --git a/test/Interpreter/SDK/objc_block_consumed.swift b/test/Interpreter/SDK/objc_block_consumed.swift index bee0890a639d6..5c591976d3d88 100644 --- a/test/Interpreter/SDK/objc_block_consumed.swift +++ b/test/Interpreter/SDK/objc_block_consumed.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -import-objc-header %S/Inputs/objc_block_consumed.h -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: executable_test diff --git a/test/Interpreter/SDK/objc_factory_method.swift b/test/Interpreter/SDK/objc_factory_method.swift index 712bfe950c464..bd768a04a7020 100644 --- a/test/Interpreter/SDK/objc_factory_method.swift +++ b/test/Interpreter/SDK/objc_factory_method.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -module-name FactoryTest %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test // REQUIRES: OS=macosx diff --git a/test/Interpreter/SDK/object_literals.swift b/test/Interpreter/SDK/object_literals.swift index 6a14ac895c247..85167094671ab 100644 --- a/test/Interpreter/SDK/object_literals.swift +++ b/test/Interpreter/SDK/object_literals.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t/Test.app/Contents/MacOS) // RUN: cp -r %S/Inputs/object_literals-Resources %t/Test.app/Contents/Resources // RUN: %target-build-swift %s -o %t/Test.app/Contents/MacOS/main +// RUN: %target-codesign %t/Test.app/Contents/MacOS/main // RUN: %target-run %t/Test.app/Contents/MacOS/main %t/Test.app/Contents/Resources/* // REQUIRES: executable_test diff --git a/test/Interpreter/bridged_casts_folding.swift b/test/Interpreter/bridged_casts_folding.swift index 31b5de2d61b3f..570a9b54e01da 100644 --- a/test/Interpreter/bridged_casts_folding.swift +++ b/test/Interpreter/bridged_casts_folding.swift @@ -57,7 +57,7 @@ Tests.test("NSString => Array. Crashing test case") { // CHECK: [ OK ] BridgedCastFolding.NSString => Array. Crashing test case // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.NSString => Array. Crashing test case - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.NSString => Array. Crashing test case expectCrashLater() do { @@ -129,7 +129,7 @@ Tests.test("NSNumber (Int) -> String. Crashing test.") { // CHECK: [ OK ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.NSNumber (Int) -> String. Crashing test. expectCrashLater() do { @@ -392,7 +392,7 @@ Tests.test("String -> NSNumber. Crashing Test Case") { // CHECK: [ OK ] BridgedCastFolding.String -> NSNumber. Crashing Test Case // CHECK-OPT-LABEL: [ RUN ] BridgedCastFolding.String -> NSNumber. Crashing Test Case - // CHECK-OPT: stderr>>> OK: saw expected "crashed: sigill" + // CHECK-OPT: stderr>>> OK: saw expected "crashed: sig{{ill|trap}}" // CHECK-OPT: [ OK ] BridgedCastFolding.String -> NSNumber. Crashing Test Case expectCrashLater() do { diff --git a/test/Interpreter/conditional_conformances_modules.swift b/test/Interpreter/conditional_conformances_modules.swift index d485c50974895..1fca8aae5113a 100644 --- a/test/Interpreter/conditional_conformances_modules.swift +++ b/test/Interpreter/conditional_conformances_modules.swift @@ -3,6 +3,7 @@ // RUN: %target-build-swift-dylib(%t/%target-library-name(WithAssoc)) %S/../Inputs/conditional_conformance_with_assoc.swift -module-name WithAssoc -emit-module -emit-module-path %t/WithAssoc.swiftmodule // RUN: %target-build-swift-dylib(%t/%target-library-name(Subclass)) %S/../Inputs/conditional_conformance_subclass.swift -module-name Subclass -emit-module -emit-module-path %t/Subclass.swiftmodule // RUN: %target-build-swift -I%t -L%t -lBasic -lWithAssoc -lSubclass %s -o %t/conditional_conformances_modules %target-rpath(%t) +// RUN: %target-codesign %t/conditional_conformances_modules // RUN: %target-run %t/conditional_conformances_modules %t/%target-library-name(Basic) %t/%target-library-name(WithAssoc) %t/%target-library-name(Subclass) // REQUIRES: executable_test diff --git a/test/Interpreter/generic_casts.swift b/test/Interpreter/generic_casts.swift index 73f1837d20ab9..0993c2d5e0810 100644 --- a/test/Interpreter/generic_casts.swift +++ b/test/Interpreter/generic_casts.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out // RUN: %target-build-swift -O %s -o %t/a.out.optimized +// RUN: %target-codesign %t/a.out // RUN: %target-codesign %t/a.out.optimized // // RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK %s diff --git a/test/Interpreter/generic_casts_objc.swift b/test/Interpreter/generic_casts_objc.swift index e9561d2e2e047..275711a2655bf 100644 --- a/test/Interpreter/generic_casts_objc.swift +++ b/test/Interpreter/generic_casts_objc.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -Onone %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck --check-prefix CHECK --check-prefix CHECK-ONONE %s // RUN: %target-build-swift -O %s -o %t/a.out.optimized // RUN: %target-codesign %t/a.out.optimized diff --git a/test/Interpreter/multi_payload_extra_inhabitant.swift b/test/Interpreter/multi_payload_extra_inhabitant.swift index 21aee2d92439a..03c1be8806c06 100644 --- a/test/Interpreter/multi_payload_extra_inhabitant.swift +++ b/test/Interpreter/multi_payload_extra_inhabitant.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -parse-stdlib -Xfrontend -verify-type-layout -Xfrontend SpareBitExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend SpareBitSingleExtraInhabitant -Xfrontend -verify-type-layout -Xfrontend SpareBitNoExtraInhabitant -Xfrontend -verify-type-layout -Xfrontend SpareBitNoExtraInhabitant2 -Xfrontend -verify-type-layout -Xfrontend TwoTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend ThreeTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend NoTagExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsNever -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsZeroBytes -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsOneByte -Xfrontend -verify-type-layout -Xfrontend DynamicExtraInhabitantsTwoBytes -Xfrontend -verify-type-layout -Xfrontend MoreSpareBitsThanTagsExtraInhabitants -Xfrontend -verify-type-layout -Xfrontend OptOptMoreSpareBitsThanTagsExtraInhabitants -O -o %t/a.out %s +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 // Type layout verifier is only compiled into the runtime in asserts builds. diff --git a/test/Interpreter/objc_class_properties_runtime.swift b/test/Interpreter/objc_class_properties_runtime.swift index 1d1cf21348c45..e2b848d798663 100644 --- a/test/Interpreter/objc_class_properties_runtime.swift +++ b/test/Interpreter/objc_class_properties_runtime.swift @@ -3,6 +3,7 @@ // RUN: %clang -arch %target-cpu -mmacosx-version-min=10.11 -isysroot %sdk -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o // RUN: %swiftc_driver -target $(echo '%target-triple' | sed -E -e 's/macosx10.(9|10).*/macosx10.11/') -sdk %sdk -I %S/Inputs/ObjCClasses/ %t/ObjCClasses.o %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out // REQUIRES: OS=macosx diff --git a/test/Interpreter/runtime_name_local_class_opaque_type.swift b/test/Interpreter/runtime_name_local_class_opaque_type.swift new file mode 100644 index 0000000000000..1b325fc10664b --- /dev/null +++ b/test/Interpreter/runtime_name_local_class_opaque_type.swift @@ -0,0 +1,24 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -Xfrontend -disable-availability-checking %s -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + +// REQUIRES: executable_test +// REQUIRES: objc_interop + +protocol MyProtocol {} + +func returnsClass1() -> some MyProtocol { + class MyClass1: MyProtocol {} + return MyClass1() +} + +var returnsClass2: some MyProtocol { + class MyClass2: MyProtocol {} + return MyClass2() +} + +print(returnsClass1()) +// CHECK: a.(unknown context at ${{[0-9a-z]+}}).(unknown context at ${{[0-9a-z]+}}).MyClass1 + +print(returnsClass2) +// CHECK: a.(unknown context at ${{[0-9a-z]+}}).(unknown context at ${{[0-9a-z]+}}).MyClass2 diff --git a/test/Interpreter/struct_extra_inhabitants.swift b/test/Interpreter/struct_extra_inhabitants.swift index b86568911fce6..38a4393c94fb9 100644 --- a/test/Interpreter/struct_extra_inhabitants.swift +++ b/test/Interpreter/struct_extra_inhabitants.swift @@ -5,6 +5,7 @@ // -- run tests // RUN: %target-build-swift -parse-stdlib -Xfrontend -verify-type-layout -Xfrontend PairWithPointerFirst -Xfrontend -verify-type-layout -Xfrontend PairWithPointerSecond -Xfrontend -verify-type-layout -Xfrontend PairWithPointerSecondAndPhantomParam_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerFirst_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerFirst_AnyObject -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerSecond_Int -Xfrontend -verify-type-layout -Xfrontend GenericPairWithPointerSecond_AnyObject -Xfrontend -verify-type-layout -Xfrontend StringAlike32 -Xfrontend -verify-type-layout -Xfrontend StringAlike64 -I %t -o %t/a.out.tests %s %t/ExtraInhabitantResilientTypes.o +// RUN: %target-codesign %t/a.out.tests // RUN: %target-run %t/a.out.tests 2>&1 // Type layout verifier is only compiled into the runtime in asserts builds. diff --git a/test/Interpreter/testable_key_path.swift b/test/Interpreter/testable_key_path.swift index de7c3f1ef79d2..7bcb16dceb178 100644 --- a/test/Interpreter/testable_key_path.swift +++ b/test/Interpreter/testable_key_path.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -whole-module-optimization -c -o %t/Module.o -enable-testing -parse-as-library -emit-module -emit-module-path %t/Module.swiftmodule -module-name Module %S/Inputs/testable_key_path_2.swift // RUN: %target-build-swift -o %t/a.out -I %t %s %t/Module.o +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Parse/async-syntax.swift b/test/Parse/async-syntax.swift new file mode 100644 index 0000000000000..54c1bac839969 --- /dev/null +++ b/test/Parse/async-syntax.swift @@ -0,0 +1,16 @@ +// RUN: %target-typecheck-verify-swift -enable-experimental-concurrency -verify-syntax-tree + +func asyncGlobal1() async { } +func asyncGlobal2() async throws { } + +typealias AsyncFunc1 = () async -> () +typealias AsyncFunc2 = () async throws -> () + +func testTypeExprs() { + let _ = [() async -> ()]() + let _ = [() async throws -> ()]() +} + +func testAwaitOperator() async { + let _ = __await asyncGlobal1() +} diff --git a/test/Parse/strange_interpolation.swift b/test/Parse/strange_interpolation.swift index ef2062ff43bfd..023ed7f4f0e32 100644 --- a/test/Parse/strange_interpolation.swift +++ b/test/Parse/strange_interpolation.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -swift-version 4.2 %s -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main | %FileCheck %s // REQUIRES: executable_test diff --git a/test/Profiler/coverage_smoke.swift b/test/Profiler/coverage_smoke.swift index 9c60045ceaa97..b059962a17e8a 100644 --- a/test/Profiler/coverage_smoke.swift +++ b/test/Profiler/coverage_smoke.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_checked_cast.swift b/test/Profiler/pgo_checked_cast.swift index 0ad48c1d33310..f62ac58a42cdf 100644 --- a/test/Profiler/pgo_checked_cast.swift +++ b/test/Profiler/pgo_checked_cast.swift @@ -4,6 +4,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_foreach.swift b/test/Profiler/pgo_foreach.swift index 9f046099d3ae3..81ceb69222f2d 100644 --- a/test/Profiler/pgo_foreach.swift +++ b/test/Profiler/pgo_foreach.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_guard.swift b/test/Profiler/pgo_guard.swift index 5b77cc98daead..2a336ed1be702 100644 --- a/test/Profiler/pgo_guard.swift +++ b/test/Profiler/pgo_guard.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_if.swift b/test/Profiler/pgo_if.swift index 02a76dd65a9ca..c8a514210220f 100644 --- a/test/Profiler/pgo_if.swift +++ b/test/Profiler/pgo_if.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_repeatwhile.swift b/test/Profiler/pgo_repeatwhile.swift index 7671287a0a582..abf3053070884 100644 --- a/test/Profiler/pgo_repeatwhile.swift +++ b/test/Profiler/pgo_repeatwhile.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_switchenum.swift b/test/Profiler/pgo_switchenum.swift index 4357e84de3a6a..5f4aad55d01ac 100644 --- a/test/Profiler/pgo_switchenum.swift +++ b/test/Profiler/pgo_switchenum.swift @@ -4,6 +4,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Profiler/pgo_while.swift b/test/Profiler/pgo_while.swift index 9ce8c0a6cec31..3e73af5c66023 100644 --- a/test/Profiler/pgo_while.swift +++ b/test/Profiler/pgo_while.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/Runtime/stable-bit-backward-deployment.swift b/test/Runtime/stable-bit-backward-deployment.swift index 09e18a7432c15..f478976dcee50 100644 --- a/test/Runtime/stable-bit-backward-deployment.swift +++ b/test/Runtime/stable-bit-backward-deployment.swift @@ -2,6 +2,7 @@ // -- Deployment target is set to pre-10.14.4 so that we use the "old" // Swift runtime bit in compiler-emitted classes // RUN: %target-build-swift -target %target-cpu-apple-macosx10.9 %s -module-name main -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SIL/Parser/async.sil b/test/SIL/Parser/async.sil new file mode 100644 index 0000000000000..694f66de78175 --- /dev/null +++ b/test/SIL/Parser/async.sil @@ -0,0 +1,8 @@ +// RUN: %target-sil-opt -enable-sil-verify-all=true %s | %target-sil-opt -enable-sil-verify-all=true | %FileCheck %s + +// CHECK: sil [async] @async_test +sil [async] @async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} diff --git a/test/SIL/Serialization/basic.sil b/test/SIL/Serialization/basic.sil index e2fff2ea050db..dd7f9ba3a54d4 100644 --- a/test/SIL/Serialization/basic.sil +++ b/test/SIL/Serialization/basic.sil @@ -15,6 +15,13 @@ bb0(%0 : @guaranteed $Builtin.NativeObject): return undef : $() } +// CHECK-LABEL: sil [async] @async_test +sil [async] @async_test : $() -> () { +bb0: + %0 = tuple () + return %0 : $() +} + // CHECK-LABEL: sil [serialized] [ossa] @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { // CHECK: end_lifetime {{%.*}} : $Builtin.NativeObject sil [serialized] [ossa] @test_end_lifetime : $@convention(thin) (@owned Builtin.NativeObject) -> () { diff --git a/test/SILGen/async.swift b/test/SILGen/async.swift new file mode 100644 index 0000000000000..901978a7ac493 --- /dev/null +++ b/test/SILGen/async.swift @@ -0,0 +1,20 @@ +// RUN: %target-swift-frontend -emit-silgen -enable-experimental-concurrency -module-name Async -Xllvm -sil-full-demangle -parse-as-library %s | %FileCheck %s + +import Swift + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async04testA0yyYF : $@convention(thin) () -> () { +func testAsync() async {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async11testAsyncp1SiyYF : $@convention(thin) () -> Int { +func testAsyncp1() async -> Int { return 0 } + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test2yyYKF : $@convention(thin) () -> @error Error { +func test2() async throws {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test2p1SiyYKF : $@convention(thin) () -> (Int, @error Error) { +func test2p1() async throws -> Int { return 0 } + +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async5test3yyyyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> @error Error) -> @error Error { +func test3(_ cl: () throws -> ()) async rethrows {} +// CHECK-LABEL: sil hidden [async] [ossa] @$s5Async7test3p1yS2iyKXEYKF : $@convention(thin) (@noescape @callee_guaranteed () -> (Int, @error Error)) -> (Int, @error Error) { +func test3p1(_ cl: () throws -> Int) async rethrows -> Int { return try cl() } + + diff --git a/test/SILGen/property_wrapper_autoclosure.swift b/test/SILGen/property_wrapper_autoclosure.swift index b86098a692fcf..585cb5725ce6c 100644 --- a/test/SILGen/property_wrapper_autoclosure.swift +++ b/test/SILGen/property_wrapper_autoclosure.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/allocboxtostack_localapply.swift b/test/SILOptimizer/allocboxtostack_localapply.swift index c9c73539ae6b4..5f3522aa07715 100644 --- a/test/SILOptimizer/allocboxtostack_localapply.swift +++ b/test/SILOptimizer/allocboxtostack_localapply.swift @@ -118,3 +118,67 @@ public func testrecur() -> Int { } return bas() + bar() } + +// Test to make sure AppliesToSpecialize in AllocBoxToStack is populated correctly when there are common function calls for mutiple allox_boxes. +// Order of function calls constructed in PromotedOperands: bar common bas common. +// AppliesToSpecialize should have the order: bar bas common. +// Only then, the functions get specialized correctly, and we won't see an assert in checkNoPromotedBoxInApply. +// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs1SiyF : +// CHECK-NOT : alloc_box ${ var Int }, var, name "x" +// CHECK-NOT : alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs1SiyF' +@inline(never) +public func testdfs1() -> Int { + var x = 0 + var y = 0 + @inline(never) + func bar() -> Int { + return x + } + @inline(never) + func bas() -> Int { + return y + } + @inline(never) + func common() -> Int { + return bar() + bas() + } + return common() +} + +// Test to make sure we don't optimize the case when we have an inner common function call for multiple boxes. +// We don't optimize this case now, because we don't have additional logic to correctly construct AppliesToSpecialize +// Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2 +// AppliesToSpecialize should have the order: bar bas innercommon local1 local2 +// Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to contruct today +// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs2SiyF : +// CHECK: alloc_box ${ var Int }, var, name "x" +// CHECK: alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs2SiyF' +@inline(never) +public func testdfs2() -> Int { + var x = 0 + var y = 0 + @inline(never) + func bar() -> Int { + return x + } + @inline(never) + func bas() -> Int { + return y + } + @inline(never) + func innercommon() -> Int { + return bar() + bas() + } + @inline(never) + func local1() -> Int { + return innercommon() + } + @inline(never) + func local2() -> Int { + return innercommon() + } + return local1() + local2() +} + diff --git a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil index 6807349240adc..48b12ef9efd5e 100644 --- a/test/SILOptimizer/allocboxtostack_localapply_ossa.sil +++ b/test/SILOptimizer/allocboxtostack_localapply_ossa.sil @@ -349,3 +349,142 @@ bb2: unwind } +struct Int { + var _value: Builtin.Int64 +} + +// Test to make sure AppliesToSpecialize in AllocBoxToStack is populated correctly when there are common function calls for mutiple allox_boxes. +// Order of function calls constructed in PromotedOperands: bar common bas common. +// AppliesToSpecialize should have the order: bar bas common. +// Only then, the functions get specialized correctly, and we won't see an assert in checkNoPromotedBoxInApply. +// CHECK-LABEL: sil [noinline] [ossa] @$testdfs1 : +// CHECK-NOT : alloc_box ${ var Int64 }, var, name "x" +// CHECK-NOT : alloc_box ${ var Int64 }, var, name "y" +// CHECK-LABEL:} // end sil function '$testdfs1' +sil [noinline] [ossa] @$testdfs1 : $@convention(thin) () -> Int64 { +bb0: + %0 = alloc_box ${ var Int64 }, var, name "x" + %1 = project_box %0 : ${ var Int64 }, 0 + %2 = integer_literal $Builtin.Int64, 0 + %3 = struct $Int64 (%2 : $Builtin.Int64) + store %3 to [trivial] %1 : $*Int64 + %5 = alloc_box ${ var Int64 }, var, name "y" + %6 = project_box %5 : ${ var Int64 }, 0 + %7 = integer_literal $Builtin.Int64, 0 + %8 = struct $Int64 (%7 : $Builtin.Int64) + store %8 to [trivial] %6 : $*Int64 + %10 = function_ref @$testdfs1common : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 + %11 = apply %10(%0, %5) : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 + destroy_value %5 : ${ var Int64 } + destroy_value %0 : ${ var Int64 } + return %11 : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1common : $@convention(thin) (@guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }, %1 : @guaranteed ${ var Int64 }): + %proj1 = project_box %0 : ${ var Int64 }, 0 + %proj2 = project_box %1 : ${ var Int64 }, 0 + %barfunc = function_ref @$testdfs1bar : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %res1 = apply %barfunc(%0) : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %basfunc = function_ref @$testdfs1bas : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %res2 = apply %basfunc(%1) : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 + %func = function_ref @$blackhole : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + %tmp1 = apply %func(%proj1) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + %tmp2 = apply %func(%proj2) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () + %res = load [trivial] %proj1 : $*Int64 + return %res : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1bar : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }): + %1 = project_box %0 : ${ var Int64 }, 0 + %4 = load [trivial] %1 : $*Int64 + return %4 : $Int64 +} + +sil private [noinline] [ossa] @$testdfs1bas : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 { +bb0(%0 : @guaranteed ${ var Int64 }): + %1 = project_box %0 : ${ var Int64 }, 0 + %4 = load [trivial] %1 : $*Int64 + return %4 : $Int64 +} + +// Test to make sure we don't optimize the case when we have an inner common function call for multiple boxes. +// We don't optimize this case now, because we don't have additional logic to correctly construct AppliesToSpecialize +// Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2 +// AppliesToSpecialize should have the order: bar bas innercommon local1 local2 +// Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to contruct today +// CHECK-LABEL: sil [noinline] [ossa] @$testdfs2 : +// CHECK: alloc_box ${ var Int }, var, name "x" +// CHECK: alloc_box ${ var Int }, var, name "y" +// CHECK-LABEL:} // end sil function '$testdfs2' +sil [noinline] [ossa] @$testdfs2 : $@convention(thin) () -> Int { +bb0: + %0 = alloc_box ${ var Int }, var, name "x" + %1 = project_box %0 : ${ var Int }, 0 + %2 = integer_literal $Builtin.Int64, 0 + %3 = struct $Int (%2 : $Builtin.Int64) + store %3 to [trivial] %1 : $*Int + %5 = alloc_box ${ var Int }, var, name "y" + %6 = project_box %5 : ${ var Int }, 0 + %7 = integer_literal $Builtin.Int64, 0 + %8 = struct $Int (%7 : $Builtin.Int64) + store %8 to [trivial] %6 : $*Int + %10 = function_ref @$testdfs2local1 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %11 = apply %10(%0, %5) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %12 = function_ref @$testdfs2local2 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %13 = apply %12(%0, %5) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %14 = struct_extract %11 : $Int, #Int._value + %15 = struct_extract %13 : $Int, #Int._value + %16 = integer_literal $Builtin.Int1, -1 + %17 = builtin "sadd_with_overflow_Int64"(%14 : $Builtin.Int64, %15 : $Builtin.Int64, %16 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + (%18, %19) = destructure_tuple %17 : $(Builtin.Int64, Builtin.Int1) + cond_fail %19 : $Builtin.Int1, "arithmetic overflow" + %21 = struct $Int (%18 : $Builtin.Int64) + destroy_value %5 : ${ var Int } + destroy_value %0 : ${ var Int } + return %21 : $Int +} + +sil private [noinline] [ossa] @$testdfs2bar : $@convention(thin) (@guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }): + %1 = project_box %0 : ${ var Int }, 0 + %4 = load [trivial] %1 : $*Int + return %4 : $Int +} + +sil private [noinline] [ossa] @$testdfs2bas : $@convention(thin) (@guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }): + %1 = project_box %0 : ${ var Int }, 0 + %4 = load [trivial] %1 : $*Int + return %4 : $Int +} + +sil private [noinline] [ossa] @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %8 = function_ref @$testdfs2bar : $@convention(thin) (@guaranteed { var Int }) -> Int + %9 = apply %8(%0) : $@convention(thin) (@guaranteed { var Int }) -> Int + %11 = function_ref @$testdfs2bas : $@convention(thin) (@guaranteed { var Int }) -> Int + %12 = apply %11(%1) : $@convention(thin) (@guaranteed { var Int }) -> Int + return %12 : $Int +} + +sil private [noinline] [ossa] @$testdfs2local1 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %7 = function_ref @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %8 = apply %7(%0, %1) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + return %8 : $Int +} + +sil private [noinline] [ossa] @$testdfs2local2 : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int { +bb0(%0 : @guaranteed ${ var Int }, %1 : @guaranteed ${ var Int }): + %2 = project_box %0 : ${ var Int }, 0 + %4 = project_box %1 : ${ var Int }, 0 + %7 = function_ref @$testdfs2innercommon : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + %8 = apply %7(%0, %1) : $@convention(thin) (@guaranteed { var Int }, @guaranteed { var Int }) -> Int + return %8 : $Int +} diff --git a/test/SILOptimizer/arcsequenceopts.sil b/test/SILOptimizer/arcsequenceopts.sil index ea05c13ea896e..8825d9cbae7f0 100644 --- a/test/SILOptimizer/arcsequenceopts.sil +++ b/test/SILOptimizer/arcsequenceopts.sil @@ -395,6 +395,53 @@ bb0(%0 : $*Builtin.Int32): return %4: $() } +struct Int { + var value : Builtin.Int64 +} + +sil @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { +bb0(%0 : $<τ_0_0> { var τ_0_0 } ): + %1 = tuple () + return %1 : $() +} + +// CHECK_LABEL: sil hidden [noinline] @$test_guaranteed_call : +// CHECK: bb1{{.*}}: +// CHECK-NOT: strong_retain +// CHECK: apply +// CHECK-NOT: strong_release +// CHECK: bb2: +// CHECK_LABEL: } // end sil function '$test_guaranteed_call' +sil hidden [noinline] @$test_guaranteed_call : $@convention(thin) () -> () { +bb0: + %box = alloc_box $<τ_0_0> { var τ_0_0 } + %proj = project_box %box : $<τ_0_0> { var τ_0_0 } , 0 + %0 = integer_literal $Builtin.Int64, 1 + %1 = integer_literal $Builtin.Int64, 100 + %funcref = function_ref @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () + %3 = struct $Int (%0 : $Builtin.Int64) + %6 = integer_literal $Builtin.Int1, -1 + br bb1(%0 : $Builtin.Int64) + +bb1(%8 : $Builtin.Int64): + %9 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %0 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) + %10 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 0 + %11 = struct $Int (%10 : $Builtin.Int64) + %12 = builtin "cmp_eq_Int64"(%10 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 + strong_retain %box : $<τ_0_0> { var τ_0_0 } + apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () + strong_release %box : $<τ_0_0> { var τ_0_0 } + cond_br %12, bb3, bb2 + +bb2: + br bb1(%10 : $Builtin.Int64) + +bb3: + strong_release %box : $<τ_0_0> { var τ_0_0 } + %17 = tuple () + return %17 : $() +} + // CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () // CHECK: bb0 // CHECK-NEXT: function_ref user diff --git a/test/SILOptimizer/array_element_propagation_crash.swift b/test/SILOptimizer/array_element_propagation_crash.swift index 4eb809835790c..77dd187803f4a 100644 --- a/test/SILOptimizer/array_element_propagation_crash.swift +++ b/test/SILOptimizer/array_element_propagation_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/cowarray_opt_crash.swift b/test/SILOptimizer/cowarray_opt_crash.swift index e9d2f860a7408..d047fb881d5e6 100644 --- a/test/SILOptimizer/cowarray_opt_crash.swift +++ b/test/SILOptimizer/cowarray_opt_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/cross-module-optimization-objc.swift b/test/SILOptimizer/cross-module-optimization-objc.swift index 76465746f2f14..8d3129a3c1735 100644 --- a/test/SILOptimizer/cross-module-optimization-objc.swift +++ b/test/SILOptimizer/cross-module-optimization-objc.swift @@ -4,12 +4,14 @@ // RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module-objc.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o // RUN: %target-swiftc_driver %t/main.o %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // Check if it also works if the main module is compiled with -Onone: // RUN: %target-build-swift -Onone -wmo -module-name=Main -I%t %s -c -o %t/main-onone.o // RUN: %target-swiftc_driver %t/main-onone.o %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/cross-module-optimization.swift b/test/SILOptimizer/cross-module-optimization.swift index df1689c391719..31a298de82ae5 100644 --- a/test/SILOptimizer/cross-module-optimization.swift +++ b/test/SILOptimizer/cross-module-optimization.swift @@ -5,12 +5,14 @@ // RUN: %target-build-swift -O -wmo -parse-as-library -cross-module-optimization -emit-module -emit-module-path=%t/Test.swiftmodule -module-name=Test -I%t %S/Inputs/cross-module.swift -c -o %t/test.o // RUN: %target-build-swift -O -wmo -module-name=Main -I%t %s -c -o %t/main.o // RUN: %target-swiftc_driver %t/main.o %t/test.o %t/submodule.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // Check if it also works if the main module is compiled with -Onone: // RUN: %target-build-swift -Onone -wmo -module-name=Main -I%t %s -c -o %t/main-onone.o // RUN: %target-swiftc_driver %t/main-onone.o %t/test.o %t/submodule.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/cse.sil b/test/SILOptimizer/cse.sil index 52f65b49001b3..60df4ccb7d4a6 100644 --- a/test/SILOptimizer/cse.sil +++ b/test/SILOptimizer/cse.sil @@ -523,7 +523,7 @@ sil @helper2 : $@convention(thin) (UInt8, UInt8) -> Builtin.Word // CHECK-LABEL: sil @sil_string_different_encodings sil @sil_string_different_encodings : $@convention(thin) () -> Builtin.Word { %0 = string_literal utf8 "help" - %1 = string_literal utf16 "help" + %1 = string_literal objc_selector "help" %2 = function_ref @helper : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer) -> Builtin.Word %3 = apply %2(%0, %1) : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer) -> Builtin.Word return %3 : $Builtin.Word diff --git a/test/SILOptimizer/devirtualize_class_method.swift b/test/SILOptimizer/devirtualize_class_method.swift index 97a819da0bc66..095734354c072 100644 --- a/test/SILOptimizer/devirtualize_class_method.swift +++ b/test/SILOptimizer/devirtualize_class_method.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/di_property_wrappers.swift b/test/SILOptimizer/di_property_wrappers.swift index 39b23d2b37c3c..c4db338ab2975 100644 --- a/test/SILOptimizer/di_property_wrappers.swift +++ b/test/SILOptimizer/di_property_wrappers.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/dse_with_union.swift b/test/SILOptimizer/dse_with_union.swift index 2d90d1937028d..9e36836ddfb8e 100644 --- a/test/SILOptimizer/dse_with_union.swift +++ b/test/SILOptimizer/dse_with_union.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -import-objc-header %S/Inputs/dse_with_union.h -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/existential_box_elimination.swift b/test/SILOptimizer/existential_box_elimination.swift index c2f838f3d5d25..4ddc7a6659d98 100644 --- a/test/SILOptimizer/existential_box_elimination.swift +++ b/test/SILOptimizer/existential_box_elimination.swift @@ -2,6 +2,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -wmo -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out // REQUIRES: executable_test diff --git a/test/SILOptimizer/global_hoisting_crash.swift b/test/SILOptimizer/global_hoisting_crash.swift index b640f656e9bbb..44a49926773de 100644 --- a/test/SILOptimizer/global_hoisting_crash.swift +++ b/test/SILOptimizer/global_hoisting_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/lazy_property_getters.swift b/test/SILOptimizer/lazy_property_getters.swift index f2282c9f1bcfc..e3e8b9d1eb7b1 100644 --- a/test/SILOptimizer/lazy_property_getters.swift +++ b/test/SILOptimizer/lazy_property_getters.swift @@ -3,6 +3,7 @@ // Also do an end-to-end test to check if the generated code is correct. // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -Xllvm -module-name=test %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT // REQUIRES: executable_test diff --git a/test/SILOptimizer/licm_and_global_addr.swift b/test/SILOptimizer/licm_and_global_addr.swift index d3b8fd73594ae..af332272c2f50 100644 --- a/test/SILOptimizer/licm_and_global_addr.swift +++ b/test/SILOptimizer/licm_and_global_addr.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %S/Inputs/licm_and_global_addr/test.swift -parse-as-library -wmo -enable-library-evolution -module-name=Test -emit-module -emit-module-path=%t/Test.swiftmodule -c -o %t/test.o // RUN: %target-build-swift -O %S/Inputs/licm_and_global_addr/main.swift %s -I%t %t/test.o -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/pgo_si_inlinelarge.swift b/test/SILOptimizer/pgo_si_inlinelarge.swift index 2947658b746a5..b90fcd0fb4864 100644 --- a/test/SILOptimizer/pgo_si_inlinelarge.swift +++ b/test/SILOptimizer/pgo_si_inlinelarge.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/SILOptimizer/pgo_si_reduce.swift b/test/SILOptimizer/pgo_si_reduce.swift index 3f5059b5a8e30..6e4e14b31ece6 100644 --- a/test/SILOptimizer/pgo_si_reduce.swift +++ b/test/SILOptimizer/pgo_si_reduce.swift @@ -3,6 +3,7 @@ // This unusual use of 'sh' allows the path of the profraw file to be // substituted by %target-run. +// RUN: %target-codesign %t/main // RUN: %target-run sh -c 'env LLVM_PROFILE_FILE=$1 $2' -- %t/default.profraw %t/main // RUN: %llvm-profdata merge %t/default.profraw -o %t/default.profdata diff --git a/test/SILOptimizer/property_wrappers_and_tuples.swift b/test/SILOptimizer/property_wrappers_and_tuples.swift index b45118f495257..783a36473384d 100644 --- a/test/SILOptimizer/property_wrappers_and_tuples.swift +++ b/test/SILOptimizer/property_wrappers_and_tuples.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -module-name=a -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/sil_combine.sil b/test/SILOptimizer/sil_combine.sil index 81b635f2b21e4..145399c069f35 100644 --- a/test/SILOptimizer/sil_combine.sil +++ b/test/SILOptimizer/sil_combine.sil @@ -1850,7 +1850,7 @@ bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.RawPointer): //CHECK: return sil @remove_pointer_compare_to_zero : $@convention(thin) (Int) -> () { bb0(%0 : $Int): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer %6 = builtin "cmp_eq_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1 @@ -1865,7 +1865,7 @@ bb0(%0 : $Int): //CHECK: unreachable sil @remove_pointer_compare_to_zero_NE : $@convention(thin) (Int) -> () { bb0(%0 : $Int): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer %6 = builtin "cmp_ne_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1 @@ -1881,7 +1881,7 @@ bb0(%0 : $Int): //CHECK: return sil @remove_pointer_compare_to_zero_arith : $@convention(thin) (Builtin.Word) -> () { bb0(%0 : $Builtin.Word): - %1 = string_literal utf16 "ss" + %1 = string_literal utf8 "ss" %2 = integer_literal $Builtin.Word, 0 %3 = integer_literal $Builtin.Word, 4 %4 = integer_literal $Builtin.Int1, -1 diff --git a/test/SILOptimizer/sil_combine_alloc_stack.swift b/test/SILOptimizer/sil_combine_alloc_stack.swift index 5a18f65738dbf..7da9e6302d651 100644 --- a/test/SILOptimizer/sil_combine_alloc_stack.swift +++ b/test/SILOptimizer/sil_combine_alloc_stack.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/silcombine_aebox_miscompile.swift b/test/SILOptimizer/silcombine_aebox_miscompile.swift index 587611be2e4b9..f392235ed8938 100644 --- a/test/SILOptimizer/silcombine_aebox_miscompile.swift +++ b/test/SILOptimizer/silcombine_aebox_miscompile.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O -module-name=a %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/silcombine_runtime_crash.swift b/test/SILOptimizer/silcombine_runtime_crash.swift index 63f298709e0d3..88b2a022a206a 100644 --- a/test/SILOptimizer/silcombine_runtime_crash.swift +++ b/test/SILOptimizer/silcombine_runtime_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/SILOptimizer/stack_promotion_crash.swift b/test/SILOptimizer/stack_promotion_crash.swift index c08d7a29810bc..86f1de0b0d137 100644 --- a/test/SILOptimizer/stack_promotion_crash.swift +++ b/test/SILOptimizer/stack_promotion_crash.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -O %s -o %t/a.out +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s // REQUIRES: executable_test diff --git a/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface new file mode 100644 index 0000000000000..fc36a2faed446 --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleOne.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleOne +import Swift +import CycleTwo + diff --git a/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface new file mode 100644 index 0000000000000..0ecabbea84dfb --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleThree.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleThree +import Swift +import CycleOne + diff --git a/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface b/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface new file mode 100644 index 0000000000000..9e97dd3b2244e --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/CycleTwo.swiftinterface @@ -0,0 +1,4 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name CycleTwo +import Swift +import CycleThree diff --git a/test/ScanDependencies/diagnose_dependency_cycle.swift b/test/ScanDependencies/diagnose_dependency_cycle.swift new file mode 100644 index 0000000000000..1157d364a7954 --- /dev/null +++ b/test/ScanDependencies/diagnose_dependency_cycle.swift @@ -0,0 +1,10 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/clang-module-cache + +// RUN: not %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -disable-implicit-swift-modules -Xcc -Xclang -Xcc -fno-implicit-modules &> %t/out.txt + +// RUN: %FileCheck %s < %t/out.txt + +// CHECK: dependency scanner detected dependency cycle: 'CycleOne.swiftmodule -> CycleTwo.swiftmodule -> CycleThree.swiftmodule -> CycleOne.swiftmodule' + +import CycleOne diff --git a/test/Sema/diag_type_conversion.swift b/test/Sema/diag_type_conversion.swift index 2f32d5886d863..ac7d0fdc02c99 100644 --- a/test/Sema/diag_type_conversion.swift +++ b/test/Sema/diag_type_conversion.swift @@ -72,3 +72,16 @@ _ = p =*= &o func rdar25963182(_ bytes: [UInt8] = nil) {} // expected-error@-1 {{nil default argument value cannot be converted to type}} + +// SR-13262 +struct SR13262_S {} + +func SR13262(_ x: Int) {} +func SR13262_Int(_ x: Int) -> Int { 0 } +func SR13262_SF(_ x: Int) -> SR13262_S { SR13262_S() } + +func testSR13262(_ arr: [Int]) { + for x in arr where SR13262(x) {} // expected-error {{cannot convert value of type '()' to expected condition type 'Bool'}} + for x in arr where SR13262_Int(x) {} // expected-error {{type 'Int' cannot be used as a boolean; test for '!= 0' instead}} {{22-22=(}} {{36-36= != 0)}} + for x in arr where SR13262_SF(x) {} // expected-error {{cannot convert value of type 'SR13262_S' to expected condition type 'Bool'}} +} diff --git a/test/Serialization/Inputs/def_async.swift b/test/Serialization/Inputs/def_async.swift new file mode 100644 index 0000000000000..e74faed0ab5b7 --- /dev/null +++ b/test/Serialization/Inputs/def_async.swift @@ -0,0 +1 @@ +public func doSomethingBig() async -> Int { return 0 } diff --git a/test/Serialization/async.swift b/test/Serialization/async.swift new file mode 100644 index 0000000000000..cbf1019a3cdc8 --- /dev/null +++ b/test/Serialization/async.swift @@ -0,0 +1,11 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t-scratch) +// RUN: %target-swift-frontend -emit-module -o %t-scratch/def_async~partial.swiftmodule -primary-file %S/Inputs/def_async.swift -module-name def_async -enable-experimental-concurrency +// RUN: %target-swift-frontend -merge-modules -emit-module -parse-as-library -enable-testing %t-scratch/def_async~partial.swiftmodule -module-name def_async -o %t/def_async.swiftmodule -enable-experimental-concurrency +// RUN: %target-swift-frontend -typecheck -I%t -verify %s -verify-ignore-unknown -enable-experimental-concurrency + +import def_async + +func testDoSomethingBig() { + let _: () -> Int = doSomethingBig // expected-error{{cannot convert value of type '() async -> Int' to specified type '() -> Int'}} +} diff --git a/test/Serialization/autolinking.swift b/test/Serialization/autolinking.swift index 864bd8db62caf..d30ae2e28826b 100644 --- a/test/Serialization/autolinking.swift +++ b/test/Serialization/autolinking.swift @@ -40,10 +40,10 @@ import someModule // NO-FORCE-LOAD-NOT: FORCE_LOAD // NO-FORCE-LOAD-NOT -lmodule // NO-FORCE-LOAD-NOT -lmagic -// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(comdat )?}}{ +// FORCE-LOAD: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$_module"() {{(#[0-9]+)?( comdat)?}} { // FORCE-LOAD: ret void // FORCE-LOAD: } -// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(comdat )?}}{ +// FORCE-LOAD-HEX: define{{( dllexport)?}} void @"_swift_FORCE_LOAD_$306d6f64756c65"() {{(#[0-9]+)?( comdat)?}} { // FORCE-LOAD-HEX: ret void // FORCE-LOAD-HEX: } diff --git a/test/SymbolGraph/Something/Inputs/SomeProtocol.swift b/test/SymbolGraph/Something/Inputs/SomeProtocol.swift new file mode 100644 index 0000000000000..e3a42fe70da44 --- /dev/null +++ b/test/SymbolGraph/Something/Inputs/SomeProtocol.swift @@ -0,0 +1,3 @@ +public protocol P { + func foo() +} diff --git a/test/SymbolGraph/Something/Something.swift b/test/SymbolGraph/Something/Something.swift new file mode 100644 index 0000000000000..a56bb3b2d5bce --- /dev/null +++ b/test/SymbolGraph/Something/Something.swift @@ -0,0 +1,15 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift %S/Inputs/SomeProtocol.swift -module-name SomeProtocol -emit-module -emit-module-path %t/ +// RUN: %target-build-swift %s -module-name Something -emit-module -emit-module-path %t/ -I %t +// RUN: %target-swift-symbolgraph-extract -module-name Something -I %t -pretty-print -output-dir %t +// RUN: %FileCheck %s --input-file %t/Something.symbols.json + +import protocol SomeProtocol.P + +public struct MyStruct: P { + public func foo() {} +} + +// CHECK: "kind": "conformsTo", +// CHECK-NEXT: "source": "s:9Something8MyStructV", +// CHECK-NEXT: "target": "s:12SomeProtocol1PP", diff --git a/test/api-digester/stability-stdlib-abi-with-asserts.test b/test/api-digester/stability-stdlib-abi-with-asserts.test index f4fc7919faf65..2c46c990d56a0 100644 --- a/test/api-digester/stability-stdlib-abi-with-asserts.test +++ b/test/api-digester/stability-stdlib-abi-with-asserts.test @@ -25,6 +25,13 @@ // REQUIRES: OS=macosx // REQUIRES: swift_stdlib_asserts + +// SR-13362 +// This currently fails on non-Intel architectures due to no baseline being +// available and it is not possible to filter across architectures in the +// output. +// XFAIL: CPU=arm64 || CPU=arm64e + // RUN: %empty-directory(%t.tmp) // mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk // RUN: %api-digester -diagnose-sdk -module Swift -o %t.tmp/changes.txt -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -abi -avoid-location diff --git a/test/api-digester/stability-stdlib-source.swift b/test/api-digester/stability-stdlib-source.swift index f0e383a5cc2c2..6d5f0120c4457 100644 --- a/test/api-digester/stability-stdlib-source.swift +++ b/test/api-digester/stability-stdlib-source.swift @@ -1,4 +1,11 @@ // REQUIRES: OS=macosx + +// SR-13362 +// This currently fails on non-Intel architectures due to no baseline being +// available and it is not possible to filter across architectures in the +// output. +// XFAIL: CPU=arm64 || CPU=arm64e + // RUN: %empty-directory(%t.tmp) // mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk // RUN: %api-digester -diagnose-sdk -module Swift -o %t.tmp/changes.txt -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -avoid-location diff --git a/test/attr/attr_originally_definedin_backward_compatibility.swift b/test/attr/attr_originally_definedin_backward_compatibility.swift index a7abe24616ce6..07dea103cd0b3 100644 --- a/test/attr/attr_originally_definedin_backward_compatibility.swift +++ b/test/attr/attr_originally_definedin_backward_compatibility.swift @@ -24,6 +24,7 @@ // RUN: %target-rpath(@executable_path/SDK/Frameworks) // --- Run the executable +// RUN: %target-codesign %t/HighlevelRunner // RUN: %target-run %t/HighlevelRunner %t/SDK/Frameworks/HighLevel.framework/HighLevel | %FileCheck %s -check-prefix=BEFORE_MOVE // --- Build low level framework. @@ -39,6 +40,7 @@ // RUN: %S/Inputs/SymbolMove/HighLevel.swift -F %t/SDK/Frameworks -Xlinker -reexport_framework -Xlinker LowLevel -enable-library-evolution // --- Run the executable +// RUN: %target-codesign %t/HighlevelRunner // RUN: %target-run %t/HighlevelRunner %t/SDK/Frameworks/HighLevel.framework/HighLevel %t/SDK/Frameworks/LowLevel.framework/LowLevel | %FileCheck %s -check-prefix=AFTER_MOVE import HighLevel diff --git a/test/decl/protocol/conforms/nscoding.swift b/test/decl/protocol/conforms/nscoding.swift index 69f839bc0721c..b6a846921caee 100644 --- a/test/decl/protocol/conforms/nscoding.swift +++ b/test/decl/protocol/conforms/nscoding.swift @@ -8,7 +8,7 @@ // RUN: %FileCheck --check-prefix=NEGATIVE %s < %t/old.ast // REQUIRES: objc_interop -// UNSUPPORTED: CPU=arm64e +// UNSUPPORTED: swift_only_stable_abi // See also nscoding_stable_abi.swift, for the stable ABI deployment // target test. diff --git a/test/decl/protocol/req/associated_type_inference.swift b/test/decl/protocol/req/associated_type_inference.swift index 0de5e8ec1b6bc..817f08de5e85d 100644 --- a/test/decl/protocol/req/associated_type_inference.swift +++ b/test/decl/protocol/req/associated_type_inference.swift @@ -676,21 +676,12 @@ struct S40: P40c { typealias B = Self } -// Self is not treated as a fixed type witness. +// Fails to find the fixed type witness B == FIXME_S1. protocol FIXME_P1a { - associatedtype A // expected-note {{protocol requires nested type 'A'}} -} -protocol FIXME_P1b: FIXME_P1a where A == Self {} -// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} -// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} -struct FIXME_S1: FIXME_P1b {} - -// Fails to find the fixed type witness B == FIXME_S2. -protocol FIXME_P2a { associatedtype A: Equatable = Never // expected-note {{protocol requires nested type 'A'}} - associatedtype B: FIXME_P2a // expected-note {{protocol requires nested type 'B'}} + associatedtype B: FIXME_P1a // expected-note {{protocol requires nested type 'B'}} } -protocol FIXME_P2b: FIXME_P2a where B == FIXME_S2 {} -// expected-error@+2 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2a'}} -// expected-error@+1 {{type 'FIXME_S2' does not conform to protocol 'FIXME_P2b'}} -struct FIXME_S2: FIXME_P2b {} +protocol FIXME_P1b: FIXME_P1a where B == FIXME_S1 {} +// expected-error@+2 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1a'}} +// expected-error@+1 {{type 'FIXME_S1' does not conform to protocol 'FIXME_P1b'}} +struct FIXME_S1: FIXME_P1b {} diff --git a/test/decl/protocol/req/associated_type_inference_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift new file mode 100644 index 0000000000000..67b4de6b4511b --- /dev/null +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -0,0 +1,101 @@ +// RUN: %target-typecheck-verify-swift + +protocol P1 where A == Never { + associatedtype A +} +struct S1: P1 {} // OK, A := Never + +protocol P2a { + associatedtype A +} +protocol P2b: P2a where A == Never {} +protocol P2c: P2b {} +struct S2a: P2b {} // OK, A := Never +struct S2b: P2c {} // OK, A := Never + +// Fixed type witnesses can reference dependent members. +protocol P3a { + associatedtype A + associatedtype B +} +protocol P3b: P3a where A == [B] {} +struct S3: P3b { // OK, A := [Never], B := Never + typealias B = Never +} + +protocol P4 {} +extension P4 { + typealias B = Self +} +struct S4: P4, P3b {} // OK, A := [S4], B := S4 + +// Self is a valid fixed type witness. +protocol P5a { + associatedtype A +} +protocol P5b: P5a where A == Self {} +struct S5: P5b {} // OK, A := S5 + + +protocol P6 where A == Never { // expected-error {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-error@+2 {{same-type constraint type 'Never' does not conform to required protocol 'P6'}} + // expected-note@+1 {{protocol requires nested type 'A}} + associatedtype A: P6 +} +struct S6: P6 {} // expected-error {{type 'S6' does not conform to protocol 'P6'}} + +protocol P7a where A == Never { + associatedtype A +} +// expected-error@+2 {{'Self.A' cannot be equal to both 'Bool' and 'Never'}} +// expected-note@+1 {{same-type constraint 'Self.A' == 'Never' implied here}} +protocol P7b: P7a where A == Bool {} +struct S7: P7b {} + +protocol P8 where A == Bool { + associatedtype A +} +// expected-error@+2 {{'P7a' requires the types 'S8.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S8]}} +struct S8: P8, P7a {} + +protocol P9a where A == Never { + associatedtype A +} +protocol P9b: P9a { + associatedtype A +} +struct S9a: P9b {} // OK, A := Never +// expected-error@+2 {{'P9a' requires the types 'S9b.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S9b]}} +struct S9b: P9b { + typealias A = Bool +} +struct S9c: P9b { // OK, S9c.A does not contradict Self.A == Never. + typealias Sugar = Never + typealias A = Sugar +} + +protocol P10 {} +extension P10 { + typealias A = Bool +} +// FIXME: 'P10 extension.A' should not be considered a viable type witness; +// instead, the compiler should infer A := Never and synthesize S10.A. +// expected-error@+2 {{'P9a' requires the types 'S10.A' (aka 'Bool') and 'Never' be equivalent}} +// expected-note@+1 {{requirement specified as 'Self.A' == 'Never' [with Self = S10]}} +struct S10: P10, P9a {} + +protocol P11a { + associatedtype A +} +protocol P11b: P11a where A == Never {} +protocol Q11 { + associatedtype A // expected-note {{protocol requires nested type 'A'}} +} +// FIXME: Unrelated protocols with a matching associated type should +// also be considered when computing a fixed type witness. +// expected-error@+3 {{type 'S11' does not conform to protocol 'Q11'}} +// expected-error@+2 {{type 'S11' does not conform to protocol 'P11a'}} +// expected-error@+1 {{type 'S11' does not conform to protocol 'P11b'}} +struct S11: Q11, P11b {} diff --git a/test/diagnostics/Localization/Inputs/en.yaml b/test/diagnostics/Localization/Inputs/en.yaml index c14e03e543519..b55d4f55cf88a 100644 --- a/test/diagnostics/Localization/Inputs/en.yaml +++ b/test/diagnostics/Localization/Inputs/en.yaml @@ -17,14 +17,29 @@ # #===----------------------------------------------------------------------===# +- id: "not_available_in_def" + msg: "Shouldn't be produced" + - id: "lex_unterminated_string" msg: "unterminated string literal" - + +- id: "not_available_in_def_2" + msg: "Shouldn't be produced" + - id: "var_init_self_referential" msg: "variable used within its own initial value" - id: "cannot_find_in_scope" msg: "cannot %select{find|find operator}1 %0 in scope" +- id: "not_available_in_def_3" + msg: "Shouldn't be produced" + - id: "warning_invalid_locale_code" msg: "unsupported locale code; supported locale codes are '%0'" + +- id: "not_available_in_def_4" + msg: "Shouldn't be produced" + +- id: "not_available_in_def_5" + msg: "Shouldn't be produced" diff --git a/test/diagnostics/Localization/fr_localization.swift b/test/diagnostics/Localization/fr_localization.swift index 50db4c8e33206..9caf88a529e37 100644 --- a/test/diagnostics/Localization/fr_localization.swift +++ b/test/diagnostics/Localization/fr_localization.swift @@ -1,5 +1,9 @@ -// RUN: %target-typecheck-verify-swift -localization-path %S/Inputs -locale fr +// RUN: %empty-directory(%t) +// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/fr.yaml --output-directory=%t/ +// RUN: swift-serialize-diagnostics --input-file-path=%S/Inputs/en.yaml --output-directory=%t/ 2>&1 | %FileCheck %s +// RUN: %target-typecheck-verify-swift -localization-path %t -locale fr +// CHECK: These diagnostic IDs are no longer availiable: 'not_available_in_def, not_available_in_def_2, not_available_in_def_3, not_available_in_def_4, not_available_in_def_5' _ = "HI! // expected-error@-1{{chaîne non terminée littérale}} var self1 = self1 // expected-error {{variable utilisée dans sa propre valeur initiale}} diff --git a/test/expr/delayed-ident/enum.swift b/test/expr/delayed-ident/enum.swift index 20fa5e6e5431b..cbb3d242f24a1 100644 --- a/test/expr/delayed-ident/enum.swift +++ b/test/expr/delayed-ident/enum.swift @@ -25,3 +25,13 @@ e2a = .Second(5) var e2b: E2 = .Second(5) e2b = .First var e2c: E2 = .First // expected-error{{generic parameter 'T' could not be inferred}} + +// SR-13357 +struct SR13357 {} +extension Optional where Wrapped == SR13357 { + static var sr13357: Self { .none } +} + +func f_sr13357(_: T?) { } + +f_sr13357(.sr13357) diff --git a/test/expr/delayed-ident/static_var.swift b/test/expr/delayed-ident/static_var.swift index f6b28bf5569c5..cfe701754f791 100644 --- a/test/expr/delayed-ident/static_var.swift +++ b/test/expr/delayed-ident/static_var.swift @@ -52,3 +52,17 @@ var _: HasClosure = .factoryOpt(3) // expected-note@-3 {{force-unwrap}} // FIXME: we should accept this var _: HasClosure = .factoryOpt!(4) // expected-error {{cannot infer contextual base in reference to member 'factoryOpt'}} + +infix operator =%: ComparisonPrecedence + +extension Optional { + static func =%(lhs: Self, rhs: Self) -> Bool { return true } +} + +struct ImplicitMembers { + static var optional: ImplicitMembers? = ImplicitMembers() +} + +func implicit(_ i: inout ImplicitMembers) { + if i =% .optional {} +} diff --git a/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift b/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift index 8fb0c6d9a98d8..72e13672ace16 100644 --- a/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift +++ b/test/expr/postfix/call/forward_trailing_closure_ambiguity.swift @@ -92,3 +92,33 @@ func notAmbiguous3( func testNotAmbiguous3() { notAmbiguous3 { $0 } } + +// Ambiguous subscript +struct S { + subscript( // expected-note {{'subscript(a:_:_:)' declared here}} + a a: Int, + fn1: (() -> Void)? = nil, + fn2: (() -> Void)? = nil) -> Bool { + get { return true } + } + + subscript( // expected-note {{'subscript(b:_:fn2:)' declared here}} + b b: Int, + fn1: (() -> Void)? = nil, + fn2 fn2: (() -> Void)? = nil) -> Bool { + get { return true } + } + + static func foo( // expected-note {{'foo(c:fn1:fn2:)' declared here}} + c: Int, + fn1: (() -> Void)? = nil, + fn2: (() -> Void)? = nil) -> S { + return S() + } +} + +func test_ambiguous_subscript_unresolved_member(s: S) { + _ = s[a: 42] {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with '_' to suppress this warning}} {{14-15=, }} {{18-18=]}} + _ = s[b: 42] {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'fn2' to suppress this warning}} {{14-15=, fn2: }} {{18-18=]}} + let _: S = .foo(c: 42) {} // expected-warning {{backward matching of the unlabeled trailing closure is deprecated; label the argument with 'fn2' to suppress this warning}} {{24-25=, fn2: }} {{28-28=)}} +} diff --git a/test/expr/primary/keypath/keypath-objc.swift b/test/expr/primary/keypath/keypath-objc.swift index 8f381e92fe925..94c015ac2d8d3 100644 --- a/test/expr/primary/keypath/keypath-objc.swift +++ b/test/expr/primary/keypath/keypath-objc.swift @@ -57,7 +57,7 @@ func testKeyPath(a: A, b: B) { let _: String = #keyPath(A.propString) // Property of String property (which looks on NSString) - let _: String = #keyPath(A.propString.URLsInText) + let _: String = #keyPath(A.propString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // String property with a suffix let _: String = #keyPath(A.propString).description @@ -72,7 +72,7 @@ func testKeyPath(a: A, b: B) { // Array property (make sure we look at the array element). let _: String = #keyPath(A.propArray) - let _: String = #keyPath(A.propArray.URLsInText) + let _: String = #keyPath(A.propArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // Dictionary property (make sure we look at the value type). let _: String = #keyPath(A.propDict.anyKeyName) @@ -80,20 +80,20 @@ func testKeyPath(a: A, b: B) { // Set property (make sure we look at the set element). let _: String = #keyPath(A.propSet) - let _: String = #keyPath(A.propSet.URLsInText) + let _: String = #keyPath(A.propSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // AnyObject property - let _: String = #keyPath(A.propAnyObject.URLsInText) + let _: String = #keyPath(A.propAnyObject.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} let _: String = #keyPath(A.propAnyObject.propA) let _: String = #keyPath(A.propAnyObject.propB) let _: String = #keyPath(A.propAnyObject.description) // NSString property - let _: String = #keyPath(A.propNSString.URLsInText) + let _: String = #keyPath(A.propNSString.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // NSArray property (AnyObject array element). let _: String = #keyPath(A.propNSArray) - let _: String = #keyPath(A.propNSArray.URLsInText) + let _: String = #keyPath(A.propNSArray.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // NSDictionary property (AnyObject value type). let _: String = #keyPath(A.propNSDict.anyKeyName) @@ -101,7 +101,7 @@ func testKeyPath(a: A, b: B) { // NSSet property (AnyObject set element). let _: String = #keyPath(A.propNSSet) - let _: String = #keyPath(A.propNSSet.URLsInText) + let _: String = #keyPath(A.propNSSet.URLsInText) // expected-warning{{'URLsInText' has been renamed to 'urlsInText'}} // Property with keyword name. let _: String = #keyPath(A.repeat) diff --git a/test/lit.cfg b/test/lit.cfg index 24b10d4a9f04f..b084a5870d2dc 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -386,6 +386,8 @@ lit_config.note("Using code completion cache: " + completion_cache_path) config.substitutions.append( ('%validate-incrparse', '%{python} %utils/incrparse/validate_parse.py --temp-dir %t --swift-syntax-test %swift-syntax-test') ) config.substitutions.append( ('%incr-transfer-tree', '%{python} %utils/incrparse/incr_transfer_tree.py --temp-dir %t --swift-syntax-test %swift-syntax-test') ) +config.substitutions.append( ('%llvm_obj_root', config.llvm_obj_root) ) +config.substitutions.append( ('%llvm_src_root', config.llvm_src_root) ) config.substitutions.append( ('%swift_obj_root', config.swift_obj_root) ) config.substitutions.append( ('%swift_src_root', config.swift_src_root) ) config.substitutions.append( ('%{python}', pipes.quote(sys.executable)) ) @@ -457,6 +459,7 @@ config.substitutions.append( ('%clang-include-dir', config.clang_include_dir) ) config.substitutions.append(('%build-clang-importer-objc-overlays', '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module && ' '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreGraphics.swift && ' + '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreFoundation.swift && ' '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift')) # FIXME: BEGIN -enable-source-import hackaround @@ -699,10 +702,10 @@ config.substitutions.append(('%target-cpu', run_cpu)) target_os_abi = run_os target_os_is_maccatalyst = "FALSE" target_mandates_stable_abi = "FALSE" -if (run_cpu == 'arm64e'): +if run_cpu in ('arm64e',): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') -if (run_os == 'maccatalyst'): +if run_os in ('maccatalyst',): # For purposes of ABI, treat maccatalyst as macosx since the maccatalyst ABI # must match the macosx ABI. target_os_abi = 'macosx' @@ -712,7 +715,12 @@ if (run_os == 'maccatalyst'): if run_os in ('macosx',) and run_cpu in ('arm64',): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') -if (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows-cygnus', 'windows-gnu', 'windows-msvc', 'linux-android', 'linux-androideabi']): +if run_os in ( + 'linux-android', 'linux-androideabi', # Android + 'freebsd', 'openbsd', # BSD + 'linux-gnu', 'linux-gnueabihf', # Linux + 'windows-cygnus', 'windows-gnu', 'windows-msvc', # Windows + ): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') config.substitutions.append(('%target-os-abi', target_os_abi)) diff --git a/test/stdlib/Compatibility50Linking.c b/test/stdlib/Compatibility50Linking.c index b931461ccfbdc..deb98344323b7 100644 --- a/test/stdlib/Compatibility50Linking.c +++ b/test/stdlib/Compatibility50Linking.c @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-clang %s -all_load %test-resource-dir/%target-sdk-name/libswiftCompatibility50.a %test-resource-dir/%target-sdk-name/libswiftCompatibility51.a -lobjc -o %t/main +// RUN: %target-codesign %t/main // RUN: %target-run %t/main // REQUIRES: objc_interop // REQUIRES: executable_test diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index 1f0403e2aade7..399cc90743606 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -278,8 +278,16 @@ DispatchAPI.test("DispatchTime.SchedulerTimeType.Stridable") { let time1 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10000)) let time2 = DispatchQueue.SchedulerTimeType(.init(uptimeNanoseconds: 10431)) let addedTime = time2.distance(to: time1) - expectEqual(addedTime.magnitude, (10000 - 10431)) + // The magnitude of the time sum is in nanosecond units. Although + // the units match up, the internal representation of the + // DispatchTime may round up to multiples of Mach timebase. This + // requires the difference being converted, which is performed here + // by constructing a `DispatchTime` from the delta. However, the + // parameter is a `UInt64` which requires us to perform the negation + // manually. + expectEqual(-Int(DispatchTime(uptimeNanoseconds: 10431 - 10000).uptimeNanoseconds), + addedTime.magnitude) } } -#endif \ No newline at end of file +#endif diff --git a/test/stdlib/ErrorBridged.swift b/test/stdlib/ErrorBridged.swift index cc45b487fc0a8..b996dad5d213f 100644 --- a/test/stdlib/ErrorBridged.swift +++ b/test/stdlib/ErrorBridged.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -o %t/ErrorBridged -DPTR_SIZE_%target-ptrsize -module-name main %s +// RUN: %target-codesign %t/ErrorBridged // RUN: %target-run %t/ErrorBridged // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/test/stdlib/Integers.swift.gyb b/test/stdlib/Integers.swift.gyb index 5fe082d520239..01e664334a77b 100644 --- a/test/stdlib/Integers.swift.gyb +++ b/test/stdlib/Integers.swift.gyb @@ -12,6 +12,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb -DWORD_BITS=%target-ptrsize %s -o %t/Integers.swift // RUN: %line-directive %t/Integers.swift -- %target-build-swift %t/Integers.swift -swift-version 4 -Onone -o %t/a.out +// RUN: %line-directive %t/Integers.swift -- %target-codesign %t/a.out // RUN: %line-directive %t/Integers.swift -- %target-run %t/a.out // REQUIRES: executable_test diff --git a/test/stdlib/OSLogExecutionTest.swift b/test/stdlib/OSLogExecutionTest.swift index 041de11b41ff2..5e1eda880ac7c 100644 --- a/test/stdlib/OSLogExecutionTest.swift +++ b/test/stdlib/OSLogExecutionTest.swift @@ -1,8 +1,10 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift %s -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-codesign %t/OSLogExecutionTest // RUN: %target-run %t/OSLogExecutionTest // // RUN: %target-build-swift %s -O -swift-version 5 -DPTR_SIZE_%target-ptrsize -o %t/OSLogExecutionTest +// RUN: %target-codesign %t/OSLogExecutionTest // RUN: %target-run %t/OSLogExecutionTest // REQUIRES: executable_test // diff --git a/test/stdlib/PrintFloat.swift.gyb b/test/stdlib/PrintFloat.swift.gyb index 8556d875368d9..2795a1c8a3473 100644 --- a/test/stdlib/PrintFloat.swift.gyb +++ b/test/stdlib/PrintFloat.swift.gyb @@ -442,21 +442,20 @@ fileprivate func expectNaN(_ expected: String, _ object: T, message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) - // debugDescription prints full details about NaNs, which is tricky to test - // because NaNs often get truncated: various implementations force all NaNs - // quiet, discard payloads, or clear sign bits. In some cases, just passing a - // NaN into a function (via an FP register) is enough to mangle the value. - -#if arch(x86_64) - // Verify the exact debugDescription value only on x86_64, where we - // know the exact expected String: + // debugDescription tries to print details about NaNs, which is tricky to test. + +/* + // We cannot reliably test the exact expected string, because various + // implementations force all NaNs quiet, discard payloads, or clear sign bits. + // In some cases, just passing a NaN into a function (via an FP register) is + // enough to mangle the value. expectEqual(expected, object.debugDescription, message(), stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) -#endif +*/ - // On all platforms, we verify that the generated debugDescription text - // follows the expected format, even when we can't verify the exact value. + // We can verify that the generated debugDescription text + // follows the expected general format, even when we can't verify the exact value. var actual = object.debugDescription // Optional leading "-" diff --git a/test/stdlib/RangeTraps.swift b/test/stdlib/RangeTraps.swift index bf9e5e06e6291..c8e265416ef66 100644 --- a/test/stdlib/RangeTraps.swift +++ b/test/stdlib/RangeTraps.swift @@ -74,7 +74,47 @@ RangeTraps.test("CountablePartialRangeFrom") _ = it.next() } +RangeTraps.test("nanLowerBound") + .code { + expectCrashLater() + _ = Double.nan ... 0 +} + +RangeTraps.test("nanUpperBound") + .code { + expectCrashLater() + _ = 0 ... Double.nan +} + +RangeTraps.test("nanLowerBoundPartial") + .code { + expectCrashLater() + _ = Double.nan ..< 0 +} + +RangeTraps.test("nanUpperBoundPartial") + .code { + expectCrashLater() + _ = 0 ..< Double.nan +} +RangeTraps.test("fromNaN") + .code { + expectCrashLater() + _ = Double.nan... +} + +RangeTraps.test("toNaN") + .code { + expectCrashLater() + _ = .. %t.txt // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/test/stdlib/TestData.swift b/test/stdlib/TestData.swift index 88abfb35e5eb9..b3348142cc43e 100644 --- a/test/stdlib/TestData.swift +++ b/test/stdlib/TestData.swift @@ -1077,6 +1077,99 @@ class TestData : TestDataSuper { expectEqual(slice4[0], 8) } + func test_rangeOfDataProtocol() { + // https://bugs.swift.org/browse/SR-10689 + + let base = Data([0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03]) + let subdata = base[10..<13] // [0x02, 0x03, 0x00] + let oneByte = base[14..<15] // [0x02] + + do { // firstRange(of:in:) + func assertFirstRange(_ data: Data, _ fragment: Data, range: ClosedRange? = nil, + expectedStartIndex: Int?, + _ message: @autoclosure () -> String = "", + file: String = #file, line: UInt = #line) { + if let index = expectedStartIndex { + let expectedRange: Range = index..<(index + fragment.count) + if let someRange = range { + expectEqual(data.firstRange(of: fragment, in: someRange), expectedRange, message(), file: file, line: line) + } else { + expectEqual(data.firstRange(of: fragment), expectedRange, message(), file: file, line: line) + } + } else { + if let someRange = range { + expectNil(data.firstRange(of: fragment, in: someRange), message(), file: file, line: line) + } else { + expectNil(data.firstRange(of: fragment), message(), file: file, line: line) + } + } + } + + assertFirstRange(base, base, expectedStartIndex: base.startIndex) + assertFirstRange(base, subdata, expectedStartIndex: 2) + assertFirstRange(base, oneByte, expectedStartIndex: 2) + + assertFirstRange(subdata, base, expectedStartIndex: nil) + assertFirstRange(subdata, subdata, expectedStartIndex: subdata.startIndex) + assertFirstRange(subdata, oneByte, expectedStartIndex: subdata.startIndex) + + assertFirstRange(oneByte, base, expectedStartIndex: nil) + assertFirstRange(oneByte, subdata, expectedStartIndex: nil) + assertFirstRange(oneByte, oneByte, expectedStartIndex: oneByte.startIndex) + + assertFirstRange(base, subdata, range: 1...14, expectedStartIndex: 2) + assertFirstRange(base, subdata, range: 6...8, expectedStartIndex: 6) + assertFirstRange(base, subdata, range: 8...10, expectedStartIndex: nil) + + assertFirstRange(base, oneByte, range: 1...14, expectedStartIndex: 2) + assertFirstRange(base, oneByte, range: 6...6, expectedStartIndex: 6) + assertFirstRange(base, oneByte, range: 8...9, expectedStartIndex: nil) + } + + do { // lastRange(of:in:) + func assertLastRange(_ data: Data, _ fragment: Data, range: ClosedRange? = nil, + expectedStartIndex: Int?, + _ message: @autoclosure () -> String = "", + file: String = #file, line: UInt = #line) { + if let index = expectedStartIndex { + let expectedRange: Range = index..<(index + fragment.count) + if let someRange = range { + expectEqual(data.lastRange(of: fragment, in: someRange), expectedRange, message(), file: file, line: line) + } else { + expectEqual(data.lastRange(of: fragment), expectedRange, message(), file: file, line: line) + } + } else { + if let someRange = range { + expectNil(data.lastRange(of: fragment, in: someRange), message(), file: file, line: line) + } else { + expectNil(data.lastRange(of: fragment), message(), file: file, line: line) + } + } + } + + assertLastRange(base, base, expectedStartIndex: base.startIndex) + assertLastRange(base, subdata, expectedStartIndex: 10) + assertLastRange(base, oneByte, expectedStartIndex: 14) + + assertLastRange(subdata, base, expectedStartIndex: nil) + assertLastRange(subdata, subdata, expectedStartIndex: subdata.startIndex) + assertLastRange(subdata, oneByte, expectedStartIndex: subdata.startIndex) + + assertLastRange(oneByte, base, expectedStartIndex: nil) + assertLastRange(oneByte, subdata, expectedStartIndex: nil) + assertLastRange(oneByte, oneByte, expectedStartIndex: oneByte.startIndex) + + assertLastRange(base, subdata, range: 1...14, expectedStartIndex: 10) + assertLastRange(base, subdata, range: 6...8, expectedStartIndex: 6) + assertLastRange(base, subdata, range: 8...10, expectedStartIndex: nil) + + assertLastRange(base, oneByte, range: 1...14, expectedStartIndex: 14) + assertLastRange(base, oneByte, range: 6...6, expectedStartIndex: 6) + assertLastRange(base, oneByte, range: 8...9, expectedStartIndex: nil) + } + } + func test_sliceAppending() { // https://bugs.swift.org/browse/SR-4473 var fooData = Data() @@ -4022,6 +4115,7 @@ DataTests.test("test_noCopyBehavior") { TestData().test_noCopyBehavior() } DataTests.test("test_doubleDeallocation") { TestData().test_doubleDeallocation() } DataTests.test("test_repeatingValueInitialization") { TestData().test_repeatingValueInitialization() } DataTests.test("test_rangeZoo") { TestData().test_rangeZoo() } +DataTests.test("test_rangeOfDataProtocol") { TestData().test_rangeOfDataProtocol() } DataTests.test("test_sliceAppending") { TestData().test_sliceAppending() } DataTests.test("test_replaceSubrange") { TestData().test_replaceSubrange() } DataTests.test("test_sliceWithUnsafeBytes") { TestData().test_sliceWithUnsafeBytes() } diff --git a/test/stdlib/dlopen_race.swift b/test/stdlib/dlopen_race.swift index 43d12118eca16..ce8c8a43df5a0 100644 --- a/test/stdlib/dlopen_race.swift +++ b/test/stdlib/dlopen_race.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -emit-library -o %t/dlopen_race.dylib %S/Inputs/dlopen_race_dylib.swift // RUN: %target-build-swift -o %t/dlopen_race %s +// RUN: %target-codesign %t/dlopen_race %t/dlopen_race.dylib // RUN: %target-run %t/dlopen_race %t/dlopen_race.dylib // REQUIRES: executable_test // REQUIRES: objc_interop diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index edb5397cc9328..9aad8debef09e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -22,6 +22,7 @@ add_swift_tool_subdirectory(swift-ide-test) add_swift_tool_subdirectory(swift-remoteast-test) add_swift_tool_subdirectory(swift-demangle) add_swift_tool_subdirectory(swift-demangle-yamldump) +add_swift_tool_subdirectory(swift-serialize-diagnostics) add_swift_tool_subdirectory(lldb-moduleimport-test) add_swift_tool_subdirectory(sil-func-extractor) add_swift_tool_subdirectory(sil-llvm-gen) diff --git a/tools/swift-serialize-diagnostics/CMakeLists.txt b/tools/swift-serialize-diagnostics/CMakeLists.txt new file mode 100644 index 0000000000000..13cf756c13c49 --- /dev/null +++ b/tools/swift-serialize-diagnostics/CMakeLists.txt @@ -0,0 +1,7 @@ +add_swift_host_tool(swift-serialize-diagnostics + swift-serialize-diagnostics.cpp + SWIFT_COMPONENT tools +) +target_link_libraries(swift-serialize-diagnostics + PRIVATE + swiftAST) diff --git a/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp new file mode 100644 index 0000000000000..01ea696002637 --- /dev/null +++ b/tools/swift-serialize-diagnostics/swift-serialize-diagnostics.cpp @@ -0,0 +1,97 @@ +//===--- swift-serialize-diagnostics.cpp ----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 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 +// +//===----------------------------------------------------------------------===// +// +// Convert localization YAML files to a srialized format. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/LocalizationFormat.h" +#include "swift/Basic/LLVMInitialize.h" +#include "swift/Basic/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/OnDiskHashTable.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLParser.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace swift; +using namespace swift::diag; + +namespace options { + +static llvm::cl::OptionCategory Category("swift-serialize-diagnostics Options"); + +static llvm::cl::opt + InputFilePath("input-file-path", + llvm::cl::desc("Path to the YAML input file"), + llvm::cl::cat(Category)); + +static llvm::cl::opt + OutputDirectory("output-directory", + llvm::cl::desc("Directory for the output file"), + llvm::cl::cat(Category)); + +} // namespace options + +int main(int argc, char *argv[]) { + PROGRAM_START(argc, argv); + + llvm::cl::HideUnrelatedOptions(options::Category); + llvm::cl::ParseCommandLineOptions(argc, argv, + "Swift Serialize Diagnostics Tool\n"); + + if (!llvm::sys::fs::exists(options::InputFilePath)) { + llvm::errs() << "YAML file not found\n"; + return EXIT_FAILURE; + } + + YAMLLocalizationProducer yaml(options::InputFilePath); + + auto localeCode = llvm::sys::path::filename(options::InputFilePath); + llvm::SmallString<128> SerializedFilePath(options::OutputDirectory); + llvm::sys::path::append(SerializedFilePath, localeCode); + llvm::sys::path::replace_extension(SerializedFilePath, ".db"); + + SerializedLocalizationWriter Serializer; + yaml.forEachAvailable( + [&Serializer](swift::DiagID id, llvm::StringRef translation) { + Serializer.insert(id, translation); + }); + + if (Serializer.emit(SerializedFilePath.str())) { + llvm::errs() << "Cannot serialize diagnostic file " + << options::InputFilePath << '\n'; + return EXIT_FAILURE; + } + + // Print out the diagnostics IDs that are available in YAML but not available + // in `.def` + if (!yaml.unknownIDs.empty()) { + llvm::errs() << "These diagnostic IDs are no longer availiable: '"; + llvm::interleave( + yaml.unknownIDs, [&](std::string id) { llvm::errs() << id; }, + [&] { llvm::errs() << ", "; }); + llvm::errs() << "'\n"; + } + + return EXIT_SUCCESS; +} diff --git a/unittests/Syntax/TypeSyntaxTests.cpp b/unittests/Syntax/TypeSyntaxTests.cpp index 22711ccc0d92f..267d8787335cb 100644 --- a/unittests/Syntax/TypeSyntaxTests.cpp +++ b/unittests/Syntax/TypeSyntaxTests.cpp @@ -471,7 +471,7 @@ TEST(TypeSyntaxTests, FunctionTypeMakeAPIs) { auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {}); auto IntArg = SyntaxFactory::makeBlankTupleTypeElement() .withType(Int); - auto Async = SyntaxFactory::makeContextualKeyword( + auto Async = SyntaxFactory::makeIdentifier( "async", { }, { Trivia::spaces(1) }); auto Throws = SyntaxFactory::makeThrowsKeyword({}, { Trivia::spaces(1) }); auto Rethrows = SyntaxFactory::makeRethrowsKeyword({}, diff --git a/utils/WindowsSDKVFSOverlay.yaml.in b/utils/WindowsSDKVFSOverlay.yaml.in index ed491aa90a2ef..e8fb615273b8f 100644 --- a/utils/WindowsSDKVFSOverlay.yaml.in +++ b/utils/WindowsSDKVFSOverlay.yaml.in @@ -149,6 +149,9 @@ roots: - name: unknwn.h type: file external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Unknwn.h" + - name: uxtheme.h + type: file + external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Uxtheme.h" - name: unknwnbase.h type: file external-contents: "@UniversalCRTSdkDir@/Include/@UCRTVersion@/um/Unknwnbase.h" diff --git a/utils/build-script-impl b/utils/build-script-impl index da29ab62e3d61..c1194abc94fd9 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -2474,13 +2474,15 @@ for host in "${ALL_HOSTS[@]}"; do executable_target= results_targets= if ! [[ "${SKIP_TEST_SWIFT}" ]]; then - executable_target=SwiftUnitTests - results_targets=("${SWIFT_TEST_TARGETS[@]}") - if [[ "${STRESS_TEST_SOURCEKIT}" ]]; then - results_targets=( - "${results_targets[@]}" - stress-SourceKit - ) + if ! [[ $(is_cross_tools_host ${host}) ]] ; then + executable_target=SwiftUnitTests + results_targets=("${SWIFT_TEST_TARGETS[@]}") + if [[ "${STRESS_TEST_SOURCEKIT}" ]]; then + results_targets=( + "${results_targets[@]}" + stress-SourceKit + ) + fi fi fi if ! [[ "${SKIP_TEST_BENCHMARKS}" ]]; then @@ -2497,6 +2499,10 @@ for host in "${ALL_HOSTS[@]}"; do if [[ "${SKIP_TEST_LLDB}" ]]; then continue fi + if [[ $(is_cross_tools_host ${host}) ]]; then + echo "--- Can't execute tests for ${host}, skipping... ---" + continue + fi llvm_build_dir=$(build_directory ${host} llvm) lldb_build_dir=$(build_directory ${host} lldb) results_dir="${lldb_build_dir}/test-results" @@ -2797,7 +2803,11 @@ for host in "${ALL_HOSTS[@]}"; do if [[ "${LLVM_INSTALL_COMPONENTS}" == "all" ]] ; then INSTALL_TARGETS=install elif [[ -n "${LLVM_INSTALL_COMPONENTS}" ]] ; then - INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/;/ install-/g') + if [[ $(is_cross_tools_host ${host}) && "${LLVM_INSTALL_COMPONENTS}" == *"compiler-rt"* ]]; then + INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/compiler-rt;//g' |sed -E 's/;/ install-/g') + else + INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/;/ install-/g') + fi fi ;; libcxx) diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py index a6455574654ce..515ea4fe02723 100644 --- a/utils/gyb_syntax_support/DeclNodes.py +++ b/utils/gyb_syntax_support/DeclNodes.py @@ -76,7 +76,8 @@ Node('FunctionSignature', kind='Syntax', children=[ Child('Input', kind='ParameterClause'), - Child('AsyncKeyword', kind='ContextualKeywordToken', + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', text_choices=['async'], is_optional=True), Child('ThrowsOrRethrowsKeyword', kind='Token', is_optional=True, diff --git a/utils/gyb_syntax_support/ExprNodes.py b/utils/gyb_syntax_support/ExprNodes.py index 730c9bf0d92cb..8b442d8c307a1 100644 --- a/utils/gyb_syntax_support/ExprNodes.py +++ b/utils/gyb_syntax_support/ExprNodes.py @@ -191,7 +191,8 @@ # NOTE: This appears only in SequenceExpr. Node('ArrowExpr', kind='Expr', children=[ - Child('AsyncKeyword', kind='ContextualKeywordToken', + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', text_choices=['async'], is_optional=True), Child('ThrowsToken', kind='ThrowsToken', is_optional=True), diff --git a/utils/gyb_syntax_support/TypeNodes.py b/utils/gyb_syntax_support/TypeNodes.py index 87dbed52dfd16..527dc4d3ccd40 100644 --- a/utils/gyb_syntax_support/TypeNodes.py +++ b/utils/gyb_syntax_support/TypeNodes.py @@ -167,8 +167,9 @@ Child('Arguments', kind='TupleTypeElementList', collection_element_name='Argument'), Child('RightParen', kind='RightParenToken'), - Child('AsyncKeyword', kind='Token', text_choices=['async'], - is_optional=True), + Child('AsyncKeyword', kind='IdentifierToken', + classification='Keyword', + text_choices=['async'], is_optional=True), Child('ThrowsOrRethrowsKeyword', kind='Token', is_optional=True, token_choices=[ diff --git a/utils/update_checkout/update-checkout-config.json b/utils/update_checkout/update-checkout-config.json index 905467e8dc06e..aecfa29a90c75 100644 --- a/utils/update_checkout/update-checkout-config.json +++ b/utils/update_checkout/update-checkout-config.json @@ -345,29 +345,29 @@ "tensorflow": { "aliases": ["tensorflow"], "repos": { - "llvm-project": "fc41e0afba70b658d512459ec631c6b4b9a526e8", + "llvm-project": "18d86c328dd7322dfede628b3cf5cd312a6efa7c", "swift": "tensorflow", - "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "cmark": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "llbuild": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "swift-tools-support-core": "0.1.8", - "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-argument-parser": "0.2.1", + "swiftpm": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-argument-parser": "0.2.2", "swift-driver": "bf0026c636347b4c31aab21deb01943529b7e556", - "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "swift-syntax": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-stress-tester": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-xctest": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-foundation": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-corelibs-libdispatch": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-integration-tests": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "swift-xcode-playground-support": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "ninja": "release", "icu": "release-65-1", "yams": "3.0.1-patched", - "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", - "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a", + "indexstore-db": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", + "sourcekit-lsp": "swift-DEVELOPMENT-SNAPSHOT-2020-08-07-a", "PythonKit": "master", "swift-format": "master", - "tensorflow": "v2.2.0-rc0", + "tensorflow": "v2.3.0", "tensorflow-swift-apis": "master" } } diff --git a/validation-test/Reflection/reflect_nested.swift b/validation-test/Reflection/reflect_nested.swift index 41173d58fe41d..90cbc1a3c331d 100644 --- a/validation-test/Reflection/reflect_nested.swift +++ b/validation-test/Reflection/reflect_nested.swift @@ -1,5 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_nested +// RUN: %target-codesign %t/reflect_nested // RUN: %target-run %target-swift-reflection-test %t/reflect_nested 2>&1 | %FileCheck %s --check-prefix=CHECK-%target-ptrsize // REQUIRES: reflection_test_support // REQUIRES: executable_test diff --git a/validation-test/SILOptimizer/large_string_array.swift.gyb b/validation-test/SILOptimizer/large_string_array.swift.gyb index 7a0169748ead0..91280bd424040 100644 --- a/validation-test/SILOptimizer/large_string_array.swift.gyb +++ b/validation-test/SILOptimizer/large_string_array.swift.gyb @@ -1,9 +1,6 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s > %t/main.swift -// FIXME: Re-enable SILOptimizer/large_string_array.swift.gyb -// REQUIRES: rdar66219627 - // The compiler should finish in less than 1 minute. To give some slack, // specify a timeout of 5 minutes. // If the compiler needs more than 5 minutes, there is probably a real problem. @@ -15,6 +12,8 @@ // REQUIRES: long_test // REQUIRES: CPU=arm64 || CPU=x86_64 +// REQUIRES: rdar66807959 + // Check if the optimizer can optimize the whole array into a statically // initialized global diff --git a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb b/validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb similarity index 68% rename from validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb rename to validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb index cfd18b2c7006e..1dd787e01ee08 100644 --- a/validation-test/Sema/type_checker_perf/slow/rdar30596744_2.swift.gyb +++ b/validation-test/Sema/type_checker_perf/fast/rdar30596744_2.swift.gyb @@ -1,4 +1,4 @@ -// RUN: %scale-test --invert-result --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 +// RUN: %scale-test --begin 1 --end 5 --step 1 --select NumLeafScopes %s --expected-exit-code 1 // REQUIRES: asserts,no_asan % enum_cases = 3 diff --git a/validation-test/compiler_crashers_2_fixed/rdar66588925.swift b/validation-test/compiler_crashers_2_fixed/rdar66588925.swift new file mode 100644 index 0000000000000..ac94cbceb3c1e --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar66588925.swift @@ -0,0 +1,4 @@ +// RUN: not %target-swift-frontend -typecheck %s + +class DataType: DataType {} +extension DataType: Encodable {} diff --git a/validation-test/execution/arc_36509461.swift b/validation-test/execution/arc_36509461.swift index 5c730e33220f2..0d42cc5c1f1b4 100644 --- a/validation-test/execution/arc_36509461.swift +++ b/validation-test/execution/arc_36509461.swift @@ -2,6 +2,7 @@ // RUN: %target-clang -x objective-c -c %S/Inputs/arc_36509461.m -o %t/arc_36509461.m.o // RUN: %target-swift-frontend -c -O -import-objc-header %S/Inputs/arc_36509461.h -sanitize=address %s -o %t/arc_36509461.swift.o // RUN: %target-build-swift %t/arc_36509461.m.o %t/arc_36509461.swift.o -sanitize=address -o %t/arc_36509461 +// RUN: %target-codesign %t/arc_36509461 // RUN: %target-run %t/arc_36509461 // REQUIRES: executable_test diff --git a/validation-test/stdlib/NewArray.swift.gyb b/validation-test/stdlib/NewArray.swift.gyb index 4bfb174b34905..764cd5ec8d295 100644 --- a/validation-test/stdlib/NewArray.swift.gyb +++ b/validation-test/stdlib/NewArray.swift.gyb @@ -13,6 +13,7 @@ // RUN: %empty-directory(%t) // RUN: %gyb %s -o %t/NewArray.swift // RUN: %line-directive %t/NewArray.swift -- %target-build-swift %t/NewArray.swift -o %t/a.out -Xfrontend -disable-access-control +// RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out 2>&1 | %line-directive %t/NewArray.swift -- %FileCheck %t/NewArray.swift --check-prefix=CHECK --check-prefix=CHECK-%target-runtime // REQUIRES: executable_test diff --git a/validation-test/stdlib/Range.swift.gyb b/validation-test/stdlib/Range.swift.gyb index 11766c272c1ea..b8fa3838e0f7f 100644 --- a/validation-test/stdlib/Range.swift.gyb +++ b/validation-test/stdlib/Range.swift.gyb @@ -401,7 +401,7 @@ ${TestSuite}.test("Equatable") { ${TestSuite}.test("'${op}' traps when upperBound < lowerBound") .crashOutputMatches(_isDebugAssertConfiguration() ? - "Can't form Range with upperBound < lowerBound" : "") + "Range requires lowerBound <= upperBound" : "") .code { let _1 = ${Bound}(1) let _2 = ${Bound}(2)