Merge pull request #23590 from compnerd/more-tests-more-better
test: loosen restrictions on DebugInfo test
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 979c323..ec64599 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -112,6 +112,8 @@
global ::= nominal-type 'Mn' // nominal type descriptor
global ::= nominal-type 'Mu' // class method lookup function
global ::= nominal-type 'MU' // ObjC metadata update callback function
+ global ::= nominal-type 'Ms' // ObjC resilient class stub
+ global ::= nominal-type 'Mt' // Full ObjC resilient class stub (private)
global ::= module 'MXM' // module descriptor
global ::= context 'MXE' // extension descriptor
global ::= context 'MXX' // anonymous context descriptor
diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h
index a3976ea..d06f7c7 100644
--- a/include/swift/ABI/Metadata.h
+++ b/include/swift/ABI/Metadata.h
@@ -3683,6 +3683,28 @@
TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> Superclass;
};
+/// A structure that stores a reference to an Objective-C class stub.
+///
+/// This is not the class stub itself; it is part of a class context
+/// descriptor.
+template <typename Runtime>
+struct TargetObjCResilientClassStubInfo {
+ /// A relative pointer to an Objective-C resilient class stub.
+ ///
+ /// We do not declare a struct type for class stubs since the Swift runtime
+ /// does not need to interpret them. The class stub struct is part of
+ /// the Objective-C ABI, and is laid out as follows:
+ /// - isa pointer, always 1
+ /// - an update callback, of type 'Class (*)(Class *, objc_class_stub *)'
+ ///
+ /// Class stubs are used for two purposes:
+ ///
+ /// - Objective-C can reference class stubs when calling static methods.
+ /// - Objective-C and Swift can reference class stubs when emitting
+ /// categories (in Swift, extensions with @objc members).
+ TargetRelativeDirectPointer<Runtime, const void> Stub;
+};
+
template <typename Runtime>
class TargetClassDescriptor final
: public TargetTypeContextDescriptor<Runtime>,
@@ -3695,7 +3717,8 @@
TargetVTableDescriptorHeader<Runtime>,
TargetMethodDescriptor<Runtime>,
TargetOverrideTableHeader<Runtime>,
- TargetMethodOverrideDescriptor<Runtime>> {
+ TargetMethodOverrideDescriptor<Runtime>,
+ TargetObjCResilientClassStubInfo<Runtime>> {
private:
using TrailingGenericContextObjects =
TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
@@ -3706,7 +3729,8 @@
TargetVTableDescriptorHeader<Runtime>,
TargetMethodDescriptor<Runtime>,
TargetOverrideTableHeader<Runtime>,
- TargetMethodOverrideDescriptor<Runtime>>;
+ TargetMethodOverrideDescriptor<Runtime>,
+ TargetObjCResilientClassStubInfo<Runtime>>;
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
@@ -3722,6 +3746,8 @@
TargetForeignMetadataInitialization<Runtime>;
using SingletonMetadataInitialization =
TargetSingletonMetadataInitialization<Runtime>;
+ using ObjCResilientClassStubInfo =
+ TargetObjCResilientClassStubInfo<Runtime>;
using StoredPointer = typename Runtime::StoredPointer;
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
@@ -3759,7 +3785,9 @@
/// positive size of metadata objects of this class (in words).
uint32_t MetadataPositiveSizeInWords;
- // Maybe add something here that's useful only for resilient types?
+ /// Otherwise, these flags are used to do things like indicating
+ /// the presence of an Objective-C resilient class stub.
+ ExtraClassDescriptorFlags ExtraClassFlags;
};
/// The number of additional members added by this class to the class
@@ -3835,6 +3863,10 @@
return getOverrideTable()->NumEntries;
}
+ size_t numTrailingObjects(OverloadToken<ObjCResilientClassStubInfo>) const {
+ return hasObjCResilientClassStub() ? 1 : 0;
+ }
+
public:
const TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> &
getResilientSuperclass() const {
@@ -3954,7 +3986,24 @@
&& i < numTrailingObjects(OverloadToken<MethodDescriptor>{}));
return getMethodDescriptors()[i].Impl.get();
}
-
+
+ /// Whether this context descriptor references an Objective-C resilient
+ /// class stub. See the above description of TargetObjCResilientClassStubInfo
+ /// for details.
+ bool hasObjCResilientClassStub() const {
+ if (!hasResilientSuperclass())
+ return false;
+ return ExtraClassFlags.hasObjCResilientClassStub();
+ }
+
+ const void *getObjCResilientClassStub() const {
+ if (!hasObjCResilientClassStub())
+ return nullptr;
+
+ return this->template getTrailingObjects<ObjCResilientClassStubInfo>()
+ ->Stub.get();
+ }
+
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Class;
}
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index f6c5497..70abb80 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -1309,6 +1309,28 @@
class_setResilientSuperclassReferenceKind)
};
+/// Extra flags for resilient classes, since we need more than 16 bits of
+/// flags there.
+class ExtraClassDescriptorFlags : public FlagSet<uint32_t> {
+ enum {
+ /// Set if the context descriptor includes a pointer to an Objective-C
+ /// resilient class stub structure. See the description of
+ /// TargetObjCResilientClassStubInfo in Metadata.h for details.
+ ///
+ /// Only meaningful for class descriptors when Objective-C interop is
+ /// enabled.
+ HasObjCResilientClassStub = 0,
+ };
+
+public:
+ explicit ExtraClassDescriptorFlags(uint32_t bits) : FlagSet(bits) {}
+ constexpr ExtraClassDescriptorFlags() {}
+
+ FLAGSET_DEFINE_FLAG_ACCESSORS(HasObjCResilientClassStub,
+ hasObjCResilientClassStub,
+ setObjCResilientClassStub)
+};
+
/// Flags for protocol context descriptors. These values are used as the
/// kindSpecificFlags of the ContextDescriptorFlags for the protocol.
class ProtocolContextDescriptorFlags : public FlagSet<uint16_t> {
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 8c06c8b..a4eeb75 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -542,7 +542,7 @@
NumRequirementsInSignature : 16
);
- SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1+1+1,
+ SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+6+1+1+1,
/// Whether this class requires all of its instance variables to
/// have in-class initializers.
RequiresStoredPropertyInits : 1,
@@ -563,12 +563,11 @@
/// control inserting the implicit destructor.
HasDestructorDecl : 1,
- /// Whether the class has @objc ancestry.
- ObjCKind : 3,
+ /// Information about the class's ancestry.
+ Ancestry : 6,
- /// Whether this class has @objc members.
- HasObjCMembersComputed : 1,
- HasObjCMembers : 1,
+ /// Whether we have computed the above field or not.
+ AncestryComputed : 1,
HasMissingDesignatedInitializers : 1,
HasMissingVTableEntries : 1
@@ -3545,21 +3544,33 @@
UIApplicationMain,
};
-enum class ObjCClassKind : uint8_t {
- /// Neither the class nor any of its superclasses are @objc.
- NonObjC,
- /// One of the superclasses is @objc but another superclass or the
- /// class itself has generic parameters, so while it cannot be
- /// directly represented in Objective-C, it has implicitly @objc
- /// members.
- ObjCMembers,
- /// The top-level ancestor of this class is not @objc, but the
- /// class itself is.
- ObjCWithSwiftRoot,
- /// The class is bona-fide @objc.
- ObjC,
+/// This is the base type for AncestryOptions. Each flag describes possible
+/// interesting kinds of superclasses that a class may have.
+enum class AncestryFlags : uint8_t {
+ /// The class or one of its superclasses is @objc.
+ ObjC = (1<<0),
+
+ /// The class or one of its superclasses is @objcMembers.
+ ObjCMembers = (1<<1),
+
+ /// The class or one of its superclasses is generic.
+ Generic = (1<<2),
+
+ /// The class or one of its superclasses is resilient.
+ Resilient = (1<<3),
+
+ /// The class or one of its superclasses has resilient metadata and is in a
+ /// different resilience domain.
+ ResilientOther = (1<<4),
+
+ /// The class or one of its superclasses is imported from Clang.
+ ClangImported = (1<<5),
};
+/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
+/// kinds of superclasses that a class may have.
+using AncestryOptions = OptionSet<AncestryFlags>;
+
/// ClassDecl - This is the declaration of a class, for example:
///
/// class Complex { var R : Double, I : Double }
@@ -3589,8 +3600,6 @@
friend class SuperclassTypeRequest;
friend class TypeChecker;
- bool hasObjCMembersSlow();
-
public:
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
MutableArrayRef<TypeLoc> Inherited,
@@ -3622,6 +3631,9 @@
/// is no superclass.
ClassDecl *getSuperclassDecl() const;
+ /// Check if this class is a superclass or equal to the given class.
+ bool isSuperclassOf(ClassDecl *other) const;
+
/// Set the superclass of this class.
void setSuperclass(Type superclass);
@@ -3749,18 +3761,13 @@
Bits.ClassDecl.InheritsSuperclassInits = true;
}
- /// Returns if this class has any @objc ancestors, or if it is directly
- /// visible to Objective-C. The latter is a stronger condition which is only
- /// true if the class does not have any generic ancestry.
- ObjCClassKind checkObjCAncestry() const;
+ /// Walks the class hierarchy starting from this class, checking various
+ /// conditions.
+ AncestryOptions checkAncestry() const;
- /// Returns if the class has implicitly @objc members. This is true if any
- /// ancestor class has the @objcMembers attribute.
- bool hasObjCMembers() const {
- if (Bits.ClassDecl.HasObjCMembersComputed)
- return Bits.ClassDecl.HasObjCMembers;
-
- return const_cast<ClassDecl *>(this)->hasObjCMembersSlow();
+ /// Check if the class has ancestry of the given kind.
+ bool checkAncestry(AncestryFlags flag) const {
+ return checkAncestry().contains(flag);
}
/// The type of metaclass to use for a class.
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index 408c2ce..83f6653 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -3592,9 +3592,11 @@
ERROR(objc_in_extension_context,none,
"members of constrained extensions cannot be declared @objc", ())
ERROR(objc_in_generic_extension,none,
- "members of extensions of "
- "%select{classes from generic context|generic classes}0 "
- "cannot be declared @objc", (bool))
+ "extensions of %select{classes from generic context|generic classes}0 "
+ "cannot contain '@objc' members", (bool))
+ERROR(objc_in_resilient_extension,none,
+ "extensions of classes built with library evolution support "
+ "cannot contain '@objc' members", ())
ERROR(objc_operator, none,
"operator methods cannot be declared @objc", ())
ERROR(objc_operator_proto, none,
@@ -3615,6 +3617,10 @@
ERROR(objc_for_generic_class,none,
"generic subclasses of '@objc' classes cannot have an explicit '@objc' "
"because they are not directly visible from Objective-C", ())
+ERROR(objc_for_resilient_class,none,
+ "classes built with library evolution support cannot have explicit "
+ "'@objc' subclasses because they are not directly "
+ "visible from Objective-C", ())
ERROR(objc_getter_for_nonobjc_property,none,
"'@objc' getter for non-'@objc' property", ())
ERROR(objc_getter_for_nonobjc_subscript,none,
diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h
index da93097..abab16b 100644
--- a/include/swift/AST/Module.h
+++ b/include/swift/AST/Module.h
@@ -324,6 +324,10 @@
Bits.ModuleDecl.RawResilienceStrategy = unsigned(strategy);
}
+ bool isResilient() const {
+ return getResilienceStrategy() != ResilienceStrategy::Default;
+ }
+
/// Look up a (possibly overloaded) value set at top-level scope
/// (but with the specified access path, which may come from an import decl)
/// within the current module.
diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h
index 88e0b47..eb8d10d 100644
--- a/include/swift/Basic/LangOptions.h
+++ b/include/swift/Basic/LangOptions.h
@@ -296,6 +296,11 @@
/// set to true.
bool ExperimentalDependenciesIncludeIntrafileOnes = false;
+ /// Enable experimental support for emitting Objective-C resilient class
+ /// stubs. This is a language option since it also determines if we admit
+ /// @objc members in extensions of classes with resilient ancestry.
+ bool EnableObjCResilientClassStubs = false;
+
/// Sets the target we are building for and updates platform conditions
/// to match.
///
diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def
index 3c0c6d6..dec6c39 100644
--- a/include/swift/Demangling/DemangleNodes.def
+++ b/include/swift/Demangling/DemangleNodes.def
@@ -134,6 +134,8 @@
NODE(Metaclass)
NODE(MethodLookupFunction)
NODE(ObjCMetadataUpdateFunction)
+NODE(ObjCResilientClassStub)
+NODE(FullObjCResilientClassStub)
CONTEXT_NODE(ModifyAccessor)
CONTEXT_NODE(Module)
CONTEXT_NODE(NativeOwningAddressor)
diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h
index 5a98fe4..efad066 100644
--- a/include/swift/IRGen/Linking.h
+++ b/include/swift/IRGen/Linking.h
@@ -96,7 +96,7 @@
// This field appears in the ValueWitness kind.
ValueWitnessShift = 8, ValueWitnessMask = 0xFF00,
- // This field appears in the TypeMetadata kind.
+ // This field appears in the TypeMetadata and ObjCResilientClassStub kinds.
MetadataAddressShift = 8, MetadataAddressMask = 0x0300,
// This field appears in associated type access functions.
@@ -164,6 +164,12 @@
/// ClassMetadataStrategy::Update or ::FixedOrUpdate.
ObjCMetadataUpdateFunction,
+ /// A stub that we emit to allow Clang-generated code to statically refer
+ /// to Swift classes with resiliently-sized metadata, since the metadata
+ /// is not statically-emitted. Used when getClassMetadataStrategy() is
+ /// equal to ClassMetadataStrategy::Resilient.
+ ObjCResilientClassStub,
+
/// A class metadata base offset global variable. This stores the offset
/// of the immediate members of a class (generic parameters, field offsets,
/// vtable offsets) in the class's metadata. The immediate members begin
@@ -613,13 +619,19 @@
return entity;
}
+ static LinkEntity forObjCResilientClassStub(ClassDecl *decl,
+ TypeMetadataAddress addr) {
+ LinkEntity entity;
+ entity.setForDecl(Kind::ObjCResilientClassStub, decl);
+ entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
+ return entity;
+ }
+
static LinkEntity forTypeMetadata(CanType concreteType,
TypeMetadataAddress addr) {
LinkEntity entity;
- entity.Pointer = concreteType.getPointer();
- entity.SecondaryPointer = nullptr;
- entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::TypeMetadata))
- | LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
+ entity.setForType(Kind::TypeMetadata, concreteType);
+ entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
return entity;
}
@@ -1021,7 +1033,8 @@
return ValueWitness(LINKENTITY_GET_FIELD(Data, ValueWitness));
}
TypeMetadataAddress getMetadataAddress() const {
- assert(getKind() == Kind::TypeMetadata);
+ assert(getKind() == Kind::TypeMetadata ||
+ getKind() == Kind::ObjCResilientClassStub);
return (TypeMetadataAddress)LINKENTITY_GET_FIELD(Data, MetadataAddress);
}
bool isForeignTypeMetadataCandidate() const {
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 045a723..c60d32a 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -555,4 +555,8 @@
Flags<[FrontendOption]>,
HelpText<"One of 'all', 'resilient' or 'fragile'">;
+def enable_objc_resilient_class_stubs : Flag<["-"], "enable-resilient-objc-class-stubs">,
+ HelpText<"Emit Objective-C resilient class stubs for classes with "
+ "resiliently-sized metadata">;
+
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]
diff --git a/include/swift/Option/SanitizerOptions.h b/include/swift/Option/SanitizerOptions.h
index b8991cc..f19500c 100644
--- a/include/swift/Option/SanitizerOptions.h
+++ b/include/swift/Option/SanitizerOptions.h
@@ -42,5 +42,8 @@
const llvm::Triple &Triple,
DiagnosticEngine &Diag,
OptionSet<SanitizerKind> sanitizers);
+
+/// Returns the active sanitizers as a comma-separated list.
+std::string getSanitizerList(const OptionSet<SanitizerKind> &Set);
}
#endif // SWIFT_OPTIONS_SANITIZER_OPTIONS_H
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 68ae9a4..1489410 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1927,14 +1927,7 @@
if (!isFormallyResilient())
return false;
- switch (getDeclContext()->getParentModule()->getResilienceStrategy()) {
- case ResilienceStrategy::Resilient:
- return true;
- case ResilienceStrategy::Default:
- return false;
- }
-
- llvm_unreachable("Unhandled ResilienceStrategy in switch.");
+ return getModuleContext()->isResilient();
}
bool AbstractStorageDecl::isResilient(ModuleDecl *M,
@@ -3077,20 +3070,10 @@
}
bool NominalTypeDecl::isResilient() const {
- // If we're not formally resilient, don't check the module resilience
- // strategy.
if (!isFormallyResilient())
return false;
- // Otherwise, check the module.
- switch (getParentModule()->getResilienceStrategy()) {
- case ResilienceStrategy::Resilient:
- return true;
- case ResilienceStrategy::Default:
- return false;
- }
-
- llvm_unreachable("Unhandled ResilienceStrategy in switch.");
+ return getModuleContext()->isResilient();
}
bool NominalTypeDecl::isResilient(ModuleDecl *M,
@@ -3536,9 +3519,8 @@
Bits.ClassDecl.InheritsSuperclassInits = 0;
Bits.ClassDecl.RawForeignKind = 0;
Bits.ClassDecl.HasDestructorDecl = 0;
- Bits.ClassDecl.ObjCKind = 0;
- Bits.ClassDecl.HasObjCMembersComputed = 0;
- Bits.ClassDecl.HasObjCMembers = 0;
+ Bits.ClassDecl.Ancestry = 0;
+ Bits.ClassDecl.AncestryComputed = 0;
Bits.ClassDecl.HasMissingDesignatedInitializers = 0;
Bits.ClassDecl.HasMissingVTableEntries = 0;
}
@@ -3549,8 +3531,7 @@
return false;
// If the module is not resilient, neither is the class metadata.
- if (getParentModule()->getResilienceStrategy()
- != ResilienceStrategy::Resilient)
+ if (!getModuleContext()->isResilient())
return false;
// If the class is not public, we can't use it outside the module at all.
@@ -3652,16 +3633,18 @@
return Bits.ClassDecl.InheritsSuperclassInits;
}
-ObjCClassKind ClassDecl::checkObjCAncestry() const {
+AncestryOptions ClassDecl::checkAncestry() const {
// See if we've already computed this.
- if (Bits.ClassDecl.ObjCKind)
- return ObjCClassKind(Bits.ClassDecl.ObjCKind - 1);
+ if (Bits.ClassDecl.AncestryComputed)
+ return AncestryOptions(Bits.ClassDecl.Ancestry);
llvm::SmallPtrSet<const ClassDecl *, 8> visited;
- bool genericAncestry = false, isObjC = false;
- const ClassDecl *CD = this;
- for (;;) {
+ AncestryOptions result;
+ const ClassDecl *CD = this;
+ auto *M = getParentModule();
+
+ do {
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
// However we have to explicitly guard against that here because we get
// called as part of validateDecl().
@@ -3669,55 +3652,54 @@
break;
if (CD->isGenericContext())
- genericAncestry = true;
+ result |= AncestryFlags::Generic;
- // Is this class @objc? For the current class, only look at the attribute
- // to avoid cycles; for superclasses, compute @objc completely.
- if ((CD == this && CD->getAttrs().hasAttribute<ObjCAttr>()) ||
- (CD != this && CD->isObjC()))
- isObjC = true;
+ // Note: it's OK to check for @objc explicitly instead of calling isObjC()
+ // to infer it since we're going to visit every superclass.
+ if (CD->getAttrs().hasAttribute<ObjCAttr>())
+ result |= AncestryFlags::ObjC;
- if (!CD->hasSuperclass())
- break;
+ if (CD->getAttrs().hasAttribute<ObjCMembersAttr>())
+ result |= AncestryFlags::ObjCMembers;
+
+ if (CD->hasClangNode())
+ result |= AncestryFlags::ClangImported;
+
+ if (CD->hasResilientMetadata())
+ result |= AncestryFlags::Resilient;
+
+ if (CD->hasResilientMetadata(M, ResilienceExpansion::Maximal))
+ result |= AncestryFlags::ResilientOther;
+
CD = CD->getSuperclassDecl();
- // If we don't have a valid class here, we should have diagnosed
- // elsewhere.
- if (!CD)
- break;
- }
-
- ObjCClassKind kind = ObjCClassKind::ObjC;
- if (!isObjC)
- kind = ObjCClassKind::NonObjC;
- else if (genericAncestry)
- kind = ObjCClassKind::ObjCMembers;
- else if (CD == this || !CD->isObjC())
- kind = ObjCClassKind::ObjCWithSwiftRoot;
+ } while (CD != nullptr);
// Save the result for later.
- const_cast<ClassDecl *>(this)->Bits.ClassDecl.ObjCKind
- = unsigned(kind) + 1;
- return kind;
+ const_cast<ClassDecl *>(this)->Bits.ClassDecl.Ancestry = result.toRaw();
+ const_cast<ClassDecl *>(this)->Bits.ClassDecl.AncestryComputed = 1;
+ return result;
}
-bool ClassDecl::hasObjCMembersSlow() {
- // Don't attempt to calculate this again.
- Bits.ClassDecl.HasObjCMembersComputed = true;
+bool ClassDecl::isSuperclassOf(ClassDecl *other) const {
+ llvm::SmallPtrSet<const ClassDecl *, 8> visited;
- bool result = false;
- if (getAttrs().hasAttribute<ObjCMembersAttr>())
- result = true;
- else if (auto *superclassDecl = getSuperclassDecl())
- result = superclassDecl->hasObjCMembers();
+ do {
+ if (!visited.insert(other).second)
+ break;
- Bits.ClassDecl.HasObjCMembers = result;
- return result;
+ if (this == other)
+ return true;
+
+ other = other->getSuperclassDecl();
+ } while (other != nullptr);
+
+ return false;
}
ClassDecl::MetaclassKind ClassDecl::getMetaclassKind() const {
assert(getASTContext().LangOpts.EnableObjCInterop &&
"querying metaclass kind without objc interop");
- auto objc = checkObjCAncestry() != ObjCClassKind::NonObjC;
+ auto objc = checkAncestry(AncestryFlags::ObjC);
return objc ? MetaclassKind::ObjC : MetaclassKind::SwiftStub;
}
@@ -3807,8 +3789,6 @@
}
}
// Check the superclass
- if (!C->hasSuperclass())
- break;
C = C->getSuperclassDecl();
}
return nullptr;
@@ -3891,12 +3871,8 @@
// Non-imported enums in non-resilient modules are exhaustive.
const ModuleDecl *containingModule = getModuleContext();
- switch (containingModule->getResilienceStrategy()) {
- case ResilienceStrategy::Default:
+ if (!containingModule->isResilient())
return true;
- case ResilienceStrategy::Resilient:
- break;
- }
// Non-public, non-versioned enums are always exhaustive.
AccessScope accessScope = getFormalAccessScope(/*useDC*/nullptr,
diff --git a/lib/AST/ProtocolConformance.cpp b/lib/AST/ProtocolConformance.cpp
index 1afedd8..9aecda4 100644
--- a/lib/AST/ProtocolConformance.cpp
+++ b/lib/AST/ProtocolConformance.cpp
@@ -458,12 +458,7 @@
if (!getType()->getAnyNominal()->isResilient())
return false;
- switch (getDeclContext()->getParentModule()->getResilienceStrategy()) {
- case ResilienceStrategy::Resilient:
- return true;
- case ResilienceStrategy::Default:
- return false;
- }
+ return getDeclContext()->getParentModule()->isResilient();
}
Optional<ArrayRef<Requirement>>
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 5c4e593..59226e5 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -3110,9 +3110,7 @@
#ifndef NDEBUG
auto *currentClass = getConcreteTypeForSuperclassTraversing(this)
->getClassOrBoundGenericClass();
- while (currentClass && currentClass != baseClass)
- currentClass = currentClass->getSuperclassDecl();
- assert(currentClass == baseClass &&
+ assert(baseClass->isSuperclassOf(currentClass) &&
"no inheritance relationship between given classes");
#endif
@@ -3950,13 +3948,9 @@
}
static ReferenceCounting getClassReferenceCounting(ClassDecl *theClass) {
- while (auto superclass = theClass->getSuperclassDecl()) {
- theClass = superclass;
- }
-
- return theClass->hasClangNode()
- ? ReferenceCounting::ObjC
- : ReferenceCounting::Native;
+ return (theClass->checkAncestry(AncestryFlags::ClangImported)
+ ? ReferenceCounting::ObjC
+ : ReferenceCounting::Native);
}
ReferenceCounting TypeBase::getReferenceCounting() {
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 6c32412..57487d4 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -1809,6 +1809,10 @@
return createWithPoppedType(Node::Kind::MethodLookupFunction);
case 'U':
return createWithPoppedType(Node::Kind::ObjCMetadataUpdateFunction);
+ case 's':
+ return createWithPoppedType(Node::Kind::ObjCResilientClassStub);
+ case 't':
+ return createWithPoppedType(Node::Kind::FullObjCResilientClassStub);
case 'B':
return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
popNode(Node::Kind::Type));
diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp
index 6878925..8a2babc 100644
--- a/lib/Demangling/NodePrinter.cpp
+++ b/lib/Demangling/NodePrinter.cpp
@@ -353,6 +353,7 @@
case Node::Kind::Extension:
case Node::Kind::EnumCase:
case Node::Kind::FieldOffset:
+ case Node::Kind::FullObjCResilientClassStub:
case Node::Kind::FullTypeMetadata:
case Node::Kind::Function:
case Node::Kind::FunctionSignatureSpecialization:
@@ -411,6 +412,7 @@
case Node::Kind::ObjCAttribute:
case Node::Kind::ObjCBlock:
case Node::Kind::ObjCMetadataUpdateFunction:
+ case Node::Kind::ObjCResilientClassStub:
case Node::Kind::Owned:
case Node::Kind::OwningAddressor:
case Node::Kind::OwningMutableAddressor:
@@ -981,6 +983,14 @@
Printer << "ObjC metadata update function for ";
print(Node->getChild(0));
return nullptr;
+ case Node::Kind::ObjCResilientClassStub:
+ Printer << "ObjC resilient class stub for ";
+ print(Node->getChild(0));
+ return nullptr;
+ case Node::Kind::FullObjCResilientClassStub:
+ Printer << "full ObjC resilient class stub for ";
+ print(Node->getChild(0));
+ return nullptr;
case Node::Kind::OutlinedBridgedMethod:
Printer << "outlined bridged method (" << Node->getText() << ") of ";
return nullptr;
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index aca002f..58f07ae 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -1807,6 +1807,14 @@
Buffer << "<objc-metadata-update-function>";
}
+void Remangler::mangleObjCResilientClassStub(Node *node) {
+ Buffer << "<objc-resilient-class-stub>";
+}
+
+void Remangler::mangleFullObjCResilientClassStub(Node *node) {
+ Buffer << "<full-objc-resilient-class-stub>";
+}
+
void Remangler::mangleEmptyList(Node *node) {
Buffer << "<empty>";
}
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 6f11709..d2cdefc 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -2135,6 +2135,16 @@
Buffer << "MU";
}
+void Remangler::mangleObjCResilientClassStub(Node *node) {
+ mangleSingleChildNode(node);
+ Buffer << "Ms";
+}
+
+void Remangler::mangleFullObjCResilientClassStub(Node *node) {
+ mangleSingleChildNode(node);
+ Buffer << "Mt";
+}
+
void Remangler::mangleThrowsAnnotation(Node *node) {
Buffer << 'K';
}
diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp
index 06ae09c..d4a8286 100644
--- a/lib/Driver/UnixToolChains.cpp
+++ b/lib/Driver/UnixToolChains.cpp
@@ -22,6 +22,7 @@
#include "swift/Driver/Driver.h"
#include "swift/Driver/Job.h"
#include "swift/Option/Options.h"
+#include "swift/Option/SanitizerOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringSwitch.h"
@@ -37,27 +38,6 @@
using namespace swift::driver;
using namespace llvm::opt;
-static void addLinkSanitizerLibArgsForLinux(const ArgList &Args,
- ArgStringList &Arguments,
- StringRef Sanitizer,
- const ToolChain &TC) {
- TC.addLinkRuntimeLib(Args, Arguments, TC.sanitizerRuntimeLibName(Sanitizer));
-
- // Code taken from
- // https://github.com/apple/swift-clang/blob/ab3cbe7/lib/Driver/Tools.cpp#L3264-L3276
- // There's no libpthread or librt on RTEMS.
- if (TC.getTriple().getOS() != llvm::Triple::RTEMS) {
- Arguments.push_back("-lpthread");
- Arguments.push_back("-lrt");
- }
- Arguments.push_back("-lm");
-
- // There's no libdl on FreeBSD or RTEMS.
- if (TC.getTriple().getOS() != llvm::Triple::FreeBSD &&
- TC.getTriple().getOS() != llvm::Triple::RTEMS)
- Arguments.push_back("-ldl");
-}
-
std::string
toolchains::GenericUnix::sanitizerRuntimeLibName(StringRef Sanitizer,
bool shared) const {
@@ -293,23 +273,11 @@
Arguments.push_back(
context.Args.MakeArgString("--target=" + getTriple().str()));
- if (getTriple().getOS() == llvm::Triple::Linux) {
- // Make sure we only add SanitizerLibs for executables
- if (job.getKind() == LinkKind::Executable) {
- if (context.OI.SelectedSanitizers & SanitizerKind::Address)
- addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "asan", *this);
-
- if (context.OI.SelectedSanitizers & SanitizerKind::Thread)
- addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "tsan", *this);
-
- if (context.OI.SelectedSanitizers & SanitizerKind::Undefined)
- addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "ubsan", *this);
-
- if (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer)
- addLinkRuntimeLib(context.Args, Arguments,
- sanitizerRuntimeLibName("fuzzer"));
-
- }
+ // Delegate to Clang for sanitizers. It will figure out the correct linker
+ // options.
+ if (job.getKind() == LinkKind::Executable && context.OI.SelectedSanitizers) {
+ Arguments.push_back(context.Args.MakeArgString(
+ "-fsanitize=" + getSanitizerList(context.OI.SelectedSanitizers)));
}
if (context.Args.hasArg(options::OPT_profile_generate)) {
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6d00f96..0193fd6 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -450,6 +450,9 @@
Opts.DisableConstraintSolverPerformanceHacks |=
Args.hasArg(OPT_disable_constraint_solver_performance_hacks);
+ Opts.EnableObjCResilientClassStubs =
+ Args.hasArg(OPT_enable_objc_resilient_class_stubs);
+
// Must be processed after any other language options that could affect
// platform conditions.
bool UnsupportedOS, UnsupportedArch;
diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp
index 7a4185c..917a2d8 100644
--- a/lib/IRGen/GenCast.cpp
+++ b/lib/IRGen/GenCast.cpp
@@ -107,7 +107,8 @@
llvm::Value *targetMetadata;
if ((targetMetadata =
tryEmitConstantHeapMetadataRef(IGF.IGM, toType.getASTType(),
- /*allowUninitialized*/ false))) {
+ /*allowUninitialized*/ false,
+ /*allowStub*/ false))) {
// ok
} else {
targetMetadata
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index b18eafd..8c83508 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -1207,7 +1207,9 @@
else {
auto type = getSelfType(getClass()).getASTType();
llvm::Constant *metadata =
- tryEmitConstantHeapMetadataRef(IGM, type, /*allowUninit*/ true);
+ tryEmitConstantHeapMetadataRef(IGM, type,
+ /*allowUninit*/ true,
+ /*allowStub*/ true);
assert(metadata &&
"extended objc class doesn't have constant metadata?");
fields.add(metadata);
@@ -2021,9 +2023,9 @@
} // end anonymous namespace
static llvm::Function *emitObjCMetadataUpdateFunction(IRGenModule &IGM,
- ClassDecl *cls) {
+ ClassDecl *D) {
llvm::Function *f =
- IGM.getAddrOfObjCMetadataUpdateFunction(cls, ForDefinition);
+ IGM.getAddrOfObjCMetadataUpdateFunction(D, ForDefinition);
f->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, f);
@@ -2037,7 +2039,7 @@
// Just directly call our metadata accessor. This should actually
// return the same metadata; the Objective-C runtime enforces this.
- auto type = cls->getDeclaredType()->getCanonicalType();
+ auto type = D->getDeclaredType()->getCanonicalType();
auto *metadata = IGF.emitTypeMetadataRef(type,
MetadataState::Complete)
.getMetadata();
@@ -2048,6 +2050,48 @@
return f;
}
+/// We emit Objective-C class stubs for non-generic classes with resilient
+/// ancestry. This lets us attach categories to the class even though it
+/// does not have statically-emitted metadata.
+bool irgen::hasObjCResilientClassStub(IRGenModule &IGM, ClassDecl *D) {
+ assert(IGM.getClassMetadataStrategy(D) == ClassMetadataStrategy::Resilient);
+ return (!D->isGenericContext() &&
+ IGM.ObjCInterop &&
+ IGM.Context.LangOpts.EnableObjCResilientClassStubs);
+}
+
+void irgen::emitObjCResilientClassStub(IRGenModule &IGM, ClassDecl *D) {
+ assert(hasObjCResilientClassStub(IGM, D));
+
+ llvm::Constant *fields[] = {
+ llvm::ConstantInt::get(IGM.SizeTy, 0), // reserved
+ llvm::ConstantInt::get(IGM.SizeTy, 1), // isa
+ IGM.getAddrOfObjCMetadataUpdateFunction(D, NotForDefinition)
+ };
+ auto init = llvm::ConstantStruct::get(IGM.ObjCFullResilientClassStubTy,
+ makeArrayRef(fields));
+
+ // Define the full stub. This is a private symbol.
+ auto fullObjCStub = cast<llvm::GlobalVariable>(
+ IGM.getAddrOfObjCResilientClassStub(D, ForDefinition,
+ TypeMetadataAddress::FullMetadata));
+ fullObjCStub->setInitializer(init);
+
+ // Emit the metadata update function referenced above.
+ emitObjCMetadataUpdateFunction(IGM, D);
+
+ // Apply the offset.
+ auto *objcStub = llvm::ConstantExpr::getBitCast(fullObjCStub, IGM.Int8PtrTy);
+ objcStub = llvm::ConstantExpr::getInBoundsGetElementPtr(
+ IGM.Int8Ty, objcStub, IGM.getSize(IGM.getPointerSize()));
+ objcStub = llvm::ConstantExpr::getPointerCast(objcStub,
+ IGM.ObjCResilientClassStubTy->getPointerTo());
+
+ auto entity = LinkEntity::forObjCResilientClassStub(
+ D, TypeMetadataAddress::AddressPoint);
+ IGM.defineAlias(entity, objcStub);
+}
+
/// Emit the private data (RO-data) associated with a class.
llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM,
ClassDecl *cls) {
diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h
index 5c357a9..b7fdf7f 100644
--- a/lib/IRGen/GenClass.h
+++ b/lib/IRGen/GenClass.h
@@ -170,6 +170,14 @@
llvm::Value *selfValue,
llvm::Value *metadataValue);
+ /// We emit Objective-C class stubs for non-generic classes with resilient
+ /// ancestry. This lets us attach categories to the class even though it
+ /// does not have statically-emitted metadata.
+ bool hasObjCResilientClassStub(IRGenModule &IGM, ClassDecl *D);
+
+ /// Emit a resilient class stub.
+ void emitObjCResilientClassStub(IRGenModule &IGM, ClassDecl *D);
+
/// Emit the constant fragile offset of the given property inside an instance
/// of the class.
llvm::Constant *
diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp
index 08f1428..3297fde 100644
--- a/lib/IRGen/GenDecl.cpp
+++ b/lib/IRGen/GenDecl.cpp
@@ -2960,7 +2960,7 @@
llvm::Function *
IRGenModule::getAddrOfObjCMetadataUpdateFunction(ClassDecl *classDecl,
ForDefinition_t forDefinition) {
- IRGen.noteUseOfTypeMetadata(classDecl);
+ assert(ObjCInterop);
LinkEntity entity = LinkEntity::forObjCMetadataUpdateFunction(classDecl);
llvm::Function *&entry = GlobalFuncs[entity];
@@ -2970,14 +2970,25 @@
}
// Class _Nullable callback(Class _Nonnull cls, void * _Nullable arg);
- llvm::Type *params[] = { ObjCClassPtrTy, Int8PtrTy };
- auto fnType = llvm::FunctionType::get(ObjCClassPtrTy, params, false);
- Signature signature(fnType, llvm::AttributeList(), DefaultCC);
+ Signature signature(ObjCUpdateCallbackTy, llvm::AttributeList(), DefaultCC);
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
entry = createFunction(*this, link, signature);
return entry;
}
+/// Fetch the declaration of an Objective-C resilient class stub.
+llvm::Constant *
+IRGenModule::getAddrOfObjCResilientClassStub(ClassDecl *classDecl,
+ ForDefinition_t forDefinition,
+ TypeMetadataAddress addr) {
+ assert(ObjCInterop);
+ assert(getClassMetadataStrategy(classDecl) ==
+ ClassMetadataStrategy::Resilient);
+
+ LinkEntity entity = LinkEntity::forObjCResilientClassStub(classDecl, addr);
+ return getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
+}
+
/// Fetch the type metadata access function for a non-generic type.
llvm::Function *
IRGenModule::getAddrOfTypeMetadataAccessFunction(CanType type,
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 031fea3..9d6f62d 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -1883,14 +1883,6 @@
llvm_unreachable("unhandled ISA encoding");
}
-static ClassDecl *getRootClass(ClassDecl *theClass) {
- while (theClass->hasSuperclass()) {
- theClass = theClass->getSuperclassDecl();
- assert(theClass && "base type of class not a class?");
- }
- return theClass;
-}
-
/// What isa encoding mechanism does a type have?
IsaEncoding irgen::getIsaEncodingForType(IRGenModule &IGM,
CanType type) {
@@ -1900,7 +1892,7 @@
if (auto theClass = type->getClassOrBoundGenericClass()) {
// We can access the isas of pure Swift classes directly.
- if (getRootClass(theClass)->hasKnownSwiftImplementation())
+ if (!theClass->checkAncestry(AncestryFlags::ClangImported))
return IsaEncoding::Pointer;
// For ObjC or mixed classes, we need to use object_getClass.
return IsaEncoding::ObjC;
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index c63f2a5..56d573e 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -1631,6 +1631,7 @@
// union {
// uint32_t MetadataPositiveSizeInWords;
+ // ExtraClassContextFlags ExtraClassFlags;
// };
if (!MetadataLayout) {
// FIXME: do something meaningful for foreign classes?
@@ -1639,7 +1640,10 @@
B.addInt32(MetadataLayout->getSize().getOffsetToEnd()
/ IGM.getPointerSize());
} else {
- B.addInt32(0); // currently unused
+ ExtraClassDescriptorFlags flags;
+ if (hasObjCResilientClassStub(IGM, getType()))
+ flags.setObjCResilientClassStub(true);
+ B.addInt32(flags.getOpaqueValue());
}
// uint32_t NumImmediateMembers;
@@ -2481,7 +2485,8 @@
case ClassMetadataStrategy::Update:
case ClassMetadataStrategy::FixedOrUpdate:
case ClassMetadataStrategy::Fixed: {
- auto type = (Target->checkObjCAncestry() != ObjCClassKind::NonObjC
+ // FIXME: Should this check HasImported instead?
+ auto type = (Target->checkAncestry(AncestryFlags::ObjC)
? IGM.Context.TheUnknownObjectType
: IGM.Context.TheNativeObjectType);
auto wtable = IGM.getAddrOfValueWitnessTable(type);
@@ -2551,7 +2556,8 @@
Type type = Target->mapTypeIntoContext(Target->getSuperclass());
auto *metadata = tryEmitConstantHeapMetadataRef(
IGM, type->getCanonicalType(),
- /*allowUninit*/ false);
+ /*allowUninit*/ false,
+ /*allowStub*/ false);
assert(metadata != nullptr);
B.add(metadata);
}
@@ -3043,23 +3049,17 @@
/// references, we emit the symbol as a global asm block.
static void emitObjCClassSymbol(IRGenModule &IGM,
ClassDecl *classDecl,
- llvm::GlobalValue *metadata) {
- llvm::SmallString<32> classSymbol;
- LinkEntity::forObjCClass(classDecl).mangle(classSymbol);
-
- // Create the alias.
- auto *metadataTy = cast<llvm::PointerType>(metadata->getType());
+ llvm::Constant *metadata) {
+ auto entity = LinkEntity::forObjCClass(classDecl);
+ LinkInfo link = LinkInfo::get(IGM, entity, ForDefinition);
// Create the alias.
- auto *alias = llvm::GlobalAlias::create(metadataTy->getElementType(),
- metadataTy->getAddressSpace(),
- metadata->getLinkage(),
- classSymbol.str(), metadata,
- IGM.getModule());
- alias->setVisibility(metadata->getVisibility());
-
- if (IGM.useDllStorage())
- alias->setDLLStorageClass(metadata->getDLLStorageClass());
+ auto *ptrTy = cast<llvm::PointerType>(metadata->getType());
+ auto *alias = llvm::GlobalAlias::create(
+ ptrTy->getElementType(), ptrTy->getAddressSpace(), link.getLinkage(),
+ link.getName(), metadata, &IGM.Module);
+ ApplyIRLinkage({link.getLinkage(), link.getVisibility(), link.getDLLStorage()})
+ .to(alias);
}
/// Emit the type metadata or metadata template for a class.
@@ -3142,6 +3142,26 @@
if (IGM.ObjCInterop) {
switch (strategy) {
case ClassMetadataStrategy::Resilient:
+ // Even non-@objc classes can have Objective-C categories attached, so
+ // we always emit a resilient class stub as long as -enable-objc-interop
+ // is set.
+ if (hasObjCResilientClassStub(IGM, classDecl)) {
+ emitObjCResilientClassStub(IGM, classDecl);
+
+ if (classDecl->isObjC()) {
+ auto *stub = IGM.getAddrOfObjCResilientClassStub(
+ classDecl, NotForDefinition,
+ TypeMetadataAddress::AddressPoint);
+ emitObjCClassSymbol(IGM, classDecl, stub);
+
+ // @_objc_non_lazy_realization is only for use by the standard
+ // library, and we cannot support it with Objective-C class
+ // stubs (which there are none of in the standard library).
+ assert(!classDecl->getAttrs().hasAttribute<ObjCNonLazyRealizationAttr>());
+ IGM.addObjCClass(stub, /*eagerInitialization=*/false);
+ }
+ }
+ break;
case ClassMetadataStrategy::Singleton:
break;
diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h
index 4aa697b..f764c39 100644
--- a/lib/IRGen/IRGenMangler.h
+++ b/lib/IRGen/IRGenMangler.h
@@ -107,6 +107,14 @@
return mangleNominalTypeSymbol(Decl, "MU");
}
+ std::string mangleObjCResilientClassStub(const ClassDecl *Decl) {
+ return mangleNominalTypeSymbol(Decl, "Ms");
+ }
+
+ std::string mangleFullObjCResilientClassStub(const ClassDecl *Decl) {
+ return mangleNominalTypeSymbol(Decl, "Mt");
+ }
+
std::string mangleClassMetadataBaseOffset(const ClassDecl *Decl) {
return mangleNominalTypeSymbol(Decl, "Mo");
}
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index 0d6f7f7..89b4c63 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -430,7 +430,24 @@
// point too.
};
ObjCBlockStructTy->setBody(objcBlockElts);
-
+
+ // Class _Nullable callback(Class _Nonnull cls, void * _Nullable arg);
+ llvm::Type *params[] = { ObjCClassPtrTy, Int8PtrTy };
+ ObjCUpdateCallbackTy = llvm::FunctionType::get(ObjCClassPtrTy, params, false);
+
+ // The full class stub structure, including a word before the address point.
+ ObjCFullResilientClassStubTy = createStructType(*this, "objc_full_class_stub", {
+ SizeTy, // zero padding to appease the linker
+ SizeTy, // isa pointer -- always 1
+ ObjCUpdateCallbackTy->getPointerTo() // the update callback
+ });
+
+ // What we actually export.
+ ObjCResilientClassStubTy = createStructType(*this, "objc_class_stub", {
+ SizeTy, // isa pointer -- always 1
+ ObjCUpdateCallbackTy->getPointerTo() // the update callback
+ });
+
auto ErrorStructTy = llvm::StructType::create(LLVMContext, "swift.error");
// ErrorStruct is currently opaque to the compiler.
ErrorPtrTy = ErrorStructTy->getPointerTo(DefaultAS);
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 9a65012..97c84fa 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -142,6 +142,7 @@
struct SymbolicMangling;
class TypeConverter;
class TypeInfo;
+ enum class TypeMetadataAddress;
enum class ValueWitness : unsigned;
enum class ClassMetadataStrategy;
@@ -577,6 +578,9 @@
llvm::PointerType *ObjCSuperPtrTy; /// %objc_super*
llvm::StructType *ObjCBlockStructTy; /// %objc_block
llvm::PointerType *ObjCBlockPtrTy; /// %objc_block*
+ llvm::FunctionType *ObjCUpdateCallbackTy;
+ llvm::StructType *ObjCFullResilientClassStubTy; /// %objc_full_class_stub
+ llvm::StructType *ObjCResilientClassStubTy; /// %objc_class_stub
llvm::StructType *ProtocolRecordTy;
llvm::PointerType *ProtocolRecordPtrTy;
llvm::StructType *ProtocolConformanceDescriptorTy;
@@ -1331,6 +1335,10 @@
llvm::Function *getAddrOfObjCMetadataUpdateFunction(ClassDecl *D,
ForDefinition_t forDefinition);
+ llvm::Constant *getAddrOfObjCResilientClassStub(ClassDecl *D,
+ ForDefinition_t forDefinition,
+ TypeMetadataAddress addr);
+
llvm::Function *
getAddrOfSILFunction(SILFunction *f, ForDefinition_t forDefinition,
bool isDynamicallyReplaceableImplementation = false,
diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp
index 5c337dc..4f5cb23 100644
--- a/lib/IRGen/Linking.cpp
+++ b/lib/IRGen/Linking.cpp
@@ -182,6 +182,15 @@
case Kind::ObjCMetadataUpdateFunction:
return mangler.mangleObjCMetadataUpdateFunction(cast<ClassDecl>(getDecl()));
+ case Kind::ObjCResilientClassStub:
+ switch (getMetadataAddress()) {
+ case TypeMetadataAddress::FullMetadata:
+ return mangler.mangleFullObjCResilientClassStub(cast<ClassDecl>(getDecl()));
+ case TypeMetadataAddress::AddressPoint:
+ return mangler.mangleObjCResilientClassStub(cast<ClassDecl>(getDecl()));
+ }
+ llvm_unreachable("invalid metadata address");
+
case Kind::ClassMetadataBaseOffset: // class metadata base offset
return mangler.mangleClassMetadataBaseOffset(cast<ClassDecl>(getDecl()));
@@ -507,6 +516,20 @@
return SILLinkage::PublicExternal;
+ case Kind::ObjCResilientClassStub: {
+ switch (getMetadataAddress()) {
+ case TypeMetadataAddress::FullMetadata:
+ // The full class stub object is private to the containing module.
+ return SILLinkage::Private;
+ case TypeMetadataAddress::AddressPoint: {
+ auto *classDecl = cast<ClassDecl>(getDecl());
+ return getSILLinkage(getDeclLinkage(classDecl),
+ forDefinition);
+ }
+ }
+ llvm_unreachable("invalid metadata address");
+ }
+
case Kind::EnumCase: {
auto *elementDecl = cast<EnumElementDecl>(getDecl());
return getSILLinkage(getDeclLinkage(elementDecl), forDefinition);
@@ -740,6 +763,7 @@
}
case Kind::ObjCMetadataUpdateFunction:
+ case Kind::ObjCResilientClassStub:
case Kind::ValueWitness:
case Kind::TypeMetadataAccessFunction:
case Kind::TypeMetadataLazyCacheVariable:
@@ -799,6 +823,7 @@
case TypeMetadataAddress::AddressPoint:
return IGM.TypeMetadataStructTy;
}
+ llvm_unreachable("invalid metadata address");
case Kind::TypeMetadataPattern:
// TODO: Use a real type?
@@ -840,6 +865,16 @@
return IGM.DynamicReplacementKeyTy;
case Kind::DynamicallyReplaceableFunctionVariable:
return IGM.DynamicReplacementLinkEntryTy;
+ case Kind::ObjCMetadataUpdateFunction:
+ return IGM.ObjCUpdateCallbackTy;
+ case Kind::ObjCResilientClassStub:
+ switch (getMetadataAddress()) {
+ case TypeMetadataAddress::FullMetadata:
+ return IGM.ObjCFullResilientClassStubTy;
+ case TypeMetadataAddress::AddressPoint:
+ return IGM.ObjCResilientClassStubTy;
+ }
+ llvm_unreachable("invalid metadata address");
default:
llvm_unreachable("declaration LLVM type not specified");
}
@@ -883,6 +918,7 @@
case Kind::SwiftMetaclassStub:
case Kind::DynamicallyReplaceableFunctionVariable:
case Kind::DynamicallyReplaceableFunctionKey:
+ case Kind::ObjCResilientClassStub:
return IGM.getPointerAlignment();
case Kind::SILFunction:
return Alignment(1);
@@ -947,7 +983,6 @@
case Kind::ObjCClassRef:
case Kind::ObjCMetaclass:
case Kind::SwiftMetaclassStub:
- case Kind::ObjCMetadataUpdateFunction:
case Kind::ClassMetadataBaseOffset:
case Kind::PropertyDescriptor:
case Kind::NominalTypeDescriptor:
@@ -966,6 +1001,8 @@
->isWeakImported(module, context);
// TODO: Revisit some of the below, for weak conformances.
+ case Kind::ObjCMetadataUpdateFunction:
+ case Kind::ObjCResilientClassStub:
case Kind::TypeMetadataPattern:
case Kind::TypeMetadataInstantiationCache:
case Kind::TypeMetadataInstantiationFunction:
@@ -1020,6 +1057,7 @@
case Kind::ObjCMetaclass:
case Kind::SwiftMetaclassStub:
case Kind::ObjCMetadataUpdateFunction:
+ case Kind::ObjCResilientClassStub:
case Kind::ClassMetadataBaseOffset:
case Kind::PropertyDescriptor:
case Kind::NominalTypeDescriptor:
diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp
index 8cd59c5..badab24 100644
--- a/lib/IRGen/MetadataRequest.cpp
+++ b/lib/IRGen/MetadataRequest.cpp
@@ -508,14 +508,20 @@
/// Attempts to return a constant heap metadata reference for a
/// class type. This is generally only valid for specific kinds of
/// ObjC reference, like superclasses or category references.
-llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
- CanType type,
- bool allowDynamicUninitialized) {
+llvm::Constant *
+irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
+ CanType type,
+ bool allowDynamicUninitialized,
+ bool allowStub) {
auto theDecl = type->getClassOrBoundGenericClass();
assert(theDecl && "emitting constant heap metadata ref for non-class type?");
switch (IGM.getClassMetadataStrategy(theDecl)) {
case ClassMetadataStrategy::Resilient:
+ if (allowStub && IGM.Context.LangOpts.EnableObjCResilientClassStubs) {
+ return IGM.getAddrOfObjCResilientClassStub(theDecl, NotForDefinition,
+ TypeMetadataAddress::AddressPoint);
+ }
return nullptr;
case ClassMetadataStrategy::Singleton:
diff --git a/lib/IRGen/MetadataRequest.h b/lib/IRGen/MetadataRequest.h
index b31a47a..cfec1da 100644
--- a/lib/IRGen/MetadataRequest.h
+++ b/lib/IRGen/MetadataRequest.h
@@ -592,7 +592,8 @@
/// by a constant.
llvm::Constant *tryEmitConstantHeapMetadataRef(IRGenModule &IGM,
CanType type,
- bool allowUninitialized);
+ bool allowUninitialized,
+ bool allowStub);
enum class MetadataValueType { ObjCClass, TypeMetadata };
diff --git a/lib/Option/SanitizerOptions.cpp b/lib/Option/SanitizerOptions.cpp
index 5cd32bf..7e59996 100644
--- a/lib/Option/SanitizerOptions.cpp
+++ b/lib/Option/SanitizerOptions.cpp
@@ -188,3 +188,13 @@
return sanitizerSet;
}
+
+std::string swift::getSanitizerList(const OptionSet<SanitizerKind> &Set) {
+ std::string list;
+ if (Set & SanitizerKind::Address) list += "address,";
+ if (Set & SanitizerKind::Thread) list += "thread,";
+ if (Set & SanitizerKind::Fuzzer) list += "fuzzer,";
+ if (Set & SanitizerKind::Undefined) list += "undefined,";
+ if (!list.empty()) list.pop_back(); // Remove last comma
+ return list;
+}
diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp
index 4408a50..c13d383 100644
--- a/lib/PrintAsObjC/PrintAsObjC.cpp
+++ b/lib/PrintAsObjC/PrintAsObjC.cpp
@@ -322,14 +322,22 @@
void visitClassDecl(ClassDecl *CD) {
printDocumentationComment(CD);
+ bool hasResilientAncestry =
+ CD->checkAncestry().contains(AncestryFlags::ResilientOther);
+ if (hasResilientAncestry) {
+ os << "SWIFT_RESILIENT_CLASS";
+ } else {
+ os << "SWIFT_CLASS";
+ }
+
StringRef customName = getNameForObjC(CD, CustomNamesOnly);
if (customName.empty()) {
llvm::SmallString<32> scratch;
- os << "SWIFT_CLASS(\"" << CD->getObjCRuntimeName(scratch) << "\")";
+ os << "(\"" << CD->getObjCRuntimeName(scratch) << "\")";
printAvailability(CD);
os << "\n@interface " << CD->getName();
} else {
- os << "SWIFT_CLASS_NAMED(\"" << CD->getName() << "\")";
+ os << "_NAMED(\"" << CD->getName() << "\")";
printAvailability(CD);
os << "\n@interface " << customName;
}
@@ -2640,6 +2648,20 @@
"SWIFT_CLASS_EXTRA\n"
"# endif\n"
"#endif\n"
+ "#if !defined(SWIFT_RESILIENT_CLASS)\n"
+ "# if __has_attribute(objc_class_stub)\n"
+ "# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) "
+ "__attribute__((objc_class_stub))\n"
+ "# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) "
+ "__attribute__((objc_class_stub)) "
+ "SWIFT_CLASS_NAMED(SWIFT_NAME)\n"
+ "# else\n"
+ "# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) "
+ "SWIFT_CLASS(SWIFT_NAME)\n"
+ "# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) "
+ "SWIFT_CLASS_NAMED(SWIFT_NAME)\n"
+ "# endif\n"
+ "#endif\n"
"\n"
"#if !defined(SWIFT_PROTOCOL)\n"
"# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) "
diff --git a/lib/SIL/DynamicCasts.cpp b/lib/SIL/DynamicCasts.cpp
index ef5cad9..25ecc64 100644
--- a/lib/SIL/DynamicCasts.cpp
+++ b/lib/SIL/DynamicCasts.cpp
@@ -56,14 +56,14 @@
return !M->getASTContext().getBridgedToObjC(M, T);
}
-static bool canClassOrSuperclassesHaveExtensions(ClassDecl *CD,
- bool isWholeModuleOpts) {
+static bool canClassOrSuperclassesHaveUnknownSubclasses(ClassDecl *CD,
+ bool isWholeModuleOpts) {
while (CD) {
- // Open classes can always be extended
+ // Open classes can always have unknown subclasses.
if (CD->getEffectiveAccess() == AccessLevel::Open)
return true;
- // Internal and public classes can be extended, if we are not in
+ // Internal and public classes may have unknown subclasses if we are not in
// whole-module-optimization mode.
if (CD->getEffectiveAccess() >= AccessLevel::Internal &&
!isWholeModuleOpts)
@@ -110,11 +110,9 @@
}
// If it is a class and it can be proven that this class and its
- // superclasses cannot be extended, then it is safe to proceed.
- // No need to check this for structs, as they do not have any
- // superclasses.
+ // superclasses cannot have unknown subclasses, then it is safe to proceed.
if (auto *CD = source.getClassOrBoundGenericClass()) {
- if (canClassOrSuperclassesHaveExtensions(CD, isWholeModuleOpts))
+ if (canClassOrSuperclassesHaveUnknownSubclasses(CD, isWholeModuleOpts))
return DynamicCastFeasibility::MaySucceed;
// Derived types may conform to the protocol.
if (!CD->isFinal()) {
@@ -555,22 +553,13 @@
if (targetClass->usesObjCGenericsModel()) {
// If both classes are ObjC generics, the cast may succeed if the
// classes are related, irrespective of their generic parameters.
- auto isDeclSuperclass = [&](ClassDecl *proposedSuper,
- ClassDecl *proposedSub) -> bool {
- do {
- if (proposedSuper == proposedSub)
- return true;
- } while ((proposedSub = proposedSub->getSuperclassDecl()));
-
- return false;
- };
-
- if (isDeclSuperclass(sourceClass, targetClass))
+
+ if (sourceClass->isSuperclassOf(targetClass))
return DynamicCastFeasibility::MaySucceed;
- if (isDeclSuperclass(targetClass, sourceClass)) {
+ if (targetClass->isSuperclassOf(sourceClass))
return DynamicCastFeasibility::WillSucceed;
- }
+
return DynamicCastFeasibility::WillFail;
}
}
diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp
index 4d396bd..13850e2 100644
--- a/lib/SIL/SILDeclRef.cpp
+++ b/lib/SIL/SILDeclRef.cpp
@@ -330,8 +330,7 @@
d = cast<NominalTypeDecl>(d->getDeclContext());
// FIXME: This should always be true.
- if (d->getDeclContext()->getParentModule()->getResilienceStrategy() ==
- ResilienceStrategy::Resilient)
+ if (d->getModuleContext()->isResilient())
limit = Limit::NeverPublic;
}
diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp
index cd18ab4..064e45c 100644
--- a/lib/SIL/SILVerifier.cpp
+++ b/lib/SIL/SILVerifier.cpp
@@ -2291,10 +2291,8 @@
->getInstanceType()->getClassOrBoundGenericClass();
require(class2,
"Second operand of dealloc_partial_ref must be a class metatype");
- while (class1 != class2) {
- class1 = class1->getSuperclassDecl();
- require(class1, "First operand not superclass of second instance type");
- }
+ require(class2->isSuperclassOf(class1),
+ "First operand not superclass of second instance type");
}
void checkAllocBoxInst(AllocBoxInst *AI) {
@@ -4981,13 +4979,8 @@
assert(theClass && "vtable entry must refer to a class member");
// The class context must be the vtable's class, or a superclass thereof.
- auto c = getClass();
- do {
- if (c == theClass)
- break;
- c = c->getSuperclassDecl();
- } while (c);
- assert(c && "vtable entry must refer to a member of the vtable's class");
+ assert(theClass->isSuperclassOf(getClass()) &&
+ "vtable entry must refer to a member of the vtable's class");
// All function vtable entries must be at their natural uncurry level.
assert(!entry.Method.isCurried && "vtable entry must not be curried");
diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp
index 579c879..11edbc4 100644
--- a/lib/SILGen/SILGen.cpp
+++ b/lib/SILGen/SILGen.cpp
@@ -1368,8 +1368,7 @@
// stored) and doesn't have a setter with less-than-public visibility.
auto expansion = ResilienceExpansion::Maximal;
- switch (SGM.M.getSwiftModule()->getResilienceStrategy()) {
- case ResilienceStrategy::Default: {
+ if (!SGM.M.getSwiftModule()->isResilient()) {
if (SGM.canStorageUseStoredKeyPathComponent(decl, expansion)) {
// External modules can't directly access storage, unless this is a
// property in a fixed-layout type.
@@ -1387,18 +1386,15 @@
return false;
}
- case ResilienceStrategy::Resilient: {
- // A resilient module needs to handle binaries compiled against its older
- // versions. This means we have to be a bit more conservative, since in
- // earlier versions, a settable property may have withheld the setter,
- // or a fixed-layout type may not have been.
- // Without availability information, only get-only computed properties
- // can resiliently use trivial descriptors.
- return !SGM.canStorageUseStoredKeyPathComponent(decl, expansion)
- && decl->getSetter() == nullptr;
- }
- }
- llvm_unreachable("unhandled strategy");
+
+ // A resilient module needs to handle binaries compiled against its older
+ // versions. This means we have to be a bit more conservative, since in
+ // earlier versions, a settable property may have withheld the setter,
+ // or a fixed-layout type may not have been.
+ // Without availability information, only get-only computed properties
+ // can resiliently use trivial descriptors.
+ return !SGM.canStorageUseStoredKeyPathComponent(decl, expansion)
+ && decl->getSetter() == nullptr;
}
void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp
index 1a3d203..a0e01f5 100644
--- a/lib/SILGen/SILGenConstructor.cpp
+++ b/lib/SILGen/SILGenConstructor.cpp
@@ -451,14 +451,9 @@
}
bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
- while (true) {
- // If the root class was implemented in Objective-C, use Objective-C's
- // allocation methods because they may have been overridden.
- if (!theClass->hasSuperclass())
- return theClass->hasClangNode();
-
- theClass = theClass->getSuperclassDecl();
- }
+ // If the root class was implemented in Objective-C, use Objective-C's
+ // allocation methods because they may have been overridden.
+ return theClass->checkAncestry(AncestryFlags::ClangImported);
}
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
index 3634c64..7ff918e 100644
--- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
+++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp
@@ -255,18 +255,6 @@
makeAlive(WT);
}
- /// Returns true if \a Derived is the same as \p Base or derived from it.
- static bool isDerivedOrEqual(ClassDecl *Derived, ClassDecl *Base) {
- for (;;) {
- if (Derived == Base)
- return true;
- if (!Derived->hasSuperclass())
- break;
- Derived = Derived->getSuperclassDecl();
- }
- return false;
- }
-
/// Returns true if the implementation of method \p FD in class \p ImplCl
/// may be called when the type of the class_method's operand is \p MethodCl.
/// Both, \p MethodCl and \p ImplCl, may by null if not known or if it's a
@@ -277,7 +265,7 @@
return true;
// All implementations of derived classes may be called.
- if (isDerivedOrEqual(ImplCl, MethodCl))
+ if (MethodCl->isSuperclassOf(ImplCl))
return true;
// Check if the method implementation is the same in a super class, i.e.
diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
index 4076785..f794dd0 100644
--- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
@@ -283,8 +283,7 @@
// If the class has an @objc ancestry it can be dynamically subclassed and we
// can't therefore statically know the default case.
- auto Ancestry = CD->checkObjCAncestry();
- if (Ancestry != ObjCClassKind::NonObjC)
+ if (CD->checkAncestry(AncestryFlags::ObjC))
return false;
// Without an associated context we cannot perform any
diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp
index 03bd71cee..55e7576 100644
--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -322,7 +322,7 @@
// Accessors for classes with @objc ancestry are not @_transparent,
// since they use a field offset variable which is not exported.
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
- if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC)
+ if (classDecl->checkAncestry(AncestryFlags::ObjC))
return;
// Accessors synthesized on-demand are never transaprent.
diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp
index 0e4ee57..befb30b 100644
--- a/lib/Sema/DerivedConformanceEquatableHashable.cpp
+++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp
@@ -631,8 +631,7 @@
auto boolTy = C.getBoolDecl()->getDeclaredType();
Identifier generatedIdentifier;
- if (parentDC->getParentModule()->getResilienceStrategy() ==
- ResilienceStrategy::Resilient) {
+ if (parentDC->getParentModule()->isResilient()) {
generatedIdentifier = C.Id_EqualsOperator;
} else if (selfIfaceTy->getEnumOrBoundGenericEnum()) {
generatedIdentifier = C.Id_derived_enum_equals;
diff --git a/lib/Sema/DerivedConformanceRawRepresentable.cpp b/lib/Sema/DerivedConformanceRawRepresentable.cpp
index 5e26678..a97d959 100644
--- a/lib/Sema/DerivedConformanceRawRepresentable.cpp
+++ b/lib/Sema/DerivedConformanceRawRepresentable.cpp
@@ -147,8 +147,7 @@
AbstractFunctionDecl *afd) {
ASTContext &C = derived.TC.Context;
auto parentDC = derived.getConformanceContext();
- if (parentDC->getParentModule()->getResilienceStrategy() !=
- ResilienceStrategy::Resilient) {
+ if (!parentDC->getParentModule()->isResilient()) {
AccessScope access =
afd->getFormalAccessScope(nullptr,
/*treatUsableFromInlineAsPublic*/true);
diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp
index eab93bd..4685e59 100644
--- a/lib/Sema/MiscDiagnostics.cpp
+++ b/lib/Sema/MiscDiagnostics.cpp
@@ -3335,13 +3335,8 @@
// If the best method was from a subclass of the place where
// this method was declared, we have a new best.
- while (auto superclassDecl = bestClassDecl->getSuperclassDecl()) {
- if (classDecl == superclassDecl) {
- bestMethod = method;
- break;
- }
-
- bestClassDecl = superclassDecl;
+ if (classDecl->isSuperclassOf(bestClassDecl)) {
+ bestMethod = method;
}
}
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index 2f354f8..d87a8fa 100644
--- a/lib/Sema/ResilienceDiagnostics.cpp
+++ b/lib/Sema/ResilienceDiagnostics.cpp
@@ -119,8 +119,7 @@
// Do enforce the restriction even in pre-Swift-5 modes if the module we're
// building is resilient, though.
if (D->isObjCDynamic() && !Context.isSwiftVersionAtLeast(5) &&
- DC->getParentModule()->getResilienceStrategy() !=
- ResilienceStrategy::Resilient) {
+ !DC->getParentModule()->isResilient()) {
return false;
}
diff --git a/lib/Sema/TypeCheckAccess.cpp b/lib/Sema/TypeCheckAccess.cpp
index 59f13d7..9506f8b 100644
--- a/lib/Sema/TypeCheckAccess.cpp
+++ b/lib/Sema/TypeCheckAccess.cpp
@@ -205,12 +205,11 @@
} else {
// The type violates the rules of access control (with or without taking the
- // TypeRepr into account).
+ // TypeRepr into account).
if (typeRepr && mayBeInferred &&
!TC.getLangOpts().isSwiftVersionAtLeast(5) &&
- useDC->getParentModule()->getResilienceStrategy() !=
- ResilienceStrategy::Resilient) {
+ !useDC->getParentModule()->isResilient()) {
// Swift 4.2 and earlier didn't check the Type when a TypeRepr was
// present. However, this is a major hole when generic parameters are
// inferred:
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index a092507..457d14a 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -2380,12 +2380,9 @@
void AttributeChecker::visitFrozenAttr(FrozenAttr *attr) {
auto *ED = cast<EnumDecl>(D);
- switch (ED->getModuleContext()->getResilienceStrategy()) {
- case ResilienceStrategy::Default:
+ if (!ED->getModuleContext()->isResilient()) {
diagnoseAndRemoveAttr(attr, diag::enum_frozen_nonresilient, attr);
return;
- case ResilienceStrategy::Resilient:
- break;
}
if (ED->getFormalAccess() < AccessLevel::Public &&
diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp
index daee66f..6506e49 100644
--- a/lib/Sema/TypeCheckConstraints.cpp
+++ b/lib/Sema/TypeCheckConstraints.cpp
@@ -4040,6 +4040,33 @@
if (toType->isAnyObject() || fromType->isAnyObject())
return CheckedCastKind::ValueCast;
+ // A cast from an existential type to a concrete type does not succeed. For
+ // example:
+ //
+ // struct S {}
+ // enum FooError: Error { case bar }
+ //
+ // func foo() {
+ // do {
+ // throw FooError.bar
+ // } catch is X { /* Will always fail */
+ // print("Caught bar error")
+ // }
+ // }
+ if (fromExistential) {
+ if (auto NTD = toType->getAnyNominal()) {
+ if (!isa<ProtocolDecl>(NTD)) {
+ auto protocolDecl =
+ dyn_cast_or_null<ProtocolDecl>(fromType->getAnyNominal());
+ if (protocolDecl &&
+ !conformsToProtocol(toType, protocolDecl, dc,
+ ConformanceCheckFlags::InExpression)) {
+ return failed();
+ }
+ }
+ }
+ }
+
bool toRequiresClass;
if (toType->isExistentialType())
toRequiresClass = toType->getExistentialLayout().requiresClass();
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 24fc3de..a9fa99c 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -2593,17 +2593,8 @@
ArrayRef<VarDecl *> vars) {
// Check whether we have an Objective-C-defined class in our
// inheritance chain.
- while (classDecl) {
- // If we found an Objective-C-defined class, continue checking.
- if (classDecl->hasClangNode())
- break;
-
- // If we ran out of superclasses, we're done.
- if (!classDecl->hasSuperclass())
- return false;
-
- classDecl = classDecl->getSuperclassDecl();
- }
+ if (!classDecl->checkAncestry(AncestryFlags::ClangImported))
+ return false;
// If all of the variables are @objc, we can use @NSManaged.
for (auto var : vars) {
diff --git a/lib/Sema/TypeCheckDeclObjC.cpp b/lib/Sema/TypeCheckDeclObjC.cpp
index 6bc43f0..307ff5d 100644
--- a/lib/Sema/TypeCheckDeclObjC.cpp
+++ b/lib/Sema/TypeCheckDeclObjC.cpp
@@ -383,6 +383,21 @@
}
if (auto classDecl = ED->getSelfClassDecl()) {
+ auto *mod = value->getModuleContext();
+ auto &ctx = mod->getASTContext();
+
+ if (!ctx.LangOpts.EnableObjCResilientClassStubs) {
+ if (classDecl->checkAncestry().contains(
+ AncestryFlags::ResilientOther) ||
+ classDecl->hasResilientMetadata(mod,
+ ResilienceExpansion::Maximal)) {
+ if (diagnose) {
+ value->diagnose(diag::objc_in_resilient_extension);
+ }
+ return true;
+ }
+ }
+
if (classDecl->isGenericContext()) {
if (!classDecl->usesObjCGenericsModel()) {
if (diagnose) {
@@ -993,17 +1008,17 @@
auto classDecl = VD->getDeclContext()->getSelfClassDecl();
if (!classDecl) return false;
- return classDecl->hasObjCMembers();
+ return classDecl->checkAncestry(AncestryFlags::ObjCMembers);
}
// A class is @objc if it does not have generic ancestry, and it either has
// an explicit @objc attribute, or its superclass is @objc.
static Optional<ObjCReason> shouldMarkClassAsObjC(const ClassDecl *CD) {
ASTContext &ctx = CD->getASTContext();
- ObjCClassKind kind = CD->checkObjCAncestry();
+ auto ancestry = CD->checkAncestry();
if (auto attr = CD->getAttrs().getAttribute<ObjCAttr>()) {
- if (kind == ObjCClassKind::ObjCMembers) {
+ if (ancestry.contains(AncestryFlags::Generic)) {
if (attr->hasName() && !CD->isGenericContext()) {
// @objc with a name on a non-generic subclass of a generic class is
// just controlling the runtime name. Don't diagnose this case.
@@ -1016,9 +1031,24 @@
.fixItRemove(attr->getRangeWithAt());
}
+ // If the class has resilient ancestry, @objc just controls the runtime
+ // name unless -enable-resilient-objc-class-stubs is enabled.
+ if (ancestry.contains(AncestryFlags::ResilientOther) &&
+ !ctx.LangOpts.EnableObjCResilientClassStubs) {
+ if (attr->hasName()) {
+ const_cast<ClassDecl *>(CD)->getAttrs().add(
+ new (ctx) ObjCRuntimeNameAttr(*attr));
+ return None;
+ }
+
+ ctx.Diags.diagnose(attr->getLocation(), diag::objc_for_resilient_class)
+ .fixItRemove(attr->getRangeWithAt());
+ }
+
// Only allow ObjC-rooted classes to be @objc.
// (Leave a hole for test cases.)
- if (kind == ObjCClassKind::ObjCWithSwiftRoot) {
+ if (ancestry.contains(AncestryFlags::ObjC) &&
+ !ancestry.contains(AncestryFlags::ClangImported)) {
if (ctx.LangOpts.EnableObjCAttrRequiresFoundation)
ctx.Diags.diagnose(attr->getLocation(),
diag::invalid_objc_swift_rooted_class)
@@ -1031,9 +1061,18 @@
return ObjCReason(ObjCReason::ExplicitlyObjC);
}
- if (kind == ObjCClassKind::ObjCWithSwiftRoot ||
- kind == ObjCClassKind::ObjC)
+ if (ancestry.contains(AncestryFlags::ObjC)) {
+ if (ancestry.contains(AncestryFlags::Generic)) {
+ return None;
+ }
+
+ if (ancestry.contains(AncestryFlags::ResilientOther) &&
+ !ctx.LangOpts.EnableObjCResilientClassStubs) {
+ return None;
+ }
+
return ObjCReason(ObjCReason::ImplicitlyObjC);
+ }
return None;
}
@@ -1214,9 +1253,8 @@
if (classDecl->isForeign())
return None;
- if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC) {
+ if (classDecl->checkAncestry(AncestryFlags::ObjC))
return ObjCReason(ObjCReason::MemberOfObjCSubclass);
- }
}
return None;
diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp
index 0ca8e73..fb7a4ff 100644
--- a/lib/Sema/TypeCheckProtocol.cpp
+++ b/lib/Sema/TypeCheckProtocol.cpp
@@ -2518,8 +2518,7 @@
AccessScope requiredAccessScope = getRequiredAccessScope();
if (!TC.Context.isSwiftVersionAtLeast(5) &&
- DC->getParentModule()->getResilienceStrategy() !=
- ResilienceStrategy::Resilient) {
+ !DC->getParentModule()->isResilient()) {
// HACK: In pre-Swift-5, these typealiases were synthesized with the
// same access level as the conforming type, which might be more
// visible than the associated type witness. Preserve that behavior
@@ -4859,19 +4858,6 @@
}
}
-/// Determine whether a particular class has generic ancestry.
-static bool hasGenericAncestry(ClassDecl *classDecl) {
- SmallPtrSet<ClassDecl *, 4> visited;
- while (classDecl && visited.insert(classDecl).second) {
- if (classDecl->isGenericContext())
- return true;
-
- classDecl = classDecl->getSuperclassDecl();
- }
-
- return false;
-}
-
/// Infer the attribute tostatic-initialize the Objective-C metadata for the
/// given class, if needed.
static void inferStaticInitializeObjCMetadata(TypeChecker &tc,
@@ -4882,7 +4868,7 @@
// If we know that the Objective-C metadata will be statically registered,
// there's nothing to do.
- if (!hasGenericAncestry(classDecl)) {
+ if (!classDecl->checkAncestry(AncestryFlags::Generic)) {
return;
}
diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp
index fbc41ad..431d637 100644
--- a/lib/Serialization/ModuleFile.cpp
+++ b/lib/Serialization/ModuleFile.cpp
@@ -1455,7 +1455,7 @@
return error(Status::TargetIncompatible);
}
if (ctx.LangOpts.EnableTargetOSChecking &&
- M->getResilienceStrategy() != ResilienceStrategy::Resilient &&
+ !M->isResilient() &&
isTargetTooNew(moduleTarget, ctx.LangOpts.Target)) {
return error(Status::TargetTooNew);
}
diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp
index c649d0a..99caf81 100644
--- a/lib/TBDGen/TBDGen.cpp
+++ b/lib/TBDGen/TBDGen.cpp
@@ -343,19 +343,18 @@
visitNominalTypeDecl(CD);
- auto hasResilientAncestor =
- CD->hasResilientMetadata(SwiftModule, ResilienceExpansion::Minimal);
- auto ancestor = CD->getSuperclassDecl();
- while (ancestor && !hasResilientAncestor) {
- hasResilientAncestor |=
- ancestor->hasResilientMetadata(SwiftModule, ResilienceExpansion::Maximal);
- ancestor = ancestor->getSuperclassDecl();
- }
-
// Types with resilient superclasses have some extra symbols.
- if (hasResilientAncestor)
+ if (CD->checkAncestry(AncestryFlags::ResilientOther) ||
+ CD->hasResilientMetadata()) {
addSymbol(LinkEntity::forClassMetadataBaseOffset(CD));
+ auto &Ctx = CD->getASTContext();
+ if (Ctx.LangOpts.EnableObjCResilientClassStubs) {
+ addSymbol(LinkEntity::forObjCResilientClassStub(
+ CD, TypeMetadataAddress::AddressPoint));
+ }
+ }
+
// Emit dispatch thunks for every new vtable entry.
struct VTableVisitor : public SILVTableVisitor<VTableVisitor> {
TBDGenVisitor &TBD;
diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp
index 3c596df..4eb257d 100644
--- a/stdlib/public/runtime/Metadata.cpp
+++ b/stdlib/public/runtime/Metadata.cpp
@@ -2641,6 +2641,11 @@
return {MetadataDependency(), super};
}
+// Suppress diagnostic about the availability of _objc_realizeClassFromSwift.
+// We test availability with a nullptr check, but the compiler doesn't see that.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+
static SWIFT_CC(swift) MetadataDependency
_swift_initClassMetadataImpl(ClassMetadata *self,
ClassLayoutFlags layoutFlags,
@@ -2667,6 +2672,11 @@
(void)unused;
setUpObjCRuntimeGetImageNameFromClass();
}, nullptr);
+
+ // Temporary workaround until _objc_realizeClassFromSwift is in the SDK.
+ static auto _objc_realizeClassFromSwift =
+ (Class (*)(Class _Nullable, const void *_Nullable))
+ dlsym(RTLD_NEXT, "_objc_realizeClassFromSwift");
#endif
// Copy field offsets, generic arguments and (if necessary) vtable entries
@@ -2680,10 +2690,12 @@
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
+ auto *description = self->getDescription();
#if SWIFT_OBJC_INTEROP
- if (self->getDescription()->isGeneric())
+ if (description->isGeneric()) {
+ assert(!description->hasObjCResilientClassStub());
initGenericObjCClass(self, numFields, fieldTypes, fieldOffsets);
- else {
+ } else {
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
// Register this class with the runtime. This will also cause the
@@ -2691,13 +2703,25 @@
// globals. Note that the field offset vector is *not* updated;
// however we should not be using it for anything in a non-generic
// class.
- swift_instantiateObjCClass(self);
+ if (auto *stub = description->getObjCResilientClassStub()) {
+ if (_objc_realizeClassFromSwift == nullptr) {
+ fatalError(0, "class %s requires missing Objective-C runtime feature; "
+ "the deployment target was newer than this OS\n",
+ self->getDescription()->Name.get());
+ }
+ _objc_realizeClassFromSwift((Class) self, stub);
+ } else
+ swift_instantiateObjCClass(self);
}
+#else
+ assert(!description->hasObjCResilientClassStub());
#endif
return MetadataDependency();
}
+#pragma clang diagnostic pop
+
void swift::swift_initClassMetadata(ClassMetadata *self,
ClassLayoutFlags layoutFlags,
size_t numFields,
@@ -2737,7 +2761,7 @@
#ifndef OBJC_REALIZECLASSFROMSWIFT_DEFINED
// Temporary workaround until _objc_realizeClassFromSwift is in the SDK.
static auto _objc_realizeClassFromSwift =
- (Class (*)(Class _Nullable, void* _Nullable))
+ (Class (*)(Class _Nullable, const void *_Nullable))
dlsym(RTLD_NEXT, "_objc_realizeClassFromSwift");
#endif
diff --git a/test/Constraints/casts.swift b/test/Constraints/casts.swift
index 2483a5e..8297d03 100644
--- a/test/Constraints/casts.swift
+++ b/test/Constraints/casts.swift
@@ -111,7 +111,7 @@
_ = p1 as! P1 & P2
- _ = p2 as! S1
+ _ = p2 as! S1 // expected-warning {{cast from 'P2' to unrelated type 'S1' always fails}}
_ = p12 as! S1
_ = p12 as! S2
@@ -126,7 +126,7 @@
var _:Bool = p1 is P1 & P2
- var _:Bool = p2 is S1
+ var _:Bool = p2 is S1 // expected-warning {{cast from 'P2' to unrelated type 'S1' always fails}}
var _:Bool = p12 is S1
var _:Bool = p12 is S2
diff --git a/test/Constraints/patterns.swift b/test/Constraints/patterns.swift
index 68fc797..7b986d2 100644
--- a/test/Constraints/patterns.swift
+++ b/test/Constraints/patterns.swift
@@ -55,7 +55,7 @@
is D,
is S:
()
-case is E:
+case is E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
()
default:
()
@@ -69,7 +69,7 @@
d.d()
case let s as S:
s.s()
-case let e as E:
+case let e as E: // expected-warning {{cast from 'P' to unrelated type 'E' always fails}}
e.e()
default:
()
@@ -120,7 +120,7 @@
()
case iPadHair.HairForceOne: // expected-error{{generic enum type 'iPadHair' is ambiguous without explicit generic parameters when matching value of type 'HairType'}}
()
-case Watch.Edition: // TODO: should warn that cast can't succeed with currently known conformances
+case Watch.Edition: // expected-warning {{cast from 'HairType' to unrelated type 'Watch' always fails}}
()
case .HairForceOne: // expected-error{{type 'HairType' has no member 'HairForceOne'}}
()
diff --git a/test/Driver/fuzzer.swift b/test/Driver/fuzzer.swift
index f6aa60b..9f36c69 100644
--- a/test/Driver/fuzzer.swift
+++ b/test/Driver/fuzzer.swift
@@ -1,8 +1,11 @@
// UNSUPPORTED: windows
// UNSUPPORTED: CPU=powerpc64le
-// RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER %s
+// RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -target x86_64-apple-macosx10.9 -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER_OSX %s
+// RUN: %swiftc_driver -driver-print-jobs -sanitize=fuzzer,address -target x86_64-unknown-linux-gnu -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ %s | %FileCheck -check-prefix=LIBFUZZER_LINUX %s
-// LIBFUZZER: libclang_rt.fuzzer
+// LIBFUZZER_OSX: libclang_rt.fuzzer
+// LIBFUZZER_LINUX: -fsanitize=address,fuzzer
+
@_cdecl("LLVMFuzzerTestOneInput") public func fuzzOneInput(Data: UnsafePointer<CChar>, Size: CLong) -> CInt {
return 0;
}
diff --git a/test/Driver/sanitizers.swift b/test/Driver/sanitizers.swift
index bde9aea..1f3e91c 100644
--- a/test/Driver/sanitizers.swift
+++ b/test/Driver/sanitizers.swift
@@ -39,6 +39,10 @@
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=undefined -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=UBSAN_LINUX %s
// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=undefined -target x86_64-unknown-windows-msvc %s 2>&1 | %FileCheck -check-prefix=UBSAN_WINDOWS %s
+/*
+ * Multiple Sanitizers At Once
+ */
+// RUN: %swiftc_driver -resource-dir %S/Inputs/fake-resource-dir/lib/swift/ -driver-print-jobs -sanitize=address,undefined,fuzzer -target x86_64-unknown-linux-gnu %s 2>&1 | %FileCheck -check-prefix=MULTIPLE_SAN_LINUX %s
/*
* Bad Argument Tests
@@ -65,7 +69,7 @@
// ASAN_tvOS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.asan_tvos_dynamic.dylib
// ASAN_watchOS_SIM: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.asan_watchossim_dynamic.dylib
// ASAN_watchOS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.asan_watchos_dynamic.dylib
-// ASAN_LINUX: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.asan-x86_64.a
+// ASAN_LINUX: -fsanitize=address
// ASAN_WINDOWS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}windows{{/|\\\\}}clang_rt.asan-x86_64.lib
// ASAN: -rpath @executable_path
@@ -82,7 +86,7 @@
// TSAN_watchOS_SIM: unsupported option '-sanitize=thread' for target 'i386-apple-watchos2.0'
// TSAN_watchOS: unsupported option '-sanitize=thread' for target 'armv7k-apple-watchos2.0'
// FUZZER_NONEXISTENT: unsupported option '-sanitize=fuzzer' for target 'x86_64-apple-macosx10.9'
-// TSAN_LINUX: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.tsan-x86_64.a
+// TSAN_LINUX: -fsanitize=thread
// TSAN_WINDOWS: unsupported option '-sanitize=thread' for target 'x86_64-unknown-windows-msvc'
// TSAN: -rpath @executable_path
@@ -97,10 +101,12 @@
// UBSAN_tvOS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.ubsan_tvos_dynamic.dylib
// UBSAN_watchOS_SIM: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.ubsan_watchossim_dynamic.dylib
// UBSAN_watchOS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}darwin{{/|\\\\}}libclang_rt.ubsan_watchos_dynamic.dylib
-// UBSAN_LINUX: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}linux{{/|\\\\}}libclang_rt.ubsan-x86_64.a
+// UBSAN_LINUX: -fsanitize=undefined
// UBSAN_WINDOWS: lib{{/|\\\\}}swift{{/|\\\\}}clang{{/|\\\\}}lib{{/|\\\\}}windows{{/|\\\\}}clang_rt.ubsan-x86_64.lib
// UBSAN: -rpath @executable_path
+// MULTIPLE_SAN_LINUX: -fsanitize=address,fuzzer,undefined
+
// BADARG: unsupported argument 'unknown' to option '-sanitize='
// INCOMPATIBLESANITIZERS: argument '-sanitize=address' is not allowed with '-sanitize=thread'
diff --git a/test/IRGen/class_update_callback_with_stub.swift b/test/IRGen/class_update_callback_with_stub.swift
new file mode 100644
index 0000000..29d81ef
--- /dev/null
+++ b/test/IRGen/class_update_callback_with_stub.swift
@@ -0,0 +1,155 @@
+// RUN: %empty-directory(%t)
+// RUN: %build-irgen-test-overlays
+// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_struct.swiftmodule -I %t %S/../Inputs/resilient_struct.swift
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module-path %t/resilient_class.swiftmodule -enable-library-evolution %S/../Inputs/resilient_class.swift
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -emit-module-path %t/resilient_objc_class.swiftmodule -enable-library-evolution %S/../Inputs/resilient_objc_class.swift
+// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -I %t -emit-ir -enable-library-evolution -enable-resilient-objc-class-stubs %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime -DINT=i%target-ptrsize
+
+import Foundation
+import resilient_class
+import resilient_objc_class
+
+// REQUIRES: objc_interop
+
+// -- Nominal type descriptor for ResilientSubclass
+// the interesting part is the 'extra class flags' field has a value of 1.
+
+// CHECK-LABEL: @"$s31class_update_callback_with_stub17ResilientSubclassCMn" = constant <{
+// -- flags
+// CHECK-SAME: i32 1644232784,
+// -- parent
+// CHECK-SAME: @"$s31class_update_callback_with_stubMXM"
+// -- name
+// CHECK-SAME: @1
+// -- access function
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMa"
+// -- field descriptor
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMF"
+// -- superclass
+// CHECK-SAME: @"symbolic 15resilient_class22ResilientOutsideParentC"
+// -- metadata bounds
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMo"
+// -- extra class flags -- has Objective-C resilient class stub
+// CHECK-SAME: i32 1,
+// -- number of immediate members
+// CHECK-SAME: i32 0,
+// -- number of fields
+// CHECK-SAME: i32 0,
+// -- field offset vector offset
+// CHECK-SAME: i32 0,
+// -- resilient superclass
+// CHECK-SAME: @"got.$s15resilient_class22ResilientOutsideParentCMn"
+// -- singleton metadata initialization
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMl"
+// -- resilient class metadata pattern
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMP"
+// -- metadata completion callback
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMr"
+// -- method override
+// CHECK-SAME: @"got.$s15resilient_class22ResilientOutsideParentCMn"
+// CHECK-SAME: @"got.$s15resilient_class22ResilientOutsideParentCACycfCTq"
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCACycfC"
+// CHECK-SAME: }>, section "__TEXT,__const", align 4
+
+
+// -- Symbols for full stubs; the address point is one word in, and defined below
+
+// CHECK-LABEL: @"$s31class_update_callback_with_stub17ResilientSubclassCMt" =
+// CHECK-SAME: internal global %objc_full_class_stub {
+// CHECK-SAME: [[INT]] 0,
+// CHECK-SAME: [[INT]] 1,
+// CHECK-SAME: %objc_class* (%objc_class*, i8*)* @"$s31class_update_callback_with_stub17ResilientSubclassCMU"
+// CHECK-SAME: }
+
+// CHECK-LABEL: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMt" =
+// CHECK-SAME: internal global %objc_full_class_stub {
+// CHECK-SAME: [[INT]] 0,
+// CHECK-SAME: [[INT]] 1,
+// CHECK-SAME: %objc_class* (%objc_class*, i8*)* @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMU"
+// CHECK-SAME: }
+
+// CHECK-LABEL: @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMt" =
+// CHECK-SAME: internal global %objc_full_class_stub {
+// CHECK-SAME: [[INT]] 0,
+// CHECK-SAME: [[INT]] 1,
+// CHECK-SAME: %objc_class* (%objc_class*, i8*)* @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMU"
+// CHECK-SAME: }
+
+
+// -- Categories reference the stubs
+
+// CHECK-LABEL: @"_CATEGORY__TtC31class_update_callback_with_stub17ResilientSubclass_$_class_update_callback_with_stub" = private constant
+// CHECK-SAME: @"$s31class_update_callback_with_stub17ResilientSubclassCMs"
+
+// CHECK-LABEL: @"_CATEGORY__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass_$_class_update_callback_with_stub" = private constant
+// CHECK-SAME: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
+
+// CHECK-LABEL: @"_CATEGORY__TtC31class_update_callback_with_stub27FixedLayoutNSObjectSubclass_$_class_update_callback_with_stub" = private constant
+// CHECK-SAME: @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMs"
+
+
+// -- The NSObject-derived class appears on the class list
+
+// CHECK-LABEL: @objc_classes = internal global
+// CHECK-SAME: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
+// CHECK-SAME: @"$s31class_update_callback_with_stub27FixedLayoutNSObjectSubclassCMs"
+// CHECK-SAME: , section "__DATA,__objc_classlist,regular,no_dead_strip"
+
+
+// -- The category list
+
+// CHECK-LABEL: @objc_categories = internal global
+// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub17ResilientSubclass_$_class_update_callback_with_stub"
+// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass_$_class_update_callback_with_stub"
+// CHECK-SAME: @"_CATEGORY__TtC31class_update_callback_with_stub27FixedLayoutNSObjectSubclass_$_class_update_callback_with_stub"
+// CHECK-SAME: , section "__DATA,__objc_catlist,regular,no_dead_strip"
+
+
+// -- Address point for class stubs
+
+// CHECK: @"$s31class_update_callback_with_stub17ResilientSubclassCMs" = alias %objc_class_stub, bitcast (i8* getelementptr inbounds (i8, i8* bitcast (%objc_full_class_stub* @"$s31class_update_callback_with_stub17ResilientSubclassCMt" to i8*), [[INT]] {{4|8}}) to %objc_class_stub*)
+// CHECK: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs" = alias %objc_class_stub, bitcast (i8* getelementptr inbounds (i8, i8* bitcast (%objc_full_class_stub* @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMt" to i8*), [[INT]] {{4|8}}) to %objc_class_stub*)
+
+
+// -- Class symbol for NSObject-derived class points at the class stub
+// CHECK: @"OBJC_CLASS_$__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass" = alias %objc_class_stub, %objc_class_stub* @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
+
+
+// -- Metadata update callbacks referenced from class stubs
+
+// CHECK-LABEL: define internal %objc_class* @"$s31class_update_callback_with_stub17ResilientSubclassCMU"(%objc_class*, i8*)
+// CHECK: entry:
+// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s31class_update_callback_with_stub17ResilientSubclassCMa"([[INT]] 0)
+// CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
+// CHECK-NEXT: [[CLASS:%.*]] = bitcast %swift.type* [[METADATA]] to %objc_class*
+// CHECK-NEXT: ret %objc_class* [[CLASS]]
+// CHECK-NEXT: }
+
+// CHECK-LABEL: define internal %objc_class* @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMU"(%objc_class*, i8*)
+// CHECK: entry:
+// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMa"([[INT]] 0)
+// CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
+// CHECK-NEXT: [[CLASS:%.*]] = bitcast %swift.type* [[METADATA]] to %objc_class*
+// CHECK-NEXT: ret %objc_class* [[CLASS]]
+// CHECK-NEXT: }
+
+open class ResilientSubclass : ResilientOutsideParent {}
+open class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+
+// Note: @_fixed_layout on a class only applies to the storage layout and
+// not metadata, which remains resilient.
+
+@_fixed_layout
+open class FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+
+extension ResilientSubclass {
+ @objc public func objcMethod() {}
+}
+
+extension ResilientNSObjectSubclass {
+ @objc public func objcMethod() {}
+}
+
+extension FixedLayoutNSObjectSubclass {
+ @objc public func objcMethod() {}
+}
\ No newline at end of file
diff --git a/test/Inputs/resilient_objc_class.swift b/test/Inputs/resilient_objc_class.swift
index df95def..db1767b 100644
--- a/test/Inputs/resilient_objc_class.swift
+++ b/test/Inputs/resilient_objc_class.swift
@@ -66,3 +66,8 @@
super.classMethod()
}
}
+
+// Fixed-layout base class
+
+@_fixed_layout
+open class FixedLayoutNSObjectOutsideParent: NSObject {}
\ No newline at end of file
diff --git a/test/PrintAsObjC/Inputs/custom-modules/module.map b/test/PrintAsObjC/Inputs/custom-modules/module.map
index c1770cd..62f8359 100644
--- a/test/PrintAsObjC/Inputs/custom-modules/module.map
+++ b/test/PrintAsObjC/Inputs/custom-modules/module.map
@@ -42,3 +42,8 @@
header "VersionedFMWK.h"
export *
}
+
+module resilient_objc_class {
+ header "resilient_objc_class.h"
+ export *
+}
diff --git a/test/PrintAsObjC/resilient-ancestry.swift b/test/PrintAsObjC/resilient-ancestry.swift
new file mode 100644
index 0000000..6d95e36
--- /dev/null
+++ b/test/PrintAsObjC/resilient-ancestry.swift
@@ -0,0 +1,52 @@
+// Please keep this file in alphabetical order!
+
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/resilient_struct.swiftmodule %S/../Inputs/resilient_struct.swift -enable-library-evolution
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module-path %t/resilient_objc_class.swiftmodule %S/../Inputs/resilient_objc_class.swift -I %t -enable-library-evolution -emit-objc-header-path %t/resilient_objc_class.h
+
+// RUN: cp %S/Inputs/custom-modules/module.map %t/module.map
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -module-name resilient -emit-objc-header-path %t/resilient.h -I %t -enable-library-evolution
+// RUN: %FileCheck %s --check-prefix=NO-STUBS < %t/resilient.h
+// RUN: %check-in-clang %t/resilient.h -I %t
+
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s -module-name resilient -emit-objc-header-path %t/resilient.h -I %t -enable-library-evolution -enable-resilient-objc-class-stubs
+// RUN: %FileCheck %s < %t/resilient.h
+// RUN: %check-in-clang %t/resilient.h -I %t
+
+// REQUIRES: objc_interop
+
+import Foundation
+import resilient_objc_class
+
+// Note: @_fixed_layout on a class only applies to the storage layout and
+// not metadata, which remains resilient.
+
+// NO-STUBS-NOT: FixedLayoutNSObjectSubclass
+
+// CHECK-LABEL: SWIFT_RESILIENT_CLASS("_TtC9resilient27FixedLayoutNSObjectSubclass")
+// CHECK-NEXT: @interface FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent
+// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
+// CHECK-NEXT: @end
+
+@_fixed_layout
+public class FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+
+// NO-STUBS-NOT: ResilientNSObjectSubclass
+
+// CHECK-LABEL: SWIFT_RESILIENT_CLASS("_TtC9resilient25ResilientNSObjectSubclass")
+// CHECK-NEXT: @interface ResilientNSObjectSubclass : ResilientNSObjectOutsideParent
+// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
+// CHECK-NEXT: @end
+
+public class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+
+// NO-STUBS-NOT: RenamedNSObjectSubclass
+
+// CHECK-LABEL: SWIFT_RESILIENT_CLASS_NAMED("UnrenamedNSObjectSubclass")
+// CHECK-NEXT: @interface RenamedNSObjectSubclass : ResilientNSObjectOutsideParent
+// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
+// CHECK-NEXT: @end
+
+@objc(RenamedNSObjectSubclass)
+public class UnrenamedNSObjectSubclass : ResilientNSObjectOutsideParent {}
diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift
index e3160fe..4516b2a 100644
--- a/test/attr/attr_objc.swift
+++ b/test/attr/attr_objc.swift
@@ -193,9 +193,9 @@
}
extension subject_genericClass {
- @objc var extProp: Int { return 0 } // expected-error{{members of extensions of generic classes cannot be declared @objc}}
+ @objc var extProp: Int { return 0 } // expected-error{{extensions of generic classes cannot contain '@objc' members}}
- @objc func extFoo() {} // expected-error{{members of extensions of generic classes cannot be declared @objc}}
+ @objc func extFoo() {} // expected-error{{extensions of generic classes cannot contain '@objc' members}}
}
@objc
diff --git a/test/attr/attr_objc_resilience.swift b/test/attr/attr_objc_resilience.swift
new file mode 100644
index 0000000..22829b6
--- /dev/null
+++ b/test/attr/attr_objc_resilience.swift
@@ -0,0 +1,44 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/resilient_struct.swiftmodule %S/../Inputs/resilient_struct.swift -enable-library-evolution
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module-path %t/resilient_objc_class.swiftmodule %S/../Inputs/resilient_objc_class.swift -I %t -enable-library-evolution
+// RUN: %target-swift-frontend -typecheck -verify %s -I %t
+
+// REQUIRES: objc_interop
+
+import Foundation
+import resilient_objc_class
+
+@objc public class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+// expected-error@-1 {{classes built with library evolution support cannot have explicit '@objc' subclasses because they are not directly visible from Objective-C}}
+
+public class AnotherResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+
+extension ResilientNSObjectOutsideParent {
+ @objc public func categoryOneMethod() {}
+ // expected-error@-1 {{extensions of classes built with library evolution support cannot contain '@objc' members}}
+}
+
+extension AnotherResilientNSObjectSubclass {
+ @objc public func categoryTwoMethod() {}
+ // expected-error@-1 {{extensions of classes built with library evolution support cannot contain '@objc' members}}
+}
+
+// Note: @_fixed_layout on a class only applies to the storage layout and
+// not metadata, which remains resilient.
+
+@_fixed_layout
+@objc public class FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+// expected-error@-1 {{classes built with library evolution support cannot have explicit '@objc' subclasses because they are not directly visible from Objective-C}}
+
+@_fixed_layout
+public class AnotherFixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+
+extension FixedLayoutNSObjectOutsideParent {
+ @objc public func categoryOneMethod() {}
+ // expected-error@-1 {{extensions of classes built with library evolution support cannot contain '@objc' members}}
+}
+
+extension AnotherFixedLayoutNSObjectSubclass {
+ @objc public func categoryTwoMethod() {}
+ // expected-error@-1 {{extensions of classes built with library evolution support cannot contain '@objc' members}}
+}
diff --git a/test/attr/attr_objc_resilient_stubs.swift b/test/attr/attr_objc_resilient_stubs.swift
new file mode 100644
index 0000000..7831a8e
--- /dev/null
+++ b/test/attr/attr_objc_resilient_stubs.swift
@@ -0,0 +1,41 @@
+// RUN: %empty-directory(%t)
+// RUN: %target-swift-frontend -emit-module-path %t/resilient_struct.swiftmodule %S/../Inputs/resilient_struct.swift -enable-library-evolution
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module-path %t/resilient_objc_class.swiftmodule %S/../Inputs/resilient_objc_class.swift -I %t -enable-library-evolution -enable-resilient-objc-class-stubs
+// RUN: %target-swift-frontend -typecheck -verify %s -I %t -enable-resilient-objc-class-stubs
+
+// REQUIRES: objc_interop
+
+import Foundation
+import resilient_objc_class
+
+// When built with -enable-resilient-objc-class-stubs, all of these cases are
+// allowed.
+
+@objc public class ResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+
+public class AnotherResilientNSObjectSubclass : ResilientNSObjectOutsideParent {}
+
+extension ResilientNSObjectOutsideParent {
+ @objc public func categoryOneMethod() {}
+}
+
+extension AnotherResilientNSObjectSubclass {
+ @objc public func categoryTwoMethod() {}
+}
+
+// Note: @_fixed_layout on a class only applies to the storage layout and
+// not metadata, which remains resilient.
+
+@_fixed_layout
+@objc public class FixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+
+@_fixed_layout
+public class AnotherFixedLayoutNSObjectSubclass : FixedLayoutNSObjectOutsideParent {}
+
+extension FixedLayoutNSObjectOutsideParent {
+ @objc public func categoryOneMethod() {}
+}
+
+extension AnotherFixedLayoutNSObjectSubclass {
+ @objc public func categoryTwoMethod() {}
+}
diff --git a/test/decl/ext/extension-generic-objc.swift b/test/decl/ext/extension-generic-objc.swift
index c1bbe42..68e924f 100644
--- a/test/decl/ext/extension-generic-objc.swift
+++ b/test/decl/ext/extension-generic-objc.swift
@@ -15,7 +15,7 @@
}
extension A {
// This should throw an error
- @objc func a1() {} // expected-error{{members of extensions of generic classes cannot be declared @objc}}
+ @objc func a1() {} // expected-error{{extensions of generic classes cannot contain '@objc' members}}
// This should *not* throw an error
func a2() {}
}
@@ -51,6 +51,6 @@
extension Outer.Inner {
@objc func outerInner1() {}
- // expected-error@-1{{members of extensions of classes from generic context cannot be declared @objc}}
+ // expected-error@-1{{extensions of classes from generic context cannot contain '@objc' members}}
func outerInner2() {}
}
diff --git a/test/lit.cfg b/test/lit.cfg
index 2001a57..af9e9ee 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -1057,8 +1057,7 @@
tools_directory,
'-L%s' % make_path(test_resource_dir, config.target_sdk_name)])
# The Swift interpreter is not available when targeting Android.
- if 'swift_interpreter' in config.available_features:
- config.available_features.remove('swift_interpreter')
+ config.available_features.discard('swift_interpreter')
else:
lit_config.fatal("Don't know how to define target_run and "
@@ -1500,7 +1499,7 @@
config.available_features.add('libdispatch')
else:
# TSan runtime requires libdispatch on non-Apple platforms
- config.available_features.remove('tsan_runtime')
+ config.available_features.discard('tsan_runtime')
if has_lib('Foundation'):
config.available_features.add('foundation')
diff --git a/test/stmt/errors.swift b/test/stmt/errors.swift
index b632132..6799b8f 100644
--- a/test/stmt/errors.swift
+++ b/test/stmt/errors.swift
@@ -165,3 +165,61 @@
}
}
}
+
+// SR 6400
+
+enum SR_6400_E: Error {
+ case castError
+}
+
+struct SR_6400_S_1 {}
+struct SR_6400_S_2: Error {}
+
+protocol SR_6400_FakeApplicationDelegate: AnyObject {}
+class SR_6400_FakeViewController {}
+
+func sr_6400() throws {
+ do {
+ throw SR_6400_E.castError
+ } catch is SR_6400_S_1 { // expected-warning {{cast from 'Error' to unrelated type 'SR_6400_S_1' always fails}}
+ print("Caught error")
+ }
+
+ do {
+ throw SR_6400_E.castError
+ } catch is SR_6400_S_2 {
+ print("Caught error") // Ok
+ }
+}
+
+func sr_6400_1<T>(error: Error, as type: T.Type) -> Bool {
+ return (error as? T) != nil // Ok
+}
+
+func sr_6400_2(error: Error) {
+ _ = error as? (SR_6400_FakeViewController & Error) // Ok
+}
+func sr_6400_3(error: Error) {
+ _ = error as? (Error & SR_6400_FakeApplicationDelegate) // Ok
+}
+
+class SR_6400_A {}
+class SR_6400_B: SR_6400_FakeApplicationDelegate & Error {}
+
+func sr_6400_4() {
+ do {
+ throw SR_6400_E.castError
+ } catch let error as SR_6400_A { // expected-warning {{cast from 'Error' to unrelated type 'SR_6400_A' always fails}} // expected-warning {{immutable value 'error' was never used; consider replacing with '_' or removing it}}
+ print("Foo")
+ } catch {
+ print("Bar")
+ }
+
+ do {
+ throw SR_6400_E.castError
+ } catch let error as SR_6400_B { // expected-warning {{immutable value 'error' was never used; consider replacing with '_' or removing it}}
+ print("Foo")
+ } catch {
+ print("Bar")
+ }
+}
diff --git a/tools/SourceKit/CMakeLists.txt b/tools/SourceKit/CMakeLists.txt
index 31e808f..b7455d3 100644
--- a/tools/SourceKit/CMakeLists.txt
+++ b/tools/SourceKit/CMakeLists.txt
@@ -13,15 +13,16 @@
get_target_property(CLANG_LOCATION clang LOCATION)
get_filename_component(CLANG_LOCATION ${CLANG_LOCATION} DIRECTORY)
- if(CMAKE_C_COMPILER_ID STREQUAL MSVC OR CMAKE_C_SIMULATE_ID STREQUAL MSVC)
- set(CMAKE_C_COMPILER_ID
+ if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC" OR
+ "${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")
+ set(CMAKE_C_COMPILER
${CLANG_LOCATION}/clang-cl${CMAKE_EXECUTABLE_SUFFIX})
- set(CMAKE_CXX_COMPILER_ID
+ set(CMAKE_CXX_COMPILER
${CLANG_LOCATION}/clang-cl${CMAKE_EXECUTABLE_SUFFIX})
else()
- set(CMAKE_C_COMPILER_ID
+ set(CMAKE_C_COMPILER
${CLANG_LOCATION}/clang${CMAKE_EXECUTABLE_SUFFIX})
- set(CMAKE_CXX_COMPILER_ID
+ set(CMAKE_CXX_COMPILER
${CLANG_LOCATION}/clang++${CMAKE_EXECUTABLE_SUFFIX})
endif()
else()