Skip to content

Commit a61ce11

Browse files
authored
Merge pull request #39782 from DougGregor/marker-protocol-runtime-type-metadata
2 parents 46f3cc9 + 7d7ec9e commit a61ce11

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
@@ -60,6 +60,9 @@ class ASTMangler : public Mangler {
6060
/// concurrency library.
6161
bool AllowConcurrencyStandardSubstitutions = true;
6262

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

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

299306
void appendSymbolKind(SymbolKind SKind);

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5943,6 +5943,9 @@ ERROR(marker_protocol_requirement, none,
59435943
ERROR(marker_protocol_inherit_nonmarker, none,
59445944
"marker protocol %0 cannot inherit non-marker protocol %1",
59455945
(DeclName, DeclName))
5946+
ERROR(marker_protocol_inherit_class, none,
5947+
"marker protocol %0 cannot inherit class %1",
5948+
(DeclName, Type))
59465949
ERROR(marker_protocol_cast,none,
59475950
"marker protocol %0 cannot be used in a conditional cast", (DeclName))
59485951
ERROR(marker_protocol_conditional_conformance,none,

lib/AST/ASTMangler.cpp

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,41 @@ void ASTMangler::appendOpaqueDeclName(const OpaqueTypeDecl *opaqueDecl) {
10231023
}
10241024
}
10251025

1026+
void ASTMangler::appendExistentialLayout(
1027+
const ExistentialLayout &layout, GenericSignature sig,
1028+
const ValueDecl *forDecl) {
1029+
bool First = true;
1030+
bool DroppedRequiresClass = false;
1031+
bool SawRequiresClass = false;
1032+
for (Type protoTy : layout.getProtocols()) {
1033+
auto proto = protoTy->castTo<ProtocolType>()->getDecl();
1034+
// If we aren't allowed to emit marker protocols, suppress them here.
1035+
if (!AllowMarkerProtocols && proto->isMarkerProtocol()) {
1036+
if (proto->requiresClass())
1037+
DroppedRequiresClass = true;
1038+
1039+
continue;
1040+
}
1041+
1042+
if (proto->requiresClass())
1043+
SawRequiresClass = true;
1044+
1045+
appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
1046+
appendListSeparator(First);
1047+
}
1048+
if (First)
1049+
appendOperator("y");
1050+
1051+
if (auto superclass = layout.explicitSuperclass) {
1052+
appendType(superclass, sig, forDecl);
1053+
return appendOperator("Xc");
1054+
} else if (layout.hasExplicitAnyObject ||
1055+
(DroppedRequiresClass && !SawRequiresClass)) {
1056+
return appendOperator("Xl");
1057+
}
1058+
return appendOperator("p");
1059+
}
1060+
10261061
/// Mangle a type into the buffer.
10271062
///
10281063
void ASTMangler::appendType(Type type, GenericSignature sig,
@@ -1199,31 +1234,15 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
11991234
return appendOperator("t");
12001235

12011236
case TypeKind::Protocol: {
1202-
bool First = true;
1203-
appendProtocolName(cast<ProtocolType>(tybase)->getDecl());
1204-
appendListSeparator(First);
1205-
return appendOperator("p");
1237+
return appendExistentialLayout(
1238+
ExistentialLayout(cast<ProtocolType>(tybase)), sig, forDecl);
12061239
}
12071240

12081241
case TypeKind::ProtocolComposition: {
12091242
// We mangle ProtocolType and ProtocolCompositionType using the
12101243
// same production:
1211-
bool First = true;
12121244
auto layout = type->getExistentialLayout();
1213-
for (Type protoTy : layout.getProtocols()) {
1214-
appendProtocolName(protoTy->castTo<ProtocolType>()->getDecl());
1215-
appendListSeparator(First);
1216-
}
1217-
if (First)
1218-
appendOperator("y");
1219-
1220-
if (auto superclass = layout.explicitSuperclass) {
1221-
appendType(superclass, sig, forDecl);
1222-
return appendOperator("Xc");
1223-
} else if (layout.hasExplicitAnyObject) {
1224-
return appendOperator("Xl");
1225-
}
1226-
return appendOperator("p");
1245+
return appendExistentialLayout(layout, sig, forDecl);
12271246
}
12281247

12291248
case TypeKind::UnboundGeneric:
@@ -2220,6 +2239,8 @@ void ASTMangler::appendModule(const ModuleDecl *module,
22202239
/// Mangle the name of a protocol as a substitution candidate.
22212240
void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
22222241
bool allowStandardSubstitution) {
2242+
assert(AllowMarkerProtocols || !protocol->isMarkerProtocol());
2243+
22232244
if (allowStandardSubstitution && tryAppendStandardSubstitution(protocol))
22242245
return;
22252246

@@ -2370,6 +2391,8 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
23702391
appendOperator("a");
23712392
break;
23722393
case DeclKind::Protocol:
2394+
assert(AllowMarkerProtocols ||
2395+
!cast<ProtocolDecl>(decl)->isMarkerProtocol());
23732396
appendOperator("P");
23742397
break;
23752398
case DeclKind::Class:
@@ -2689,6 +2712,11 @@ void ASTMangler::appendRequirement(const Requirement &reqt,
26892712
case RequirementKind::Layout: {
26902713
} break;
26912714
case RequirementKind::Conformance: {
2715+
// If we don't allow marker protocols but we have one here, skip it.
2716+
if (!AllowMarkerProtocols &&
2717+
reqt.getProtocolDecl()->isMarkerProtocol())
2718+
return;
2719+
26922720
appendProtocolName(reqt.getProtocolDecl());
26932721
} break;
26942722
case RequirementKind::Superclass:
@@ -3226,6 +3254,12 @@ void ASTMangler::appendAnyProtocolConformance(
32263254
GenericSignature genericSig,
32273255
CanType conformingType,
32283256
ProtocolConformanceRef conformance) {
3257+
// If we have a conformance to a marker protocol but we aren't allowed to
3258+
// emit marker protocols, skip it.
3259+
if (!AllowMarkerProtocols &&
3260+
conformance.getRequirement()->isMarkerProtocol())
3261+
return;
3262+
32293263
if (conformingType->isTypeParameter()) {
32303264
assert(genericSig && "Need a generic signature to resolve conformance");
32313265
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
appendType(Ty, Sig);
164166
});

lib/Sema/TypeCheckAttr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5575,6 +5575,12 @@ void AttributeChecker::visitMarkerAttr(MarkerAttr *attr) {
55755575
}
55765576
}
55775577

5578+
if (Type superclass = proto->getSuperclass()) {
5579+
proto->diagnose(
5580+
diag::marker_protocol_inherit_class,
5581+
proto->getName(), superclass);
5582+
}
5583+
55785584
// A marker protocol cannot have any requirements.
55795585
for (auto member : proto->getAllMembers()) {
55805586
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)