diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index c3c42adab8a..268993b9d20 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -279,8 +279,17 @@ class alignas(8) Decl { /// Whether this is a complete object initializer. unsigned CompleteObjectInit : 1; + + /// Whether this initializer is a stub placed into a subclass to + /// catch invalid delegations to a subobject initializer not + /// overridden by the subclass. A stub will always trap at runtime. + /// + /// Initializer stubs can be invoked from Objective-C or through + /// the Objective-C runtime; there is no way to directly express + /// an object construction that will invoke a stub. + unsigned HasStubImplementation : 1; }; - enum { NumConstructorDeclBits = NumAbstractFunctionDeclBits + 5 }; + enum { NumConstructorDeclBits = NumAbstractFunctionDeclBits + 6 }; static_assert(NumConstructorDeclBits <= 32, "fits in an unsigned"); class TypeDeclBitfields { @@ -3742,6 +3751,17 @@ public: return !isCompleteObjectInit(); } + /// Whether the implementation of this method is a stub that traps at runtime. + bool hasStubImplementation() const { + return ConstructorDeclBits.HasStubImplementation; + } + + /// Set whether the implementation of this method is a stub that + /// traps at runtime. + void setStubImplementation(bool stub) { + ConstructorDeclBits.HasStubImplementation = stub; + } + ConstructorDecl *getOverriddenDecl() const { return OverriddenDecl; } void setOverriddenDecl(ConstructorDecl *over) { OverriddenDecl = over; } diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 4666b768f4f..7e4d7485e86 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -464,6 +464,16 @@ public: /// \brief Retrieve the type without any default arguments. Type getWithoutDefaultArgs(const ASTContext &Context); + /// Replace the result type of the given function type with a new + /// result type. + /// + /// \param newResultType The new result type. + /// + /// \param uncurryLevel The number of uncurry levels to apply before + /// replacing the type. With uncurry level == 0, this simply + /// replaces the current type with the new result type. + Type replaceResultType(Type newResultType, unsigned uncurryLevel = 1); + /// getRValueType - For an @lvalue type, retrieves the underlying object type. /// Otherwise, returns the type itself. Type getRValueType(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7af82d46878..3c8fd3a52c3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1155,6 +1155,10 @@ bool ClassDecl::inheritsSuperclassInitializers(LazyResolver *resolver) { if (!ctor->hasType()) resolver->resolveDeclSignature(ctor); + // Ignore any stub implementations. + if (ctor->hasStubImplementation()) + continue; + if (auto overridden = ctor->getOverriddenDecl()) { if (overridden->isSubobjectInit()) overriddenInits.insert(overridden); @@ -1983,6 +1987,7 @@ ConstructorDecl::ConstructorDecl(Identifier NameHack, SourceLoc ConstructorLoc, ConstructorDeclBits.ComputedBodyInitKind = 0; ConstructorDeclBits.Required = 0; ConstructorDeclBits.CompleteObjectInit = 0; + ConstructorDeclBits.HasStubImplementation = 0; } void ConstructorDecl::setArgParams(Pattern *selfPattern, Pattern *argParams) { diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index ae39b1209bd..2e0718f11b1 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -885,10 +885,9 @@ bool DeclContext::lookupQualified(Type type, // Allow filtering of the visible declarations based on bool onlyCompleteObjectInits = false; auto isAcceptableDecl = [&](NominalTypeDecl *current, Decl *decl) -> bool { - // Filter out subobject initializers, if requestred. + // Filter out subobject initializers, if requested. if (onlyCompleteObjectInits) { - // Allow any initializer in an Objective-C class that neither declares nor - // inherits designated initializers. + // Allow any initializer in an Objective-C class. bool assumeCompleteObjectInit = false; if (current->hasClangNode()) { if (auto objcClass @@ -906,6 +905,12 @@ bool DeclContext::lookupQualified(Type type, } } + // Ignore stub implementations. + if (auto ctor = dyn_cast(decl)) { + if (ctor->hasStubImplementation()) + return false; + } + return true; }; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 891c9f26f07..d30d6961061 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -491,6 +491,32 @@ Type TypeBase::getWithoutDefaultArgs(const ASTContext &Context) { /*defaultArgs=*/true); } +Type TypeBase::replaceResultType(Type newResultType, unsigned uncurryLevel) { + if (uncurryLevel == 0) + return newResultType; + + // Determine the input and result types of this function. + auto fnType = this->castTo(); + Type inputType = fnType->getInput(); + Type resultType = fnType->getResult()->replaceResultType(newResultType, + uncurryLevel - 1); + + // Produce the resulting function type. + if (auto genericFn = dyn_cast(fnType)) { + return GenericFunctionType::get(genericFn->getGenericSignature(), + inputType, resultType, + fnType->getExtInfo()); + } + + if (auto polyFn = dyn_cast(fnType)) { + return PolymorphicFunctionType::get(inputType, resultType, + &polyFn->getGenericParams(), + fnType->getExtInfo()); + } + + return FunctionType::get(inputType, resultType, fnType->getExtInfo()); +} + /// Retrieve the object type for a 'self' parameter, digging into one-element /// tuples, lvalue types, and metatypes. Type TypeBase::getRValueInstanceType() { diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 18257e91d78..7017e23ba1a 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2717,11 +2717,15 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { // FIXME: Hack until all delegation is dispatched. IsCompleteObjectInit = ctor->isCompleteObjectInit(); - assert(ctor->getBody() && "Class constructor without a body?"); + assert((ctor->getBody() || ctor->hasStubImplementation()) && + "Class constructor without a body?"); // True if this constructor delegates to a peer constructor with self.init(). - bool isDelegating = ctor->getDelegatingOrChainedInitKind(nullptr) == - ConstructorDecl::BodyInitKind::Delegating; + bool isDelegating = false; + if (!ctor->hasStubImplementation()) { + isDelegating = ctor->getDelegatingOrChainedInitKind(nullptr) == + ConstructorDecl::BodyInitKind::Delegating; + } // FIXME: The (potentially partially initialized) value here would need to be // cleaned up on a constructor failure unwinding. @@ -2738,7 +2742,8 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { auto selfTypeContext = ctor->getDeclContext()->getDeclaredTypeInContext(); auto selfClassDecl = cast(selfTypeContext->getNominalOrBoundGenericNominal()); - bool NeedsBoxForSelf = isDelegating || selfClassDecl->hasSuperclass(); + bool NeedsBoxForSelf = isDelegating || + (selfClassDecl->hasSuperclass() && !ctor->hasStubImplementation()); if (NeedsBoxForSelf) emitLocalVariable(selfDecl); @@ -2754,33 +2759,37 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { if (!NeedsBoxForSelf) B.createDebugValue(selfDecl, selfArg); - // If needed, mark 'self' as uninitialized so that DI knows to enforce its DI - // properties on stored properties. - MarkUninitializedInst::Kind MUKind; - bool usesObjCAllocator = Lowering::usesObjCAllocator(selfClassDecl); - if (isDelegating) - MUKind = MarkUninitializedInst::DelegatingSelf; - else if (selfClassDecl->requiresStoredPropertyInits() && usesObjCAllocator) { - // Stored properties will be initialized in a separate .cxx_construct method - // called by the Objective-C runtime. - assert(selfClassDecl->hasSuperclass() && - "Cannot use ObjC allocation without a superclass"); - MUKind = MarkUninitializedInst::DerivedSelfOnly; - } else if (selfClassDecl->hasSuperclass()) - MUKind = MarkUninitializedInst::DerivedSelf; - else - MUKind = MarkUninitializedInst::RootSelf; + if (!ctor->hasStubImplementation()) { + // If needed, mark 'self' as uninitialized so that DI knows to + // enforce its DI properties on stored properties. + MarkUninitializedInst::Kind MUKind; + + if (isDelegating) + MUKind = MarkUninitializedInst::DelegatingSelf; + else if (selfClassDecl->requiresStoredPropertyInits() && + usesObjCAllocator) { + // Stored properties will be initialized in a separate + // .cxx_construct method called by the Objective-C runtime. + assert(selfClassDecl->hasSuperclass() && + "Cannot use ObjC allocation without a superclass"); + MUKind = MarkUninitializedInst::DerivedSelfOnly; + } else if (selfClassDecl->hasSuperclass()) + MUKind = MarkUninitializedInst::DerivedSelf; + else + MUKind = MarkUninitializedInst::RootSelf; - selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind); - assert(selfTy.hasReferenceSemantics() && "can't emit a value type ctor here"); + selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind); + assert(selfTy.hasReferenceSemantics() && + "can't emit a value type ctor here"); - if (NeedsBoxForSelf) { - SILLocation prologueLoc = RegularLocation(ctor); - prologueLoc.markAsPrologue(); - B.createStore(prologueLoc, selfArg, VarLocs[selfDecl].getAddress()); - } else { - VarLocs[selfDecl] = VarLoc::getConstant(selfArg); + if (NeedsBoxForSelf) { + SILLocation prologueLoc = RegularLocation(ctor); + prologueLoc.markAsPrologue(); + B.createStore(prologueLoc, selfArg, VarLocs[selfDecl].getAddress()); + } else { + VarLocs[selfDecl] = VarLoc::getConstant(selfArg); + } } // Prepare the end of initializer location. @@ -2795,7 +2804,10 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { if (isDelegating) { // A delegating initializer does not initialize instance // variables. - } else if (selfClassDecl->requiresStoredPropertyInits() && usesObjCAllocator) { + } else if (ctor->hasStubImplementation()) { + // Nor does a stub implementation. + } else if (selfClassDecl->requiresStoredPropertyInits() && + usesObjCAllocator) { // When the class requires all stored properties to have initial // values and we're using Objective-C's allocation, stored // properties are initialized via the .cxx_construct method, which @@ -2808,7 +2820,14 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { } // Emit the constructor body. - visit(ctor->getBody()); + if (ctor->hasStubImplementation()) { + auto int1Ty = SILType::getBuiltinIntegerType(1, getASTContext()); + auto *trueInst = B.createIntegerLiteral(endOfInitLoc, int1Ty, 1); + auto *failInst = B.createCondFail(endOfInitLoc, trueInst); + (void)failInst; + } else { + visit(ctor->getBody()); + } // Return 'self' in the epilog. Optional maybeReturnValue; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 2a83a72ef23..7ee29a08205 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -1998,6 +1998,78 @@ public: } } + /// Create a new initializer that overrides the given subobject + /// initializer. + /// + /// \param classDecl The subclass in which the new initializer will + /// be declared. + /// + /// \param superclassCtor The superclass initializer for which this + /// routine will create an override. + /// + /// \returns the newly-created initializer that overrides \p + /// superclassCtor. + ConstructorDecl * + createSubobjectInitOverride(ClassDecl *classDecl, + ConstructorDecl *superclassCtor) { + // Determine the initializer parameters. + Type superInitType = superclassCtor->getInitializerInterfaceType(); + if (superInitType->is() || + classDecl->getGenericParamsOfContext()) { + // FIXME: Handle generic initializers as well. + return nullptr; + } + + auto &ctx = TC.Context; + + // Create the 'self' declaration and patterns. + auto *selfDecl = new (ctx) VarDecl(/*static*/ false, /*IsLet*/ true, + SourceLoc(), ctx.Id_self, + Type(), classDecl); + selfDecl->setImplicit(); + Pattern *selfArgPattern + = new (ctx) NamedPattern(selfDecl, /*Implicit=*/true); + selfArgPattern = new (ctx) TypedPattern(selfArgPattern, TypeLoc()); + Pattern *selfBodyPattern + = new (ctx) NamedPattern(selfDecl, /*Implicit=*/true); + selfBodyPattern = new (ctx) TypedPattern(selfBodyPattern, TypeLoc()); + + // Create the initializer parameter patterns. + Pattern *argParamPatterns + = superclassCtor->getArgParamPatterns()[1]->clone(ctx,/*Implicit=*/true); + Pattern *bodyParamPatterns + = superclassCtor->getBodyParamPatterns()[1]->clone(ctx,/*Implicit=*/true); + + // Create the initializer declaration. + auto ctor = new (ctx) ConstructorDecl(ctx.Id_init, SourceLoc(), + selfArgPattern, argParamPatterns, + selfBodyPattern, bodyParamPatterns, + nullptr, classDecl); + ctor->setImplicit(); + if (superclassCtor->hasSelectorStyleSignature()) + ctor->setHasSelectorStyleSignature(); + + // Configure 'self'. + GenericParamList *outerGenericParams = nullptr; + Type selfType = configureImplicitSelf(ctor, outerGenericParams); + selfArgPattern->setType(selfType); + selfBodyPattern->setType(selfType); + cast(selfArgPattern)->getSubPattern()->setType(selfType); + cast(selfBodyPattern)->getSubPattern()->setType(selfType); + + // Set the type of the initializer. + configureConstructorType(ctor, outerGenericParams, selfType, + argParamPatterns->getType()); + if (superclassCtor->isObjC()) + ctor->setIsObjC(true); + checkOverrides(ctor); + + // Mark this as a stub implementation. + ctor->setStubImplementation(true); + + return ctor; + } + void visitClassDecl(ClassDecl *CD) { if (!IsSecondPass) { TC.validateDecl(CD); @@ -2025,10 +2097,10 @@ public: TC.addImplicitConstructors(CD); TC.addImplicitDestructor(CD); - // Check whether the superclass has any abstract initializers and whether - // they have been implemented. + // Check for inconsistencies between the initializers of our + // superclass and our own initializers. if (auto superclassTy = CD->getSuperclass()) { - // Collect the set of constructors we override in the base class. + // Collect the set of initializers we override in superclass. llvm::SmallPtrSet overriddenCtors; for (auto member : TC.lookupConstructors(CD->getDeclaredTypeInContext(), CD)) { @@ -2037,13 +2109,19 @@ public: overriddenCtors.insert(overridden); } - // Diagnose any abstract constructors from our superclass that have - // not been overridden or inherited. + // Look for any required constructors or subobject initializers in the + // subclass that have not been overridden or otherwise provided. bool diagnosed = false; + llvm::SmallVector synthesizedCtors; for (auto superclassMember : TC.lookupConstructors(superclassTy, CD)) { - // We only care about abstract constructors. + // We only care about required or subobject initializers. auto superclassCtor = cast(superclassMember); - if (!superclassCtor->isRequired()) + if (!superclassCtor->isRequired() && + !superclassCtor->isSubobjectInit()) + continue; + + // Skip invalid superclass initializers. + if (superclassCtor->isInvalid()) continue; // If we have an override for this constructor, it's okay. @@ -2053,20 +2131,53 @@ public: // If the superclass constructor is a complete object initializer // that is inherited into the current class, it's okay. if (superclassCtor->isCompleteObjectInit() && - CD->inheritsSuperclassInitializers(&TC)) + CD->inheritsSuperclassInitializers(&TC)) { + assert(superclassCtor->isRequired()); continue; - - // Complain that we don't have an overriding constructor. - if (!diagnosed) { - TC.diagnose(CD, diag::abstract_incomplete_implementation, - CD->getDeclaredInterfaceType()); - diagnosed = true; } - // FIXME: Using the type here is awful. We want to use the selector - // name and provide a nice Fix-It with that declaration. - TC.diagnose(superclassCtor, diag::abstract_initializer_not_overridden, - superclassCtor->getArgumentType()); + // Diagnose a missing override of a required initializer. + if (superclassCtor->isRequired()) { + // Complain that we don't have an overriding constructor. + if (!diagnosed) { + TC.diagnose(CD, diag::abstract_incomplete_implementation, + CD->getDeclaredInterfaceType()); + diagnosed = true; + } + + // FIXME: Using the type here is awful. We want to use the selector + // name and provide a nice Fix-It with that declaration. + TC.diagnose(superclassCtor, + diag::abstract_initializer_not_overridden, + superclassCtor->getArgumentType()); + continue; + } + + // A subobject initializer has not been overridden. + + // Skip this subobject initializer if it's in an extension. + // FIXME: We shouldn't allow this. + if (isa(superclassCtor->getDeclContext())) + continue; + + // Create an override for it. + if (auto ctor = createSubobjectInitOverride(CD, superclassCtor)) { + assert(ctor->getOverriddenDecl() == superclassCtor && + "Not an override?"); + synthesizedCtors.push_back(ctor); + } + } + + // If we synthesized any initializers, add them. + if (!synthesizedCtors.empty()) { + auto members = CD->getMembers(); + unsigned numMembers = members.size(); + MutableArrayRef newMembers + = TC.Context.Allocate(numMembers + synthesizedCtors.size()); + std::copy(members.begin(), members.end(), newMembers.begin()); + std::copy(synthesizedCtors.begin(), synthesizedCtors.end(), + newMembers.begin() + numMembers); + CD->setMembers(newMembers, CD->getBraces()); } } } @@ -2633,6 +2744,8 @@ public: return type; }); } + } else if (isa(decl)) { + type = type->replaceResultType(subclass, /*uncurryLevel=*/2); } return type; @@ -2796,7 +2909,7 @@ public: // Check whether the types are identical. // FIXME: It's wrong to use the uncurried types here for methods. - auto parentDeclTy = adjustSuperclassMemberDeclType(parentDecl,superclass); + auto parentDeclTy = adjustSuperclassMemberDeclType(parentDecl,owningTy); auto uncurriedParentDeclTy = parentDeclTy; if (method) { uncurriedParentDeclTy = parentDeclTy->castTo() @@ -3171,6 +3284,37 @@ public: // their enclosing declaration. } + /// Compute the allocating and initializing constructor types for + /// the given constructor. + void configureConstructorType(ConstructorDecl *ctor, + GenericParamList *outerGenericParams, + Type selfType, + Type argType) { + Type fnType; + Type allocFnType; + Type initFnType; + Type resultType = selfType->getInOutObjectType(); + + if (GenericParamList *innerGenericParams = ctor->getGenericParams()) { + innerGenericParams->setOuterParameters(outerGenericParams); + fnType = PolymorphicFunctionType::get(argType, resultType, + innerGenericParams); + } else + fnType = FunctionType::get(argType, resultType); + Type selfMetaType = MetatypeType::get(resultType, TC.Context); + if (outerGenericParams) { + allocFnType = PolymorphicFunctionType::get(selfMetaType, fnType, + outerGenericParams); + initFnType = PolymorphicFunctionType::get(selfType, fnType, + outerGenericParams); + } else { + allocFnType = FunctionType::get(selfMetaType, fnType); + initFnType = FunctionType::get(selfType, fnType); + } + ctor->setType(allocFnType); + ctor->setInitializerType(initFnType); + } + void visitConstructorDecl(ConstructorDecl *CD) { if (CD->isInvalid()) { CD->overwriteType(ErrorType::get(TC.Context)); @@ -3260,30 +3404,8 @@ public: CD->overwriteType(ErrorType::get(TC.Context)); CD->setInvalid(); } else { - Type FnTy; - Type AllocFnTy; - Type InitFnTy; - Type ArgType = CD->getArgParamPatterns()[1]->getType(); - Type ResultTy = SelfTy->getInOutObjectType(); - - if (GenericParamList *innerGenericParams = CD->getGenericParams()) { - innerGenericParams->setOuterParameters(outerGenericParams); - FnTy = PolymorphicFunctionType::get(ArgType, ResultTy, - innerGenericParams); - } else - FnTy = FunctionType::get(ArgType, ResultTy); - Type SelfMetaTy = MetatypeType::get(ResultTy, TC.Context); - if (outerGenericParams) { - AllocFnTy = PolymorphicFunctionType::get(SelfMetaTy, FnTy, - outerGenericParams); - InitFnTy = PolymorphicFunctionType::get(SelfTy, FnTy, - outerGenericParams); - } else { - AllocFnTy = FunctionType::get(SelfMetaTy, FnTy); - InitFnTy = FunctionType::get(SelfTy, FnTy); - } - CD->setType(AllocFnTy); - CD->setInitializerType(InitFnTy); + configureConstructorType(CD, outerGenericParams, SelfTy, + CD->getArgParamPatterns()[1]->getType()); } validateAttributes(TC, CD); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 319406fc323..a6763babc35 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -873,6 +873,12 @@ static bool shouldSerializeMember(Decl *D) { case DeclKind::EnumCase: return false; + case DeclKind::Constructor: { + // Never serialize a constructor with a stub implementation. + auto ctor = cast(D); + return !ctor->hasStubImplementation(); + } + case DeclKind::EnumElement: case DeclKind::Protocol: case DeclKind::Destructor: @@ -886,7 +892,6 @@ static bool shouldSerializeMember(Decl *D) { case DeclKind::Class: case DeclKind::Var: case DeclKind::Func: - case DeclKind::Constructor: return true; } } diff --git a/test/IRGen/objc_dealloc.sil b/test/IRGen/objc_dealloc.sil index 33f0111ad00..3a1c2ef2b69 100644 --- a/test/IRGen/objc_dealloc.sil +++ b/test/IRGen/objc_dealloc.sil @@ -17,6 +17,7 @@ func onDestruct() { } class SwiftGizmo : Gizmo { var x : X + init() deinit } sil @_TFCSo10SwiftGizmoD : $@cc(method) @thin (SwiftGizmo) -> () @@ -89,7 +90,7 @@ bb0(%0 : $SwiftGizmo): // CHECK-NEXT: [[OBJC_SUPER_RECEIVER:%[a-zA-Z0-9]+]] = getelementptr %objc_super* [[OBJC_SUPER]], i32 0, i32 0 // CHECK-NEXT: store %objc_object* [[SUPER_OBJ]], %objc_object** [[OBJC_SUPER_RECEIVER]], align 8 // CHECK-NEXT: [[OBJC_SUPER_CLASS:%[a-zA-Z0-9]+]] = getelementptr %objc_super* [[OBJC_SUPER]], i32 0, i32 1 - // CHECK-NEXT: store %objc_class* bitcast (%swift.type* getelementptr inbounds (%swift.full_heapmetadata* bitcast ({ void ([[SGIZMO]]*)*, i8**, i64, %objc_class*, %swift.opaque*, %swift.opaque*, i64, { i64, i8*, i64, i64, i8*, i64, i64 }*, i64, i64 }* @_TMdCSo10SwiftGizmo to %swift.full_heapmetadata*), i32 0, i32 2) to %objc_class*), %objc_class** [[OBJC_SUPER_CLASS]], align 8 + // CHECK-NEXT: store %objc_class* bitcast (%swift.type* getelementptr inbounds (%swift.full_heapmetadata* bitcast ({{.*}}* @_TMdCSo10SwiftGizmo to %swift.full_heapmetadata*), i32 0, i32 2) to %objc_class*), %objc_class** [[OBJC_SUPER_CLASS]], align 8 // CHECK-NEXT: [[DEALLOC_SEL:%[a-zA-Z0-9]+]] = load i8** @"\01L_selector(dealloc)", align 8 // CHECK-NEXT: call void bitcast (void ()* @objc_msgSendSuper2 to void (%objc_super*, i8*)*)(%objc_super* [[OBJC_SUPER]], i8* [[DEALLOC_SEL]]) %5 = super_method %0 : $SwiftGizmo, #Gizmo.deinit!deallocator.foreign : $@cc(objc_method) @thin (Gizmo) -> () // user: %7 @@ -107,3 +108,13 @@ bb0(%0 : $SwiftGizmo): %3 = tuple () return %3 : $() // id: %4 } + +sil @_TToFCSo10SwiftGizmocfMS_FT_S_ : $@cc(objc_method) @thin (@owned SwiftGizmo) -> @owned SwiftGizmo { +bb0(%0 : $SwiftGizmo): + return %0 : $SwiftGizmo +} + +sil @_TToFCSo10SwiftGizmocfMS_FT11withBellsOnSi_S_ : $@cc(objc_method) @thin (Int, @owned SwiftGizmo) -> @owned SwiftGizmo { +bb0(%0 : $Int, %1 : $SwiftGizmo): + return %1 : $SwiftGizmo +} diff --git a/test/SILGen/Inputs/usr/include/Gizmo.h b/test/SILGen/Inputs/usr/include/Gizmo.h index 889db4abba6..99d1df71dfb 100644 --- a/test/SILGen/Inputs/usr/include/Gizmo.h +++ b/test/SILGen/Inputs/usr/include/Gizmo.h @@ -14,6 +14,7 @@ #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) #define NS_CONSUMED __attribute__((ns_consumed)) +#define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) struct Rect { float x; @@ -38,7 +39,9 @@ typedef long NSInteger; @interface Gizmo : NSObject - (Gizmo*) clone NS_RETURNS_RETAINED; - (Gizmo*) duplicate; -- (Gizmo*) initWithBellsOn:(NSInteger)x; +- (Gizmo*) init OBJC_DESIGNATED_INITIALIZER; +- (Gizmo*) initWithBellsOn:(NSInteger)x OBJC_DESIGNATED_INITIALIZER; +- (instancetype) initWithoutBells:(NSInteger)x; - (void) fork NS_CONSUMES_SELF; - (void) enumerateSubGizmos: (void (^)(Gizmo*))f; + (void) consume: (NS_CONSUMED Gizmo*) gizmo;