Skip to content

Commit 59158a1

Browse files
committed
Don't emit marker protocols into runtime type metadata.
Marker protocols don't exist at runtime, drop them when mangling a type for the purposes of runtime type metadata or reflection. Fixes rdar://82314404. (cherry picked from commit 7d7ec9e)
1 parent db15620 commit 59158a1

File tree

7 files changed

+105
-20
lines changed

7 files changed

+105
-20
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class ASTMangler : public Mangler {
6161
/// concurrency library.
6262
bool AllowConcurrencyStandardSubstitutions = true;
6363

64+
/// If enabled, marker protocols can be encoded in the mangled name.
65+
bool AllowMarkerProtocols = true;
66+
6467
public:
6568
using SymbolicReferent = llvm::PointerUnion<const NominalTypeDecl *,
6669
const OpaqueTypeDecl *>;
@@ -293,6 +296,10 @@ class ASTMangler : public Mangler {
293296
static const clang::NamedDecl *
294297
getClangDeclForMangling(const ValueDecl *decl);
295298

299+
void appendExistentialLayout(
300+
const ExistentialLayout &layout, GenericSignature sig,
301+
const ValueDecl *forDecl);
302+
296303
protected:
297304

298305
void appendSymbolKind(SymbolKind SKind);

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5827,6 +5827,9 @@ ERROR(marker_protocol_requirement, none,
58275827
ERROR(marker_protocol_inherit_nonmarker, none,
58285828
"marker protocol %0 cannot inherit non-marker protocol %1",
58295829
(DeclName, DeclName))
5830+
ERROR(marker_protocol_inherit_class, none,
5831+
"marker protocol %0 cannot inherit class %1",
5832+
(DeclName, Type))
58305833
ERROR(marker_protocol_cast,none,
58315834
"marker protocol %0 cannot be used in a conditional cast", (DeclName))
58325835
ERROR(marker_protocol_conditional_conformance,none,

lib/AST/ASTMangler.cpp

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,41 @@ void ASTMangler::appendOpaqueDeclName(const OpaqueTypeDecl *opaqueDecl) {
10141014
}
10151015
}
10161016

1017+
void ASTMangler::appendExistentialLayout(
1018+
const ExistentialLayout &layout, GenericSignature sig,
1019+
const ValueDecl *forDecl) {
1020+
bool First = true;
1021+
bool DroppedRequiresClass = false;
1022+
bool SawRequiresClass = false;
1023+
for (Type protoTy : layout.getProtocols()) {
1024+
auto proto = protoTy->castTo<ProtocolType>()->getDecl();
1025+
// If we aren't allowed to emit marker protocols, suppress them here.
1026+
if (!AllowMarkerProtocols && proto->isMarkerProtocol()) {
1027+
if (proto->requiresClass())
1028+
DroppedRequiresClass = true;
1029+
1030+
continue;
1031+
}
1032+
1033+
if (proto->requiresClass())
1034+
SawRequiresClass = true;
1035+
1036+
appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
1037+
appendListSeparator(First);
1038+
}
1039+
if (First)
1040+
appendOperator("y");
1041+
1042+
if (auto superclass = layout.explicitSuperclass) {
1043+
appendType(superclass, sig, forDecl);
1044+
return appendOperator("Xc");
1045+
} else if (layout.hasExplicitAnyObject ||
1046+
(DroppedRequiresClass && !SawRequiresClass)) {
1047+
return appendOperator("Xl");
1048+
}
1049+
return appendOperator("p");
1050+
}
1051+
10171052
/// Mangle a type into the buffer.
10181053
///
10191054
void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
@@ -1183,31 +1218,15 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {
11831218
return appendOperator("t");
11841219

11851220
case TypeKind::Protocol: {
1186-
bool First = true;
1187-
appendProtocolName(cast<ProtocolType>(tybase)->getDecl());
1188-
appendListSeparator(First);
1189-
return appendOperator("p");
1221+
return appendExistentialLayout(
1222+
ExistentialLayout(cast<ProtocolType>(tybase)), sig, forDecl);
11901223
}
11911224

11921225
case TypeKind::ProtocolComposition: {
11931226
// We mangle ProtocolType and ProtocolCompositionType using the
11941227
// same production:
1195-
bool First = true;
11961228
auto layout = type->getExistentialLayout();
1197-
for (Type protoTy : layout.getProtocols()) {
1198-
appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
1199-
appendListSeparator(First);
1200-
}
1201-
if (First)
1202-
appendOperator("y");
1203-
1204-
if (auto superclass = layout.explicitSuperclass) {
1205-
appendType(superclass, forDecl);
1206-
return appendOperator("Xc");
1207-
} else if (layout.hasExplicitAnyObject) {
1208-
return appendOperator("Xl");
1209-
}
1210-
return appendOperator("p");
1229+
return appendExistentialLayout(layout, sig, forDecl);
12111230
}
12121231

12131232
case TypeKind::UnboundGeneric:
@@ -2190,6 +2209,8 @@ void ASTMangler::appendModule(const ModuleDecl *module,
21902209
/// Mangle the name of a protocol as a substitution candidate.
21912210
void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
21922211
bool allowStandardSubstitution) {
2212+
assert(AllowMarkerProtocols || !protocol->isMarkerProtocol());
2213+
21932214
if (allowStandardSubstitution && tryAppendStandardSubstitution(protocol))
21942215
return;
21952216

@@ -2338,6 +2359,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
23382359
appendOperator("a");
23392360
break;
23402361
case DeclKind::Protocol:
2362+
assert(AllowMarkerProtocols ||
2363+
!cast<ProtocolDecl>(decl)->isMarkerProtocol());
23412364
appendOperator("P");
23422365
break;
23432366
case DeclKind::Class:
@@ -2651,6 +2674,11 @@ void ASTMangler::appendRequirement(const Requirement &reqt) {
26512674
case RequirementKind::Layout: {
26522675
} break;
26532676
case RequirementKind::Conformance: {
2677+
// If we don't allow marker protocols but we have one here, skip it.
2678+
if (!AllowMarkerProtocols &&
2679+
reqt.getProtocolDecl()->isMarkerProtocol())
2680+
return;
2681+
26542682
appendProtocolName(reqt.getProtocolDecl());
26552683
} break;
26562684
case RequirementKind::Superclass:
@@ -3181,6 +3209,12 @@ void ASTMangler::appendAnyProtocolConformance(
31813209
CanGenericSignature genericSig,
31823210
CanType conformingType,
31833211
ProtocolConformanceRef conformance) {
3212+
// If we have a conformance to a marker protocol but we aren't allowed to
3213+
// emit marker protocols, skip it.
3214+
if (!AllowMarkerProtocols &&
3215+
conformance.getRequirement()->isMarkerProtocol())
3216+
return;
3217+
31843218
if (conformingType->isTypeParameter()) {
31853219
assert(genericSig && "Need a generic signature to resolve conformance");
31863220
auto path = genericSig->getConformanceAccessPath(conformingType,

lib/IRGen/IRGenMangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ IRGenMangler::mangleTypeForReflection(IRGenModule &IGM,
159159
AllowConcurrencyStandardSubstitutions = false;
160160
}
161161

162+
llvm::SaveAndRestore<bool> savedAllowMarkerProtocols(
163+
AllowMarkerProtocols, false);
162164
return withSymbolicReferences(IGM, [&]{
163165
bindGenericParameters(Sig);
164166
appendType(Ty);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5588,6 +5588,12 @@ void AttributeChecker::visitMarkerAttr(MarkerAttr *attr) {
55885588
}
55895589
}
55905590

5591+
if (Type superclass = proto->getSuperclass()) {
5592+
proto->diagnose(
5593+
diag::marker_protocol_inherit_class,
5594+
proto->getName(), superclass);
5595+
}
5596+
55915597
// A marker protocol cannot have any requirements.
55925598
for (auto member : proto->getAllMembers()) {
55935599
auto value = dyn_cast<ValueDecl>(member);

test/IRGen/marker_protocol.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
extension Int: P { }
1414
extension Array: P where Element: P { }
1515

16-
// CHECK: @"$s15marker_protocol1QMp" = {{(dllexport |protected )?}}constant
16+
// No mention of the marker protocol for runtime type instantiation.
17+
// CHECK-LABEL: @"$sSS_15marker_protocol1P_ptMD" =
18+
// CHECK-SAME: @"symbolic SS_ypt"
19+
20+
// CHECK-LABEL: @"$s15marker_protocol1QMp" = {{(dllexport |protected )?}}constant
1721
// CHECK-SAME: i32 trunc{{.*}}s15marker_protocolMXM{{.*}}s15marker_protocol1QMp
1822
// CHECK-SAME: i32 0, i32 5, i32 0
1923
public protocol Q: P {
@@ -24,6 +28,31 @@ public protocol Q: P {
2428
func j()
2529
}
2630

31+
protocol R { }
32+
33+
@_marker protocol S: AnyObject { }
34+
35+
// Note: no mention of marker protocols here.
36+
// CHECK-LABEL: @"$s15marker_protocol10HasMarkersVMF" =
37+
// CHECK-SAME: @"symbolic yp"
38+
// CHECK-SAME: @"symbolic ______p 15marker_protocol1QP"
39+
// CHECK-SAME: @"symbolic ______p 15marker_protocol1RP"
40+
// CHECK-SAME: @"symbolic yXl"
41+
struct HasMarkers {
42+
var field1: P
43+
var field2: P & Q
44+
var field3: P & R
45+
var field4: S
46+
}
47+
48+
// Note: no mention of marker protocols when forming a dictionary.
49+
// CHECK-LABEL: define{{.*}}@"$s15marker_protocol0A12InDictionaryypyF"
50+
// CHECK: call %swift.type* @__swift_instantiateConcreteTypeFromMangledName({{.*}} @"$sSS_15marker_protocol1P_ptMD")
51+
public func markerInDictionary() -> Any {
52+
let dict: [String: P] = ["answer" : 42]
53+
return dict
54+
}
55+
2756
// Note: no witness tables
2857
// CHECK: swiftcc void @"$s15marker_protocol7genericyyxAA1PRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* %T)
2958
public func generic<T: P>(_: T) { }

test/attr/attr_marker_protocol.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ protocol P4 { } // expected-note{{'P4' declared here}}
1717

1818
@_marker protocol P5: P4 { } // expected-error{{marker protocol 'P5' cannot inherit non-marker protocol 'P4'}}
1919

20+
class C { }
21+
@_marker protocol P5a: AnyObject { } // okay
22+
@_marker protocol P5b: C { } // expected-error{{marker protocol 'P5b' cannot inherit class 'C'}}
23+
2024
// Legitimate uses of marker protocols.
2125
extension P3 {
2226
func f() { }

0 commit comments

Comments
 (0)