Skip to content

Commit d13d600

Browse files
authored
Merge pull request #17603 from jckarter/synthesized-type-reflection-4.2
[4.2] Runtime: Handle synthesized decl "related entity" tags.
2 parents db2e63d + 43b7b7e commit d13d600

File tree

11 files changed

+180
-34
lines changed

11 files changed

+180
-34
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,12 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
11761176
///
11771177
/// Meaningful for all type-descriptor kinds.
11781178
IsReflectable = 2,
1179+
1180+
/// Set if the type is a Clang-importer-synthesized related entity. After
1181+
/// the null terminator for the type name is another null-terminated string
1182+
/// containing the tag that discriminates the entity from other synthesized
1183+
/// declarations associated with the same declaration.
1184+
IsSynthesizedRelatedEntity = 3,
11791185

11801186
/// Set if the context descriptor is includes metadata for dynamically
11811187
/// constructing a class's vtables at metadata instantiation time.
@@ -1208,6 +1214,10 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12081214
FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTypedef, isCTypedef, setIsCTypedef)
12091215
FLAGSET_DEFINE_FLAG_ACCESSORS(IsReflectable, isReflectable, setIsReflectable)
12101216

1217+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsSynthesizedRelatedEntity,
1218+
isSynthesizedRelatedEntity,
1219+
setIsSynthesizedRelatedEntity)
1220+
12111221
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
12121222
class_hasVTable,
12131223
class_setHasVTable)

include/swift/Remote/MetadataReader.h

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,20 +1136,30 @@ class MetadataReader {
11361136
Demangle::NodePointer
11371137
buildNominalTypeMangling(ContextDescriptorRef descriptor,
11381138
Demangle::NodeFactory &nodeFactory) {
1139-
std::vector<std::pair<Demangle::Node::Kind, std::string>>
1139+
std::vector<std::pair<Demangle::Node::Kind, Demangle::NodePointer>>
11401140
nameComponents;
11411141
ContextDescriptorRef parent = descriptor;
11421142

11431143
while (parent) {
11441144
std::string nodeName;
1145+
std::string relatedTag;
11451146
Demangle::Node::Kind nodeKind;
11461147

11471148
auto getTypeName = [&]() -> bool {
11481149
auto typeBuffer =
11491150
reinterpret_cast<const TargetTypeContextDescriptor<Runtime> *>
11501151
(parent.getLocalBuffer());
11511152
auto nameAddress = resolveRelativeField(parent, typeBuffer->Name);
1152-
return Reader->readString(RemoteAddress(nameAddress), nodeName);
1153+
if (!Reader->readString(RemoteAddress(nameAddress), nodeName))
1154+
return false;
1155+
1156+
if (typeBuffer->isSynthesizedRelatedEntity()) {
1157+
nameAddress += nodeName.size() + 1;
1158+
if (!Reader->readString(RemoteAddress(nameAddress), relatedTag))
1159+
return false;
1160+
}
1161+
1162+
return true;
11531163
};
11541164

11551165
bool isTypeContext = false;
@@ -1208,8 +1218,17 @@ class MetadataReader {
12081218
else if (typeFlags.isCTypedef())
12091219
nodeKind = Demangle::Node::Kind::TypeAlias;
12101220
}
1221+
1222+
auto nameNode = nodeFactory.createNode(Node::Kind::Identifier,
1223+
nodeName);
1224+
if (!relatedTag.empty()) {
1225+
auto relatedNode =
1226+
nodeFactory.createNode(Node::Kind::RelatedEntityDeclName, relatedTag);
1227+
relatedNode->addChild(nameNode, nodeFactory);
1228+
nameNode = relatedNode;
1229+
}
12111230

1212-
nameComponents.emplace_back(nodeKind, nodeName);
1231+
nameComponents.emplace_back(nodeKind, nameNode);
12131232

12141233
parent = readParentContextDescriptor(parent);
12151234
}
@@ -1222,13 +1241,11 @@ class MetadataReader {
12221241
auto moduleInfo = std::move(nameComponents.back());
12231242
nameComponents.pop_back();
12241243
auto demangling =
1225-
nodeFactory.createNode(Node::Kind::Module, moduleInfo.second);
1244+
nodeFactory.createNode(Node::Kind::Module, moduleInfo.second->getText());
12261245
for (auto &component : reversed(nameComponents)) {
1227-
auto name = nodeFactory.createNode(Node::Kind::Identifier,
1228-
component.second);
12291246
auto parent = nodeFactory.createNode(component.first);
12301247
parent->addChild(demangling, nodeFactory);
1231-
parent->addChild(name, nodeFactory);
1248+
parent->addChild(component.second, nodeFactory);
12321249
demangling = parent;
12331250
}
12341251

include/swift/Runtime/Metadata.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3511,6 +3511,21 @@ class TargetTypeContextDescriptor
35113511

35123512
llvm::ArrayRef<GenericParamDescriptor> getGenericParams() const;
35133513

3514+
bool isSynthesizedRelatedEntity() const {
3515+
return getTypeContextDescriptorFlags().isSynthesizedRelatedEntity();
3516+
}
3517+
3518+
/// Return the tag used to discriminate declarations synthesized by the
3519+
/// Clang importer and give them stable identities.
3520+
StringRef getSynthesizedDeclRelatedEntityTag() const {
3521+
if (!isSynthesizedRelatedEntity())
3522+
return {};
3523+
// The tag name comes after the null terminator for the name.
3524+
const char *nameBegin = Name.get();
3525+
auto *nameEnd = nameBegin + strlen(nameBegin) + 1;
3526+
return nameEnd;
3527+
}
3528+
35143529
/// Return the offset of the start of generic arguments in the nominal
35153530
/// type's metadata. The returned value is measured in sizeof(void*).
35163531
int32_t getGenericArgumentOffset() const;

lib/IRGen/GenMeta.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,21 @@ namespace {
481481
}
482482

483483
void addName() {
484+
SmallString<32> nameBuf;
484485
StringRef name;
485-
486+
487+
// Use the original name with tag for synthesized decls. The tag comes
488+
// after the null terminator for the name.
489+
if (auto *synthesizedTypeAttr =
490+
Type->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>()) {
491+
nameBuf.append(synthesizedTypeAttr->originalTypeName);
492+
nameBuf.push_back('\0');
493+
nameBuf.append(synthesizedTypeAttr->getManglingName());
494+
495+
name = nameBuf;
486496
// Try to use the Clang name if there is one.
487-
if (auto namedClangDecl =
488-
Mangle::ASTMangler::getClangDeclForMangling(Type)) {
497+
} else if (auto namedClangDecl =
498+
Mangle::ASTMangler::getClangDeclForMangling(Type)) {
489499
name = namedClangDecl->getName();
490500
} else {
491501
name = Type->getName().str();
@@ -565,22 +575,18 @@ namespace {
565575
/// Flags to indicate Clang-imported declarations so we mangle them
566576
/// consistently at runtime.
567577
void getClangImportedFlags(TypeContextDescriptorFlags &flags) const {
568-
auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type);
569-
if (!clangDecl)
570-
return;
571-
572-
if (isa<clang::TagDecl>(clangDecl)) {
573-
flags.setIsCTag(true);
574-
return;
578+
if (Type->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>()) {
579+
flags.setIsSynthesizedRelatedEntity(true);
575580
}
576581

577-
if (isa<clang::TypedefNameDecl>(clangDecl)
578-
|| isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
579-
flags.setIsCTypedef(true);
580-
return;
582+
if (auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type)) {
583+
if (isa<clang::TagDecl>(clangDecl)) {
584+
flags.setIsCTag(true);
585+
} else if (isa<clang::TypedefNameDecl>(clangDecl)
586+
|| isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
587+
flags.setIsCTypedef(true);
588+
}
581589
}
582-
583-
return;
584590
}
585591

586592
// Subclasses should provide:

lib/RemoteAST/RemoteAST.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,17 @@ RemoteASTTypeBuilder::findForeignNominalTypeDecl(StringRef name,
753753
if (HadError) return;
754754
if (decl == Result) return;
755755
if (!Result) {
756-
Result = cast<NominalTypeDecl>(decl);
756+
// A synthesized type from the Clang importer may resolve to a
757+
// compatibility alias.
758+
if (auto resultAlias = dyn_cast<TypeAliasDecl>(decl)) {
759+
if (resultAlias->isCompatibilityAlias()) {
760+
Result = resultAlias->getUnderlyingTypeLoc().getType()
761+
->getAnyNominal();
762+
}
763+
} else {
764+
Result = dyn_cast<NominalTypeDecl>(decl);
765+
}
766+
HadError |= !Result;
757767
} else {
758768
HadError = true;
759769
Result = nullptr;

stdlib/public/runtime/Demangle.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,14 @@ swift::_buildDemanglingForContext(const ContextDescriptor *context,
160160

161161
auto typeNode = Dem.createNode(nodeKind);
162162
typeNode->addChild(node, Dem);
163-
auto identifier = Dem.createNode(Node::Kind::Identifier, name);
164-
typeNode->addChild(identifier, Dem);
163+
auto nameNode = Dem.createNode(Node::Kind::Identifier, name);
164+
if (type->isSynthesizedRelatedEntity()) {
165+
auto relatedName = Dem.createNode(Node::Kind::RelatedEntityDeclName,
166+
type->getSynthesizedDeclRelatedEntityTag());
167+
relatedName->addChild(nameNode, Dem);
168+
nameNode = relatedName;
169+
}
170+
typeNode->addChild(nameNode, Dem);
165171
node = typeNode;
166172

167173
// Apply generic arguments if the context is generic.

stdlib/public/runtime/Metadata.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1488,7 +1488,20 @@ bool swift::equalContexts(const ContextDescriptor *a,
14881488
&& kind <= ContextDescriptorKind::Type_Last) {
14891489
auto typeA = cast<TypeContextDescriptor>(a);
14901490
auto typeB = cast<TypeContextDescriptor>(b);
1491-
return strcmp(typeA->Name.get(), typeB->Name.get()) == 0;
1491+
if (strcmp(typeA->Name.get(), typeB->Name.get()) != 0)
1492+
return false;
1493+
1494+
// A synthesized entity has to match the related entity tag too.
1495+
if (typeA->isSynthesizedRelatedEntity()) {
1496+
if (!typeB->isSynthesizedRelatedEntity())
1497+
return false;
1498+
1499+
if (typeA->getSynthesizedDeclRelatedEntityTag()
1500+
!= typeB->getSynthesizedDeclRelatedEntityTag())
1501+
return false;
1502+
}
1503+
1504+
return true;
14921505
}
14931506

14941507
// Otherwise, this runtime doesn't know anything about this context kind.

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,14 +264,31 @@ swift::_contextDescriptorMatchesMangling(const ContextDescriptor *context,
264264
}
265265

266266
auto nameNode = node->getChild(1);
267-
if (nameNode->getKind() == Demangle::Node::Kind::PrivateDeclName)
268-
return false;
269-
270-
if (nameNode->getText() != type->Name.get())
267+
268+
// Declarations synthesized by the Clang importer get a small tag
269+
// string in addition to their name.
270+
if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName){
271+
if (nameNode->getText() != type->getSynthesizedDeclRelatedEntityTag())
272+
return false;
273+
274+
nameNode = nameNode->getChild(0);
275+
} else if (type->isSynthesizedRelatedEntity()) {
271276
return false;
277+
}
278+
279+
// We should only match public or internal declarations with stable
280+
// names. The runtime metadata for private declarations would be
281+
// anonymized.
282+
if (nameNode->getKind() == Demangle::Node::Kind::Identifier) {
283+
if (nameNode->getText() != type->Name.get())
284+
return false;
285+
286+
node = node->getChild(0);
287+
break;
288+
}
272289

273-
node = node->getChild(0);
274-
break;
290+
return false;
291+
275292
}
276293

277294
// We don't know about this kind of context, or it doesn't have a stable
@@ -1166,7 +1183,7 @@ void swift::_swift_getFieldAt(
11661183
if (typeInfo == nullptr) {
11671184
typeInfo = TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {});
11681185
warning(0, "SWIFT RUNTIME BUG: unable to demangle type of field '%*s'. "
1169-
"mangled type name is '%*s'",
1186+
"mangled type name is '%*s'\n",
11701187
(int)name.size(), name.data(),
11711188
(int)typeName.size(), typeName.data());
11721189
}
@@ -1214,6 +1231,17 @@ void swift::_swift_getFieldAt(
12141231
return;
12151232
}
12161233
}
1234+
1235+
// If we failed to find the field descriptor metadata for the type, fall
1236+
// back to returning an empty tuple as a standin.
1237+
auto typeName = swift_getTypeName(base, /*qualified*/ true);
1238+
warning(0, "SWIFT RUNTIME BUG: unable to find field metadata for type '%*s'\n",
1239+
(int)typeName.length, typeName.data);
1240+
callback("unknown",
1241+
FieldType()
1242+
.withType(TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {}))
1243+
.withIndirect(false)
1244+
.withWeak(false));
12171245
}
12181246

12191247
#define OVERRIDE_METADATALOOKUP COMPATIBILITY_OVERRIDE
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import CoreLocation
2+
3+
public func getCLError() -> Any.Type {
4+
return CLError.self
5+
}
6+
7+
public func getCLErrorCode() -> Any.Type {
8+
return CLError.Code.self
9+
}

test/Runtime/demangleToMetadataObjC.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import StdlibUnittest
66
import Foundation
77
import CoreFoundation
8+
import CoreLocation
89

910
let DemangleToMetadataTests = TestSuite("DemangleToMetadataObjC")
1011

@@ -74,5 +75,15 @@ DemangleToMetadataTests.test("@objc protocol conformances") {
7475
expectNil(_typeByMangledName("4main3CG4CyAA1DCAA1DCG"))
7576
}
7677

78+
DemangleToMetadataTests.test("synthesized declarations") {
79+
expectEqual(CLError.self, _typeByMangledName("SC7CLErrorLeV")!)
80+
expectNil(_typeByMangledName("SC7CLErrorV"))
81+
expectEqual(CLError.Code.self, _typeByMangledName("So7CLErrorV")!)
82+
83+
let error = NSError(domain: NSCocoaErrorDomain, code: 0)
84+
let reflectionString = String(reflecting: CLError(_nsError: error))
85+
expectTrue(reflectionString.hasPrefix("__C_Synthesized.related decl 'e' for CLError(_nsError:"))
86+
}
87+
7788
runAllTests()
7889

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -parse-as-library -force-single-frontend-invocation %S/Inputs/synthesized_decl_uniqueness.swift -emit-object -o %t/A.o -module-name A -emit-module-path %t/A.swiftmodule
3+
// RUN: %target-build-swift -parse-as-library -force-single-frontend-invocation %S/Inputs/synthesized_decl_uniqueness.swift -emit-object -o %t/B.o -module-name B -emit-module-path %t/B.swiftmodule
4+
// RUN: %target-build-swift -I %t %s %t/A.o %t/B.o -o %t/a.out
5+
// RUN: %target-run %t/a.out
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: objc_interop
9+
10+
import StdlibUnittest
11+
import A
12+
import B
13+
14+
var tests = TestSuite("metadata identity for synthesized types")
15+
16+
tests.test("synthesized type identity across modules") {
17+
expectEqual(A.getCLError(), B.getCLError())
18+
expectEqual(A.getCLErrorCode(), B.getCLErrorCode())
19+
}
20+
21+
runAllTests()

0 commit comments

Comments
 (0)