Skip to content

Commit 04775d4

Browse files
authored
Merge pull request #38419 from beccadax/the-generic-bound-is-cheaper
[IRGen] Fix crashes involving ObjC generic params
2 parents 20e924e + 70d120b commit 04775d4

19 files changed

+214
-53
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3979,7 +3979,7 @@ class ClassDecl final : public NominalTypeDecl {
39793979
/// Returns true if the decl uses the Objective-C generics model.
39803980
///
39813981
/// This is true of imported Objective-C classes.
3982-
bool usesObjCGenericsModel() const {
3982+
bool isTypeErasedGenericClass() const {
39833983
return hasClangNode() && isGenericContext() && isObjC();
39843984
}
39853985

lib/AST/Decl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,7 +2925,8 @@ bool ValueDecl::isObjCDynamicInGenericClass() const {
29252925
if (!classDecl)
29262926
return false;
29272927

2928-
return classDecl->isGenericContext() && !classDecl->usesObjCGenericsModel();
2928+
return classDecl->isGenericContext()
2929+
&& !classDecl->isTypeErasedGenericClass();
29292930
}
29302931

29312932
bool ValueDecl::shouldUseObjCMethodReplacement() const {
@@ -4196,7 +4197,7 @@ bool NominalTypeDecl::isTypeErasedGenericClass() const {
41964197
// ObjC classes are type erased.
41974198
// TODO: Unless they have magic methods...
41984199
if (auto clas = dyn_cast<ClassDecl>(this))
4199-
return clas->hasClangNode() && clas->isGenericContext();
4200+
return clas->isTypeErasedGenericClass();
42004201
return false;
42014202
}
42024203

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3003,7 +3003,8 @@ Type ArchetypeType::getExistentialType() const {
30033003
constraintTypes.push_back(proto->getDeclaredInterfaceType());
30043004
}
30053005
return ProtocolCompositionType::get(
3006-
const_cast<ArchetypeType*>(this)->getASTContext(), constraintTypes, false);
3006+
const_cast<ArchetypeType*>(this)->getASTContext(), constraintTypes,
3007+
requiresClass());
30073008
}
30083009

30093010
PrimaryArchetypeType::PrimaryArchetypeType(const ASTContext &Ctx,

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ llvm::cl::opt<bool> UseBasicDynamicReplacement(
8585
llvm::cl::desc("Basic implementation of dynamic replacement"));
8686

8787
namespace {
88-
88+
8989
/// Add methods, properties, and protocol conformances from a JITed extension
9090
/// to an ObjC class using the ObjC runtime.
9191
///
@@ -119,8 +119,8 @@ class CategoryInitializerVisitor
119119
/*allow uninitialized*/ false);
120120
classMetadata = Builder.CreateBitCast(classMetadata, IGM.ObjCClassPtrTy);
121121
metaclassMetadata = IGM.getAddrOfMetaclassObject(
122-
origTy.getClassOrBoundGenericClass(),
123-
NotForDefinition);
122+
dyn_cast_or_null<ClassDecl>(origTy->getAnyNominal()),
123+
NotForDefinition);
124124
metaclassMetadata = llvm::ConstantExpr::getBitCast(metaclassMetadata,
125125
IGM.ObjCClassPtrTy);
126126

lib/IRGen/GenProto.cpp

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,10 @@ class PolymorphicConvention {
134134

135135
private:
136136
void initGenerics();
137-
void considerNewTypeSource(MetadataSource::Kind kind, unsigned paramIndex,
138-
CanType type, IsExact_t isExact);
137+
138+
template <typename ...Args>
139+
void considerNewTypeSource(IsExact_t isExact, MetadataSource::Kind kind,
140+
CanType type, Args... args);
139141
bool considerType(CanType type, IsExact_t isExact,
140142
unsigned sourceIndex, MetadataPath &&path);
141143

@@ -234,12 +236,17 @@ PolymorphicConvention::PolymorphicConvention(IRGenModule &IGM,
234236

235237
void PolymorphicConvention::addPseudogenericFulfillments() {
236238
enumerateRequirements([&](GenericRequirement reqt) {
237-
MetadataPath path;
238-
path.addImpossibleComponent();
239+
auto archetype = Generics->getGenericEnvironment()
240+
->mapTypeIntoContext(reqt.TypeParameter)
241+
->getAs<ArchetypeType>();
242+
assert(archetype && "did not get an archetype by mapping param?");
243+
auto erasedTypeParam = archetype->getExistentialType()->getCanonicalType();
244+
Sources.emplace_back(MetadataSource::Kind::ErasedTypeMetadata,
245+
reqt.TypeParameter, erasedTypeParam);
239246

240-
unsigned sourceIndex = 0; // unimportant, since impossible
247+
MetadataPath path;
241248
Fulfillments.addFulfillment({reqt.TypeParameter, reqt.Protocol},
242-
sourceIndex, std::move(path),
249+
Sources.size() - 1, std::move(path),
243250
MetadataState::Complete);
244251
});
245252
}
@@ -302,14 +309,15 @@ void PolymorphicConvention::initGenerics() {
302309
Generics = FnType->getInvocationGenericSignature();
303310
}
304311

305-
void PolymorphicConvention::considerNewTypeSource(MetadataSource::Kind kind,
306-
unsigned paramIndex,
312+
template <typename ...Args>
313+
void PolymorphicConvention::considerNewTypeSource(IsExact_t isExact,
314+
MetadataSource::Kind kind,
307315
CanType type,
308-
IsExact_t isExact) {
316+
Args... args) {
309317
if (!Fulfillments.isInterestingTypeForFulfillments(type)) return;
310318

311319
// Prospectively add a source.
312-
Sources.emplace_back(kind, paramIndex, type);
320+
Sources.emplace_back(kind, type, std::forward<Args>(args)...);
313321

314322
// Consider the source.
315323
if (!considerType(type, isExact, Sources.size() - 1, MetadataPath())) {
@@ -333,9 +341,7 @@ void PolymorphicConvention::considerWitnessSelf(CanSILFunctionType fnType) {
333341
auto conformance = fnType->getWitnessMethodConformanceOrInvalid();
334342

335343
// First, bind type metadata for Self.
336-
Sources.emplace_back(MetadataSource::Kind::SelfMetadata,
337-
MetadataSource::InvalidSourceIndex,
338-
selfTy);
344+
Sources.emplace_back(MetadataSource::Kind::SelfMetadata, selfTy);
339345

340346
if (selfTy->is<GenericTypeParamType>()) {
341347
// The Self type is abstract, so we can fulfill its metadata from
@@ -347,8 +353,7 @@ void PolymorphicConvention::considerWitnessSelf(CanSILFunctionType fnType) {
347353

348354
// The witness table for the Self : P conformance can be
349355
// fulfilled from the Self witness table parameter.
350-
Sources.emplace_back(MetadataSource::Kind::SelfWitnessTable,
351-
MetadataSource::InvalidSourceIndex, selfTy);
356+
Sources.emplace_back(MetadataSource::Kind::SelfWitnessTable, selfTy);
352357
addSelfWitnessTableFulfillment(selfTy, conformance);
353358
}
354359

@@ -359,8 +364,7 @@ void PolymorphicConvention::considerObjCGenericSelf(CanSILFunctionType fnType) {
359364
unsigned paramIndex = fnType->getParameters().size() - 1;
360365

361366
// Bind type metadata for Self.
362-
Sources.emplace_back(MetadataSource::Kind::ClassPointer, paramIndex,
363-
selfTy);
367+
Sources.emplace_back(MetadataSource::Kind::ClassPointer, selfTy, paramIndex);
364368

365369
if (isa<GenericTypeParamType>(selfTy))
366370
addSelfMetadataFulfillment(selfTy);
@@ -385,8 +389,9 @@ void PolymorphicConvention::considerParameter(SILParameterInfo param,
385389
case ParameterConvention::Indirect_InoutAliasable:
386390
if (!isSelfParameter) return;
387391
if (type->getNominalOrBoundGenericNominal()) {
388-
considerNewTypeSource(MetadataSource::Kind::GenericLValueMetadata,
389-
paramIndex, type, IsExact);
392+
considerNewTypeSource(IsExact,
393+
MetadataSource::Kind::GenericLValueMetadata,
394+
type, paramIndex);
390395
}
391396
return;
392397

@@ -395,15 +400,15 @@ void PolymorphicConvention::considerParameter(SILParameterInfo param,
395400
case ParameterConvention::Direct_Guaranteed:
396401
// Classes are sources of metadata.
397402
if (type->getClassOrBoundGenericClass()) {
398-
considerNewTypeSource(MetadataSource::Kind::ClassPointer,
399-
paramIndex, type, IsInexact);
403+
considerNewTypeSource(IsInexact, MetadataSource::Kind::ClassPointer,
404+
type, paramIndex);
400405
return;
401406
}
402407

403408
if (isa<GenericTypeParamType>(type)) {
404409
if (auto superclassTy = getSuperclassBound(type)) {
405-
considerNewTypeSource(MetadataSource::Kind::ClassPointer,
406-
paramIndex, superclassTy, IsInexact);
410+
considerNewTypeSource(IsInexact, MetadataSource::Kind::ClassPointer,
411+
superclassTy, paramIndex);
407412
return;
408413

409414
}
@@ -418,11 +423,11 @@ void PolymorphicConvention::considerParameter(SILParameterInfo param,
418423
// sources of metadata.
419424
CanType objTy = metatypeTy.getInstanceType();
420425
if (auto classDecl = objTy->getClassOrBoundGenericClass())
421-
if (classDecl->usesObjCGenericsModel())
426+
if (classDecl->isTypeErasedGenericClass())
422427
return;
423428

424-
considerNewTypeSource(MetadataSource::Kind::Metadata,
425-
paramIndex, objTy, IsInexact);
429+
considerNewTypeSource(IsInexact, MetadataSource::Kind::Metadata, objTy,
430+
paramIndex);
426431
return;
427432
}
428433

@@ -599,6 +604,17 @@ void EmitPolymorphicParameters::bindExtraSource(
599604
}
600605
return;
601606
}
607+
608+
case MetadataSource::Kind::ErasedTypeMetadata: {
609+
ArtificialLocation Loc(IGF.getDebugScope(), IGF.IGM.DebugInfo.get(),
610+
IGF.Builder);
611+
CanType argTy = getTypeInContext(source.Type);
612+
llvm::Value *metadata = IGF.emitTypeMetadataRef(source.getFixedType());
613+
setTypeMetadataName(IGF.IGM, metadata, argTy);
614+
IGF.bindLocalTypeDataFromTypeMetadata(argTy, IsExact, metadata,
615+
MetadataState::Complete);
616+
return;
617+
}
602618
}
603619
llvm_unreachable("bad source kind!");
604620
}
@@ -2986,6 +3002,10 @@ namespace {
29863002
case MetadataSource::Kind::SelfMetadata:
29873003
case MetadataSource::Kind::SelfWitnessTable:
29883004
continue;
3005+
3006+
// No influence on the arguments.
3007+
case MetadataSource::Kind::ErasedTypeMetadata:
3008+
continue;
29893009
}
29903010
llvm_unreachable("bad source kind!");
29913011
}
@@ -3040,6 +3060,10 @@ void EmitPolymorphicArguments::emit(SubstitutionMap subs,
30403060
// Added later.
30413061
continue;
30423062
}
3063+
3064+
case MetadataSource::Kind::ErasedTypeMetadata:
3065+
// No influence on the arguments.
3066+
continue;
30433067
}
30443068
llvm_unreachable("bad source kind");
30453069
}
@@ -3098,6 +3122,10 @@ NecessaryBindings NecessaryBindings::computeBindings(
30983122
case MetadataSource::Kind::SelfWitnessTable:
30993123
// We'll just pass undef in cases like this.
31003124
continue;
3125+
3126+
case MetadataSource::Kind::ErasedTypeMetadata:
3127+
// Fixed in the body.
3128+
continue;
31013129
}
31023130
llvm_unreachable("bad source kind");
31033131
}
@@ -3320,6 +3348,8 @@ namespace {
33203348
case MetadataSource::Kind::SelfMetadata:
33213349
case MetadataSource::Kind::SelfWitnessTable:
33223350
return; // handled as a special case in expand()
3351+
case MetadataSource::Kind::ErasedTypeMetadata:
3352+
return; // fixed in the body
33233353
}
33243354
llvm_unreachable("bad source kind");
33253355
}

lib/IRGen/GenProto.h

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ namespace irgen {
197197
/// Metadata is derived from the Self witness table parameter
198198
/// passed via the WitnessMethod convention.
199199
SelfWitnessTable,
200+
201+
/// Metadata is obtained directly from the FixedType indicated. Used with
202+
/// Objective-C generics, where the actual argument is erased at runtime
203+
/// and its existential bound is used instead.
204+
ErasedTypeMetadata,
200205
};
201206

202207
static bool requiresSourceIndex(Kind kind) {
@@ -205,28 +210,56 @@ namespace irgen {
205210
kind == Kind::GenericLValueMetadata);
206211
}
207212

213+
static bool requiresFixedType(Kind kind) {
214+
return (kind == Kind::ErasedTypeMetadata);
215+
}
216+
208217
enum : unsigned { InvalidSourceIndex = ~0U };
209218

210219
private:
211220
/// The kind of source this is.
212221
Kind TheKind;
213222

214-
/// The parameter index, for ClassPointer and Metadata sources.
215-
unsigned Index;
223+
/// For ClassPointer, Metadata, and GenericLValueMetadata, the source index;
224+
/// for ErasedTypeMetadata, the type; for others, Index should be set to
225+
/// InvalidSourceIndex.
226+
union {
227+
unsigned Index;
228+
CanType FixedType;
229+
};
216230

217231
public:
218232
CanType Type;
219233

220-
MetadataSource(Kind kind, unsigned index, CanType type)
234+
MetadataSource(Kind kind, CanType type)
235+
: TheKind(kind), Index(InvalidSourceIndex), Type(type)
236+
{
237+
assert(!requiresSourceIndex(kind) && !requiresFixedType(kind));
238+
}
239+
240+
241+
MetadataSource(Kind kind, CanType type, unsigned index)
221242
: TheKind(kind), Index(index), Type(type) {
222-
assert(index != InvalidSourceIndex || !requiresSourceIndex(kind));
243+
assert(requiresSourceIndex(kind));
244+
assert(index != InvalidSourceIndex);
245+
}
246+
247+
MetadataSource(Kind kind, CanType type, CanType fixedType)
248+
: TheKind(kind), FixedType(fixedType), Type(type) {
249+
assert(requiresFixedType(kind));
223250
}
224251

225252
Kind getKind() const { return TheKind; }
253+
226254
unsigned getParamIndex() const {
227255
assert(requiresSourceIndex(getKind()));
228256
return Index;
229257
}
258+
259+
CanType getFixedType() const {
260+
assert(requiresFixedType(getKind()));
261+
return FixedType;
262+
}
230263
};
231264

232265
using GenericParamFulfillmentCallback =

lib/IRGen/GenReflection.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ class CaptureDescriptorBuilder : public ReflectionMetadataBuilder {
11181118
case irgen::MetadataSource::Kind::Metadata:
11191119
Root = SourceBuilder.createMetadataCapture(Source.getParamIndex());
11201120
break;
1121+
1122+
case irgen::MetadataSource::Kind::ErasedTypeMetadata:
1123+
// Fixed in the function body
1124+
break;
11211125
}
11221126

11231127
// The metadata might be reached via a non-trivial path (eg,

lib/IRGen/MetadataRequest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,7 +3411,7 @@ llvm::Value *irgen::emitClassHeapMetadataRef(IRGenFunction &IGF, CanType type,
34113411
bool allowUninitialized) {
34123412
assert(request.canResponseStatusBeIgnored() &&
34133413
"emitClassHeapMetadataRef only supports satisfied requests");
3414-
assert(type->mayHaveSuperclass());
3414+
assert(type->mayHaveSuperclass() || type->isTypeErasedGenericClassType());
34153415

34163416
// Archetypes may or may not be ObjC classes and need unwrapping to get at
34173417
// the class object.
@@ -3426,7 +3426,7 @@ llvm::Value *irgen::emitClassHeapMetadataRef(IRGenFunction &IGF, CanType type,
34263426
return classPtr;
34273427
}
34283428

3429-
if (ClassDecl *theClass = type->getClassOrBoundGenericClass()) {
3429+
if (ClassDecl *theClass = dyn_cast_or_null<ClassDecl>(type->getAnyNominal())) {
34303430
if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) {
34313431
llvm::Value *result =
34323432
emitObjCHeapMetadataRef(IGF, theClass, allowUninitialized);

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,7 @@ static bool isPseudogeneric(SILDeclRef c) {
17661766
if (!dc) return false;
17671767

17681768
auto classDecl = dc->getSelfClassDecl();
1769-
return (classDecl && classDecl->usesObjCGenericsModel());
1769+
return (classDecl && classDecl->isTypeErasedGenericClass());
17701770
}
17711771

17721772
/// Update the result type given the foreign error convention that we will be

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -603,12 +603,12 @@ swift::classifyDynamicCast(ModuleDecl *M,
603603
if (targetClass) {
604604
// Imported Objective-C generics don't check the generic parameters, which
605605
// are lost at runtime.
606-
if (sourceClass->usesObjCGenericsModel()) {
606+
if (sourceClass->isTypeErasedGenericClass()) {
607607

608608
if (sourceClass == targetClass)
609609
return DynamicCastFeasibility::WillSucceed;
610610

611-
if (targetClass->usesObjCGenericsModel()) {
611+
if (targetClass->isTypeErasedGenericClass()) {
612612
// If both classes are ObjC generics, the cast may succeed if the
613613
// classes are related, irrespective of their generic parameters.
614614

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,7 +4030,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
40304030
require(instClass,
40314031
"upcast must convert a class metatype to a class metatype");
40324032

4033-
if (instClass->usesObjCGenericsModel()) {
4033+
if (instClass->isTypeErasedGenericClass()) {
40344034
require(instClass->getDeclaredTypeInContext()
40354035
->isBindableToSuperclassOf(opInstTy),
40364036
"upcast must cast to a superclass or an existential metatype");
@@ -4063,7 +4063,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
40634063
auto ToClass = ToTy.getClassOrBoundGenericClass();
40644064
require(ToClass,
40654065
"upcast must convert a class instance to a class type");
4066-
if (ToClass->usesObjCGenericsModel()) {
4066+
if (ToClass->isTypeErasedGenericClass()) {
40674067
require(ToClass->getDeclaredTypeInContext()
40684068
->isBindableToSuperclassOf(FromTy.getASTType()),
40694069
"upcast must cast to a superclass or an existential metatype");

0 commit comments

Comments
 (0)