Skip to content

Commit 14f48dc

Browse files
committed
[IRGen] Fix crashes involving ObjC generic params
Sema allows you to pass type-pinning parameters into an extension of an Objective-C generic class, but IRGen did not properly handle erasing these types to existential types in runtime metadata. This commit corrects that mistake.
1 parent 48f2453 commit 14f48dc

File tree

6 files changed

+120
-9
lines changed

6 files changed

+120
-9
lines changed

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/GenProto.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,17 @@ PolymorphicConvention::PolymorphicConvention(IRGenModule &IGM,
236236

237237
void PolymorphicConvention::addPseudogenericFulfillments() {
238238
enumerateRequirements([&](GenericRequirement reqt) {
239-
MetadataPath path;
240-
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);
241246

242-
unsigned sourceIndex = 0; // unimportant, since impossible
247+
MetadataPath path;
243248
Fulfillments.addFulfillment({reqt.TypeParameter, reqt.Protocol},
244-
sourceIndex, std::move(path),
249+
Sources.size() - 1, std::move(path),
245250
MetadataState::Complete);
246251
});
247252
}
@@ -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: 27 additions & 3 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,22 +210,31 @@ 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

220234
MetadataSource(Kind kind, CanType type)
221235
: TheKind(kind), Index(InvalidSourceIndex), Type(type)
222236
{
223-
assert(!requiresSourceIndex(kind));
237+
assert(!requiresSourceIndex(kind) && !requiresFixedType(kind));
224238
}
225239

226240

@@ -230,12 +244,22 @@ namespace irgen {
230244
assert(index != InvalidSourceIndex);
231245
}
232246

247+
MetadataSource(Kind kind, CanType type, CanType fixedType)
248+
: TheKind(kind), FixedType(fixedType), Type(type) {
249+
assert(requiresFixedType(kind));
250+
}
251+
233252
Kind getKind() const { return TheKind; }
234253

235254
unsigned getParamIndex() const {
236255
assert(requiresSourceIndex(getKind()));
237256
return Index;
238257
}
258+
259+
CanType getFixedType() const {
260+
assert(requiresFixedType(getKind()));
261+
return FixedType;
262+
}
239263
};
240264

241265
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,

test/IRGen/Inputs/usr/include/Gizmo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,6 @@ __attribute__((swift_name("OuterType.InnerType")))
166166

167167
@interface ObjcGenericClass<__covariant SectionType>
168168
@end
169+
170+
@interface FungingArray <Element: id<NSFunging>> : NSObject
171+
@end

test/IRGen/objc_extensions.swift

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %build-irgen-test-overlays
33
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -disable-objc-attr-requires-foundation-module -emit-module %S/Inputs/objc_extension_base.swift -o %t
4-
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | %FileCheck %s
4+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir -g | %FileCheck %s
55

66
// REQUIRES: CPU=x86_64
77
// REQUIRES: objc_interop
@@ -195,3 +195,52 @@ class SwiftSubGizmo : SwiftBaseGizmo {
195195
}
196196
}
197197

198+
@inline(never) func opaquePrint(_ value: Any) { print(value) }
199+
200+
/*
201+
* Check that we can extend ObjC generics and use both the type and metatype of
202+
* the generic parameter. Specifically, we're checking that we emit debug info
203+
* if we look up the existential bound, and that we derive the argument to
204+
* `opaquePrint(_:)` from the actual parameter, not just the fixed metadata.
205+
*/
206+
extension FungingArray {
207+
// CHECK-LABEL: define {{.*}} @"$sSo12FungingArrayC15objc_extensionsEyAByxGxcfC"
208+
// CHECK-SAME: (%objc_object* %0, %swift.type* swiftself %1)
209+
// CHECK: @__swift_instantiateConcreteTypeFromMangledName{{.*}}@"$sSo9NSFunging_XlMD"{{.*}}!dbg
210+
211+
// CHECK-LABEL: define {{.*}} @"$sSo12FungingArrayC15objc_extensionsEyAByxGxcfc"
212+
// CHECK-SAME: (%objc_object* %0, %TSo12FungingArrayC* swiftself %1)
213+
// CHECK: [[ALLOCA:%[^, =]+]] = alloca %Any, align 8
214+
// CHECK: @__swift_instantiateConcreteTypeFromMangledName{{.*}}@"$sSo9NSFunging_XlMD"{{.*}}!dbg
215+
// CHECK: {{%[^, =]+}} = getelementptr inbounds %Any, %Any* [[ALLOCA]], i32 0, i32 0
216+
// CHECK: [[ANYBUF:%[^, =]+]] = getelementptr inbounds %Any, %Any* [[ALLOCA]], i32 0, i32 0
217+
// CHECK: [[BUFPTR:%[^, =]+]] = {{.*}} [[ANYBUF]]
218+
// CHECK: [[BUF_0:%[^, =]+]] = {{.*}} [[BUFPTR]]
219+
// CHECK: store {{.*}} %0, {{.*}} [[BUF_0]]
220+
// CHECK: call swiftcc void @"$s15objc_extensions11opaquePrintyyypF"(%Any* {{.*}} [[ALLOCA]])
221+
@objc public convenience init(_ elem: Element) {
222+
opaquePrint(elem)
223+
self.init()
224+
}
225+
226+
// CHECK-LABEL: define {{.*}} @"$sSo12FungingArrayC15objc_extensionsE7pinningAByxGxm_tcfC"
227+
// CHECK-SAME: (%swift.type* %0, %swift.type* swiftself %1)
228+
// CHECK: @__swift_instantiateConcreteTypeFromMangledName{{.*}}@"$sSo9NSFunging_XlMD"{{.*}}!dbg
229+
230+
// CHECK-LABEL: define {{.*}} @"$sSo12FungingArrayC15objc_extensionsE7pinningAByxGxm_tcfc"
231+
// CHECK-SAME: (%swift.type* %0, %TSo12FungingArrayC* swiftself %1)
232+
// CHECK: [[ALLOCA:%[^, =]+]] = alloca %Any, align 8
233+
// CHECK: @__swift_instantiateConcreteTypeFromMangledName{{.*}}@"$sSo9NSFunging_XlMD"{{.*}}!dbg
234+
// CHECK: [[OBJC_CLASS:%[^, =]+]] = call %objc_class* @swift_getObjCClassFromMetadata(%swift.type* %0)
235+
// CHECK: [[OBJC_CLASS_OBJ:%[^, =]+]] = bitcast %objc_class* [[OBJC_CLASS]]
236+
// CHECK: {{%[^, =]+}} = getelementptr inbounds %Any, %Any* [[ALLOCA]], i32 0, i32 0
237+
// CHECK: [[ANYBUF:%[^, =]+]] = getelementptr inbounds %Any, %Any* [[ALLOCA]], i32 0, i32 0
238+
// CHECK: [[BUFPTR:%[^, =]+]] = {{.*}} [[ANYBUF]]
239+
// CHECK: [[BUF_0:%[^, =]+]] = {{.*}} [[BUFPTR]]
240+
// CHECK: store {{.*}} [[OBJC_CLASS_OBJ]], {{.*}} [[BUF_0]]
241+
// CHECK: call swiftcc void @"$s15objc_extensions11opaquePrintyyypF"(%Any* {{.*}} [[ALLOCA]])
242+
@objc public convenience init(pinning: Element.Type) {
243+
opaquePrint(pinning as AnyObject)
244+
self.init()
245+
}
246+
}

0 commit comments

Comments
 (0)