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/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/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/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/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index dffa6c581e48d..5029660d88834 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -4873,6 +4873,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 4fa5b46942946..d0577f975b1fc 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -278,6 +278,7 @@ getLayoutFunctionForComputedComponent(IRGenModule &IGM, auto layoutFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_get_arg_layout", IGM.getModule()); + layoutFn->setAttributes(IGM.constructInitialAttributes()); layoutFn->setCallingConv(IGM.SwiftCC); { @@ -381,6 +382,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, llvm::GlobalValue::PrivateLinkage, "keypath_destroy", IGM.getModule()); destroyFn->setCallingConv(IGM.SwiftCC); destroy = destroyFn; + destroyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, destroyFn); if (IGM.DebugInfo) @@ -430,6 +432,7 @@ getWitnessTableForComputedComponent(IRGenModule &IGM, llvm::GlobalValue::PrivateLinkage, "keypath_copy", IGM.getModule()); copyFn->setCallingConv(IGM.SwiftCC); copy = copyFn; + copyFn->setAttributes(IGM.constructInitialAttributes()); IRGenFunction IGF(IGM, copyFn); if (IGM.DebugInfo) @@ -542,8 +545,8 @@ getInitializerForComputedComponent(IRGenModule &IGM, auto initFn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage, "keypath_arg_init", IGM.getModule()); + initFn->setAttributes(IGM.constructInitialAttributes()); initFn->setCallingConv(IGM.SwiftCC); - { IRGenFunction IGF(IGM, initFn); @@ -951,23 +954,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/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index b2b0cb3a7d2d9..34ab8da4de979 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1428,6 +1428,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 8f33b91a85fef..87a40476b5912 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,141 +2796,133 @@ 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); - llvm::Value *stringAddr; - if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { - stringAddr = subIGF.Builder.CreateIntToPtr(stringAddrOffset, IGM.Int8PtrTy); - } else { - auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); - if (IGM.getModule()->getDataLayout().isBigEndian()) { - stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, - llvm::ConstantInt::get(IGM.SizeTy, 4)); - } - stringAddr = subIGF.Builder.CreateAdd(stringAddrBase, - stringAddrOffset); - stringAddr = subIGF.Builder.CreateIntToPtr(stringAddr, IGM.Int8PtrTy); + 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); + + llvm::Value *stringAddr; + if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::Wasm) { + stringAddr = subIGF.Builder.CreateIntToPtr(stringAddrOffset, IGM.Int8PtrTy); + } else { + auto stringAddrBase = subIGF.Builder.CreatePtrToInt(cache, IGM.SizeTy); + if (IGM.getModule()->getDataLayout().isBigEndian()) { + stringAddrBase = subIGF.Builder.CreateAdd(stringAddrBase, + llvm::ConstantInt::get(IGM.SizeTy, 4)); } + 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); - 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); - }(); - } + // 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/SILOptimizer/Differentiation/PullbackCloner.cpp b/lib/SILOptimizer/Differentiation/PullbackCloner.cpp index 0438285ed07aa..79611c38eaaf4 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 a `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::Trivial); + } 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,64 @@ 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); + blockTemporaries[getPullbackBlock(predBB)].insert(concreteBBArgAdjCopy); + // Handle `switch_enum` on `Optional`. + auto termInst = bbArg->getSingleTerminator(); + if (isSwitchEnumInstOnOptional(termInst)) + accumulateAdjointForOptional(bb, incomingValue, concreteBBArgAdjCopy); + else + 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 +2842,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/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/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index c24f5b0eeac43..c5715942de0c6 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2699,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; } @@ -5469,124 +5469,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, @@ -5678,13 +5560,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(); 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 ee0a332e702d8..64e41d6f52d71 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -6598,3 +6598,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 fd84a2be78015..4a5505a69a634 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -2216,6 +2216,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 dc8da1a9db443..6e91606d735bb 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3999,6 +3999,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 8e58a6d89201e..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. @@ -6591,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) @@ -9967,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; } diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h index b11704caec940..4e4924a0bc78b 100644 --- a/lib/Sema/ConstraintSystem.h +++ b/lib/Sema/ConstraintSystem.h @@ -559,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; } @@ -586,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. 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/DerivedConformances.h b/lib/Sema/DerivedConformances.h index c5dba4bb20172..3465402b7a9d6 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/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 7743f1d336f20..e68a7b2d095fa 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5691,8 +5691,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); default: diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index fe1066c5d534e..21fe9d350ff71 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -807,7 +807,8 @@ Type AssociatedTypeInference::computeFixedTypeWitness( // require a fixed type for this associated type. Type resultType; for (auto conformedProto : adoptee->getAnyNominal()->getAllProtocols()) { - if (!conformedProto->inheritsFrom(assocType->getProtocol())) + if (conformedProto != assocType->getProtocol() && + !conformedProto->inheritsFrom(assocType->getProtocol())) continue; const auto genericSig = conformedProto->getGenericSignature(); 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..(_ 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..c2fc0fac4a695 --- /dev/null +++ b/test/AutoDiff/validation-test/optional.swift @@ -0,0 +1,319 @@ +// RUN: %target-run-simple-swift +// REQUIRES: executable_test + +import StdlibUnittest +import DifferentiationUnittest + +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_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 { + 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_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_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_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_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_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_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_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/patterns.swift b/test/Constraints/patterns.swift index 2250343a9e666..c79fc2195c719 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 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/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 72a1e63775cf0..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=arm64 || 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 0f19d2f5cc63e..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=arm64 || 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/jit-debugging.swift b/test/IRGen/jit-debugging.swift index 78d59fa93fbf9..6a8a8a5243ee7 100644 --- a/test/IRGen/jit-debugging.swift +++ b/test/IRGen/jit-debugging.swift @@ -12,4 +12,6 @@ // 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/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_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/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/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/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/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/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/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_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/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/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/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_fixed_type.swift b/test/decl/protocol/req/associated_type_inference_fixed_type.swift index 4b8f6c99b3289..67b4de6b4511b 100644 --- a/test/decl/protocol/req/associated_type_inference_fixed_type.swift +++ b/test/decl/protocol/req/associated_type_inference_fixed_type.swift @@ -1,10 +1,9 @@ // RUN: %target-typecheck-verify-swift protocol P1 where A == Never { - associatedtype A // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// FIXME: Should this infer A := Never? -struct S1: P1 {} // expected-error {{type 'S1' does not conform to protocol 'P1'}} +struct S1: P1 {} // OK, A := Never protocol P2a { associatedtype A @@ -54,22 +53,19 @@ protocol P7b: P7a where A == Bool {} struct S7: P7b {} protocol P8 where A == Bool { - associatedtype A // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// expected-error@+2 {{type 'S8' does not conform to protocol 'P7a'}} -// expected-error@+1 {{type 'S8' does not conform to protocol 'P8'}} +// 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 // expected-note {{protocol requires nested type 'A'}} + associatedtype A } -// FIXME: Associated type restatement sabotages the conformance. -// expected-error@+2 {{type 'S9a' does not conform to protocol 'P9a'}} -// expected-error@+1 {{type 'S9a' does not conform to protocol 'P9b'}} -struct S9a: P9b {} +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 { 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/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 ee712560f306f..399cc90743606 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -278,7 +278,15 @@ 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((10000 - 10431), addedTime.magnitude) + // 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) } } 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/StringBridge.swift b/test/stdlib/StringBridge.swift index ade117064deaf..f9ab61c19b930 100644 --- a/test/stdlib/StringBridge.swift +++ b/test/stdlib/StringBridge.swift @@ -1,6 +1,7 @@ // RUN: %empty-directory(%t) // RUN: cp %s %t/main.swift // RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %t/main.swift %S/../Inputs/SmallStringTestUtilities.swift -o %t.out -O +// RUN: %target-codesign %t.out // RUN: %target-run %t.out // REQUIRES: executable_test diff --git a/test/stdlib/TestCalendar.swift b/test/stdlib/TestCalendar.swift index df339391578f5..d6512605c3fd0 100644 --- a/test/stdlib/TestCalendar.swift +++ b/test/stdlib/TestCalendar.swift @@ -11,6 +11,8 @@ // RUN: %target-clang %S/Inputs/FoundationBridge/FoundationBridge.m -c -o %t/FoundationBridgeObjC.o -g // RUN: %target-build-swift %s -I %S/Inputs/FoundationBridge/ -Xlinker %t/FoundationBridgeObjC.o -o %t/TestCalendar +// RUN: %target-codesign %t/TestCalendar + // RUN: %target-run %t/TestCalendar > %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/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/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