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/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/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/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/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"); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5b3b7bc661246..c5832bf29cbb1 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. @@ -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/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 61d3d4bfd56f9..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,13 +2418,64 @@ NamingPatternRequest::evaluate(Evaluator &evaluator, VarDecl *VD) const { return namingPattern; } -DeclRange +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 { - 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. @@ -2451,16 +2503,40 @@ 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. 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); } - return CD->getMembers(); + return Context.AllocateCopy(result); } bool TypeChecker::isPassThroughTypealias(TypeAliasDecl *typealias, 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{{.*}} 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