From ff2cc3556a09148cc5806b52bcd5a5326573d4a3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 26 Jun 2020 23:04:26 -0400 Subject: [PATCH 1/6] ASTMangler: Tiny cleanup --- include/swift/AST/ASTMangler.h | 7 ++++--- lib/AST/ASTMangler.cpp | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index f6605561b4adb..d806bcc3fda0c 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -101,7 +101,8 @@ class ASTMangler : public Mangler { SymbolKind SKind = SymbolKind::Default); std::string mangleDestructorEntity(const DestructorDecl *decl, - bool isDeallocating, SymbolKind SKind); + bool isDeallocating, + SymbolKind SKind = SymbolKind::Default); std::string mangleConstructorEntity(const ConstructorDecl *ctor, bool isAllocating, @@ -120,11 +121,11 @@ class ASTMangler : public Mangler { std::string mangleDefaultArgumentEntity(const DeclContext *func, unsigned index, - SymbolKind SKind); + SymbolKind SKind = SymbolKind::Default); std::string mangleInitializerEntity(const VarDecl *var, SymbolKind SKind); std::string mangleBackingInitializerEntity(const VarDecl *var, - SymbolKind SKind); + SymbolKind SKind = SymbolKind::Default); std::string mangleNominalType(const NominalTypeDecl *decl); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 6a53a27c9f8ac..0b416b6a745e5 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -2741,7 +2741,7 @@ void ASTMangler::appendConstructorEntity(const ConstructorDecl *ctor, } void ASTMangler::appendDestructorEntity(const DestructorDecl *dtor, - bool isDeallocating) { + bool isDeallocating) { appendContextOf(dtor); appendOperator(isDeallocating ? "fD" : "fd"); } From 31a78590a8bff31b5ab95e067fac2573b8dd38b0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 29 Jun 2020 18:17:19 -0400 Subject: [PATCH 2/6] ASTMangler: Fix assertion when mangling invalid identifiers We sometimes need to mangle invalid identifiers, for example when sorting declarations in EmittedMembersRequest. Make sure this doesn't assert. --- include/swift/Demangling/ManglingUtils.h | 12 +++++++++--- ...first-char-of-sub-string-may-not-be-a-digit.swift | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) rename validation-test/{compiler_crashers => compiler_crashers_fixed}/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift (83%) diff --git a/include/swift/Demangling/ManglingUtils.h b/include/swift/Demangling/ManglingUtils.h index a5315e4028beb..e15872004ddab 100644 --- a/include/swift/Demangling/ManglingUtils.h +++ b/include/swift/Demangling/ManglingUtils.h @@ -192,9 +192,8 @@ void mangleIdentifier(Mangler &M, StringRef ident) { // Mangle the sub-string up to the next word substitution (or to the end // of the identifier - that's why we added the dummy-word). // The first thing: we add the encoded sub-string length. + bool first = true; M.Buffer << (Repl.StringPos - Pos); - assert(!isDigit(ident[Pos]) && - "first char of sub-string may not be a digit"); do { // Update the start position of new added words, so that they refer to // the begin of the whole mangled Buffer. @@ -203,9 +202,16 @@ void mangleIdentifier(Mangler &M, StringRef ident) { M.Words[WordsInBuffer].start = M.getBufferStr().size(); WordsInBuffer++; } + // Error recovery. We sometimes need to mangle identifiers coming + // from invalid code. + if (first && isDigit(ident[Pos])) + M.Buffer << 'X'; // Add a literal character of the sub-string. - M.Buffer << ident[Pos]; + else + M.Buffer << ident[Pos]; + Pos++; + first = false; } while (Pos < Repl.StringPos); } // Is it a "real" word substitution (and not the dummy-word)? diff --git a/validation-test/compiler_crashers/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift b/validation-test/compiler_crashers_fixed/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift similarity index 83% rename from validation-test/compiler_crashers/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift rename to validation-test/compiler_crashers_fixed/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift index bce90c51bd538..fd641ca3dfa49 100644 --- a/validation-test/compiler_crashers/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift +++ b/validation-test/compiler_crashers_fixed/28809-isdigit-ident-pos-first-char-of-sub-string-may-not-be-a-digit.swift @@ -5,6 +5,6 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// REQUIRES: asserts -// RUN: not --crash %target-swift-frontend %s -emit-ir + +// RUN: not %target-swift-frontend %s -emit-ir protocol 0{class TextOutputStream From f8720d55dd3a1483d51252d79fb683b968415387 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 25 Jun 2020 16:43:41 -0400 Subject: [PATCH 3/6] Sema: Force synthesized conformance to Differentiable in EmittedMembersRequest --- lib/Sema/TypeCheckDecl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 61d3d4bfd56f9..0f129f3ae20b9 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2451,6 +2451,7 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, forceConformance(Context.getProtocol(KnownProtocolKind::Decodable)); forceConformance(Context.getProtocol(KnownProtocolKind::Encodable)); forceConformance(Context.getProtocol(KnownProtocolKind::Hashable)); + forceConformance(Context.getProtocol(KnownProtocolKind::Differentiable)); // The projected storage wrapper ($foo) might have dynamically-dispatched // accessors, so force them to be synthesized. From c1b0c931886f875e176cde737084750aa2fa30df Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 25 Jun 2020 15:59:51 -0400 Subject: [PATCH 4/6] Sema: Use request evaluator caching for EmittedMembersRequest --- include/swift/AST/Decl.h | 15 ++------------- include/swift/AST/TypeCheckRequests.h | 9 +++------ include/swift/AST/TypeCheckerTypeIDZone.def | 4 ++-- lib/AST/Decl.cpp | 4 ++-- lib/AST/TypeCheckRequests.cpp | 17 ----------------- lib/Sema/TypeCheckDecl.cpp | 16 +++++++++++----- 6 files changed, 20 insertions(+), 45 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7e05f887dc565..8848b5c2360a1 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -535,7 +535,7 @@ class alignas(1 << DeclAlignInBits) Decl { NumRequirementsInSignature : 16 ); - SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1, + SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1, /// Whether this class inherits its superclass's convenience initializers. InheritsSuperclassInits : 1, ComputedInheritsSuperclassInits : 1, @@ -543,9 +543,6 @@ class alignas(1 << DeclAlignInBits) Decl { /// \see ClassDecl::ForeignKind RawForeignKind : 2, - /// \see ClassDecl::getEmittedMembers() - HasForcedEmittedMembers : 1, - HasMissingDesignatedInitializers : 1, ComputedHasMissingDesignatedInitializers : 1, @@ -3856,14 +3853,6 @@ class ClassDecl final : public NominalTypeDecl { llvm::PointerIntPair SuperclassType; } LazySemanticInfo; - bool hasForcedEmittedMembers() const { - return Bits.ClassDecl.HasForcedEmittedMembers; - } - - void setHasForcedEmittedMembers() { - Bits.ClassDecl.HasForcedEmittedMembers = true; - } - Optional getCachedInheritsSuperclassInitializers() const { if (Bits.ClassDecl.ComputedInheritsSuperclassInits) return Bits.ClassDecl.InheritsSuperclassInits; @@ -4089,7 +4078,7 @@ class ClassDecl final : public NominalTypeDecl { /// Get all the members of this class, synthesizing any implicit members /// that appear in the vtable if needed. - DeclRange getEmittedMembers() const; + ArrayRef getEmittedMembers() const; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index bed14bfd6c62a..04fe9c2bc2183 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1064,8 +1064,8 @@ class SynthesizeAccessorRequest : class EmittedMembersRequest : public SimpleRequest { + ArrayRef(ClassDecl *), + RequestFlags::Cached> { public: using SimpleRequest::SimpleRequest; @@ -1073,14 +1073,11 @@ class EmittedMembersRequest : friend SimpleRequest; // Evaluation. - DeclRange + ArrayRef evaluate(Evaluator &evaluator, ClassDecl *classDecl) const; public: - // Separate caching. bool isCached() const { return true; } - Optional getCachedResult() const; - void cacheResult(DeclRange value) const; }; class IsImplicitlyUnwrappedOptionalRequest : diff --git a/include/swift/AST/TypeCheckerTypeIDZone.def b/include/swift/AST/TypeCheckerTypeIDZone.def index 78f85350138e8..c77b86bde2ed1 100644 --- a/include/swift/AST/TypeCheckerTypeIDZone.def +++ b/include/swift/AST/TypeCheckerTypeIDZone.def @@ -65,8 +65,8 @@ SWIFT_REQUEST(TypeChecker, TypeEraserHasViableInitRequest, SWIFT_REQUEST(TypeChecker, DynamicallyReplacedDeclRequest, ValueDecl *(ValueDecl *), Cached, NoLocationInfo) -SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *), - SeparatelyCached, NoLocationInfo) +SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, ArrayRef(ClassDecl *), + Cached, NoLocationInfo) SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest, evaluator::SideEffect (EnumDecl *, TypeResolutionStage), SeparatelyCached, NoLocationInfo) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5b3b7bc661246..010352be59a73 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4285,11 +4285,11 @@ DestructorDecl *ClassDecl::getDestructor() const { nullptr); } -DeclRange ClassDecl::getEmittedMembers() const { +ArrayRef ClassDecl::getEmittedMembers() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, EmittedMembersRequest{const_cast(this)}, - getMembers()); + ArrayRef()); } /// Synthesizer callback for an empty implicit function body. diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 41276bd6d1956..12887f1be18e7 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -783,23 +783,6 @@ void SynthesizeAccessorRequest::cacheResult(AccessorDecl *accessor) const { storage->setSynthesizedAccessor(kind, accessor); } -//----------------------------------------------------------------------------// -// EmittedMembersRequest computation. -//----------------------------------------------------------------------------// - -Optional -EmittedMembersRequest::getCachedResult() const { - auto *classDecl = std::get<0>(getStorage()); - if (classDecl->hasForcedEmittedMembers()) - return classDecl->getMembers(); - return None; -} - -void EmittedMembersRequest::cacheResult(DeclRange result) const { - auto *classDecl = std::get<0>(getStorage()); - classDecl->setHasForcedEmittedMembers(); -} - //----------------------------------------------------------------------------// // IsImplicitlyUnwrappedOptionalRequest computation. //----------------------------------------------------------------------------// diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 0f129f3ae20b9..05a17a4028ae8 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2417,13 +2417,17 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { return namingPattern; } -DeclRange +ArrayRef EmittedMembersRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { - if (!CD->getParentSourceFile()) - return CD->getMembers(); - auto &Context = CD->getASTContext(); + SmallVector result; + + if (!CD->getParentSourceFile()) { + auto members = CD->getMembers(); + result.append(members.begin(), members.end()); + return Context.AllocateCopy(result); + } // We need to add implicit initializers because they // affect vtable layout. @@ -2461,7 +2465,9 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, (void) var->getPropertyWrapperBackingProperty(); } - return CD->getMembers(); + auto members = CD->getMembers(); + result.append(members.begin(), members.end()); + return Context.AllocateCopy(result); } bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, From 055b3a8e2ec092ea9179cd725e82fb79389ece08 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 26 Jun 2020 22:52:41 -0400 Subject: [PATCH 5/6] Sema: Deterministically order declarations in EmittedMemberRequest Previously we did this in the SILVTableVisitor, since maintaining a consistent order between translation units is important for correctness. However, we also want the order in which the members themselves are emitted to remain consistent regardless of the order in which members were synthesized. This is in service of reproducible builds. --- include/swift/SIL/SILVTableVisitor.h | 71 +------------------------ lib/Sema/TypeCheckDecl.cpp | 79 ++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/include/swift/SIL/SILVTableVisitor.h b/include/swift/SIL/SILVTableVisitor.h index b9be52452b402..de8419b238601 100644 --- a/include/swift/SIL/SILVTableVisitor.h +++ b/include/swift/SIL/SILVTableVisitor.h @@ -18,55 +18,11 @@ #ifndef SWIFT_SIL_SILVTABLEVISITOR_H #define SWIFT_SIL_SILVTABLEVISITOR_H -#include - #include "swift/AST/Decl.h" #include "swift/AST/Types.h" -#include "swift/AST/ASTMangler.h" namespace swift { -// Utility class for deterministically ordering vtable entries for -// synthesized methods. -struct SortedFuncList { - using Entry = std::pair; - SmallVector elts; - bool sorted = false; - - void add(AbstractFunctionDecl *afd) { - Mangle::ASTMangler mangler; - std::string mangledName; - if (auto *cd = dyn_cast(afd)) - mangledName = mangler.mangleConstructorEntity(cd, 0); - else - mangledName = mangler.mangleEntity(afd); - - elts.push_back(std::make_pair(mangledName, afd)); - } - - bool empty() { return elts.empty(); } - - void sort() { - assert(!sorted); - sorted = true; - std::sort(elts.begin(), - elts.end(), - [](const Entry &lhs, const Entry &rhs) -> bool { - return lhs.first < rhs.first; - }); - } - - decltype(elts)::const_iterator begin() const { - assert(sorted); - return elts.begin(); - } - - decltype(elts)::const_iterator end() const { - assert(sorted); - return elts.end(); - } -}; - /// A CRTP class for visiting virtually-dispatched methods of a class. /// /// You must override these two methods in your subclass: @@ -192,33 +148,8 @@ template class SILVTableVisitor { if (!theClass->hasKnownSwiftImplementation()) return; - // Note that while vtable order is not ABI, we still want it to be - // consistent between translation units. - // - // So, sort synthesized members by their mangled name, since they - // are added lazily during type checking, with the remaining ones - // forced at the end. - SortedFuncList synthesizedMembers; - - for (auto member : theClass->getEmittedMembers()) { - if (auto *afd = dyn_cast(member)) { - if (afd->isSynthesized()) { - synthesizedMembers.add(afd); - continue; - } - } - + for (auto member : theClass->getEmittedMembers()) maybeAddMember(member); - } - - if (synthesizedMembers.empty()) - return; - - synthesizedMembers.sort(); - - for (const auto &pair : synthesizedMembers) { - maybeAddMember(pair.second); - } } }; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 05a17a4028ae8..145de572b43c3 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -25,6 +25,7 @@ #include "TypeCheckType.h" #include "MiscDiagnostics.h" #include "swift/AST/AccessScope.h" +#include "swift/AST/ASTMangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" @@ -2417,6 +2418,53 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { return namingPattern; } +namespace { + +// Utility class for deterministically ordering vtable entries for +// synthesized methods. +struct SortedFuncList { + using Entry = std::pair; + SmallVector elts; + bool sorted = false; + + void add(AbstractFunctionDecl *afd) { + Mangle::ASTMangler mangler; + std::string mangledName; + if (auto *cd = dyn_cast(afd)) + mangledName = mangler.mangleConstructorEntity(cd, /*allocator=*/false); + else if (auto *dd = dyn_cast(afd)) + mangledName = mangler.mangleDestructorEntity(dd, /*deallocating=*/false); + else + mangledName = mangler.mangleEntity(afd); + + elts.push_back(std::make_pair(mangledName, afd)); + } + + bool empty() { return elts.empty(); } + + void sort() { + assert(!sorted); + sorted = true; + std::sort(elts.begin(), + elts.end(), + [](const Entry &lhs, const Entry &rhs) -> bool { + return lhs.first < rhs.first; + }); + } + + decltype(elts)::const_iterator begin() const { + assert(sorted); + return elts.begin(); + } + + decltype(elts)::const_iterator end() const { + assert(sorted); + return elts.end(); + } +}; + +} // end namespace + ArrayRef EmittedMembersRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { @@ -2457,16 +2505,37 @@ EmittedMembersRequest::evaluate(Evaluator &evaluator, forceConformance(Context.getProtocol(KnownProtocolKind::Hashable)); forceConformance(Context.getProtocol(KnownProtocolKind::Differentiable)); - // The projected storage wrapper ($foo) might have dynamically-dispatched - // accessors, so force them to be synthesized. for (auto *member : CD->getMembers()) { - if (auto *var = dyn_cast(member)) + if (auto *var = dyn_cast(member)) { + // The projected storage wrapper ($foo) might have dynamically-dispatched + // accessors, so force them to be synthesized. if (var->hasAttachedPropertyWrapper()) (void) var->getPropertyWrapperBackingProperty(); + } + } + + SortedFuncList synthesizedMembers; + + for (auto *member : CD->getMembers()) { + if (auto *afd = dyn_cast(member)) { + // Add synthesized members to a side table and sort them by their mangled + // name, since they could have been added to the class in any order. + if (afd->isSynthesized()) { + synthesizedMembers.add(afd); + continue; + } + } + + result.push_back(member); + } + + if (!synthesizedMembers.empty()) { + synthesizedMembers.sort(); + + for (const auto &pair : synthesizedMembers) + result.push_back(pair.second); } - auto members = CD->getMembers(); - result.append(members.begin(), members.end()); return Context.AllocateCopy(result); } From 89b2f27b4dc1fd4c574a318ead24e2f4d3a2725c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 26 Jun 2020 23:08:40 -0400 Subject: [PATCH 6/6] AST: Mark implicit destructor as synthesized to fix non-deterministic function order We can synthesize the default init() and the implicit deinit in a class in any order, depending on the order of primary files and how that class was used in other primary files. Make sure that EmittedMembersRequest puts the destructor at the end with all other synthesized members, so that we produce the same object file in any case. --- lib/AST/Decl.cpp | 4 ++++ .../Inputs/deterministic-dtor-ordering-other.swift | 3 +++ test/SILGen/deterministic-dtor-ordering.swift | 10 ++++++++++ test/SILGen/objc_thunks.swift | 6 +++--- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 test/SILGen/Inputs/deterministic-dtor-ordering-other.swift create mode 100644 test/SILGen/deterministic-dtor-ordering.swift diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 010352be59a73..c5832bf29cbb1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -4318,6 +4318,10 @@ GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { if (ctx.LangOpts.EnableObjCInterop) CD->recordObjCMethod(DD, DD->getObjCSelector()); + // Mark it as synthesized to make its location in getEmittedMembers() + // deterministic. + DD->setSynthesized(true); + return DD; } diff --git a/test/SILGen/Inputs/deterministic-dtor-ordering-other.swift b/test/SILGen/Inputs/deterministic-dtor-ordering-other.swift new file mode 100644 index 0000000000000..e1627702f0233 --- /dev/null +++ b/test/SILGen/Inputs/deterministic-dtor-ordering-other.swift @@ -0,0 +1,3 @@ +public func makeAHorse() -> Horse { + return Horse() +} diff --git a/test/SILGen/deterministic-dtor-ordering.swift b/test/SILGen/deterministic-dtor-ordering.swift new file mode 100644 index 0000000000000..06b7c9275e0eb --- /dev/null +++ b/test/SILGen/deterministic-dtor-ordering.swift @@ -0,0 +1,10 @@ +// RUN: %target-swift-emit-silgen -module-name horse -primary-file %S/Inputs/deterministic-dtor-ordering-other.swift -primary-file %s -module-name horse | %FileCheck %s +// RUN: %target-swift-emit-silgen -module-name horse %S/Inputs/deterministic-dtor-ordering-other.swift -primary-file %s -module-name horse | %FileCheck %s + +public class Horse {} + +// CHECK-LABEL: sil hidden [exact_self_class] [ossa] @$s5horse5HorseCACycfC : $@convention(method) (@thick Horse.Type) -> @owned Horse { +// CHECK-LABEL: sil hidden [ossa] @$s5horse5HorseCACycfc : $@convention(method) (@owned Horse) -> @owned Horse { +// CHECK-LABEL: sil [ossa] @$s5horse5HorseCfd : $@convention(method) (@guaranteed Horse) -> @owned Builtin.NativeObject { +// CHECK-LABEL: sil [ossa] @$s5horse5HorseCfD : $@convention(method) (@owned Horse) -> () { + diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift index 76a3a48e3e64c..668ca2048fab4 100644 --- a/test/SILGen/objc_thunks.swift +++ b/test/SILGen/objc_thunks.swift @@ -454,13 +454,13 @@ class Wotsit : Gizmo { return "Hello, world." } - // Ivar destroyer - // CHECK-LABEL: sil hidden [ossa] @$s11objc_thunks6WotsitCfETo - // CHECK-LABEL: sil hidden [thunk] [ossa] @$s11objc_thunks6WotsitCACyxGSgycfcTo : $@convention(objc_method) (@owned Wotsit) -> @owned Optional> // CHECK-LABEL: sil hidden [thunk] [ossa] @$s11objc_thunks6WotsitC7bellsOnACyxGSgSi_tcfcTo : $@convention(objc_method) (Int, @owned Wotsit) -> @owned Optional> + // Ivar destroyer + // CHECK-LABEL: sil hidden [ossa] @$s11objc_thunks6WotsitCfETo + } // CHECK-NOT: sil hidden [thunk] [ossa] @_TToF{{.*}}Wotsit{{.*}}