[cxx-interop] Fix lookup of class template instantiations

To fix a crash during deserialization, we need to store the mangled names of C++ class template instantiations in the lookup table.

For example, `std::string` will be serialized as `__CxxTemplateInstNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE`, and when another instance of the Swift compiler will later attempt to deserialize a decl referencing this instantiation, it will query the `SwiftLookupTable` for a decl with this name. If this instantiation is not referenced from the module that is currently being compiled, Swift will not instantiate `std::string` during typechecking, and the mangled name will be missing from `SwiftLookupTable`, leading to a deserialization failure. This happens when compiling with cross-module optimization enabled, and the current module does not reference `std::string`, but one of its dependencies does.
This commit is contained in:
Egor Zhdan
2022-04-29 19:19:03 +01:00
parent 2285c518f7
commit c952fc175b
2 changed files with 33 additions and 3 deletions

View File

@@ -1922,6 +1922,30 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
}
}
// Class template instantiations are imported lazily, however, the lookup
// table must include their mangled name (__CxxTemplateInst...) to make it
// possible to find these decls during deserialization. For any C++ typedef
// that defines a name for a class template instantiation (e.g. std::string),
// import the mangled name of this instantiation, and add it to the table.
if (auto typedefNameDecl = dyn_cast<clang::TypedefNameDecl>(named)) {
auto underlyingDecl = typedefNameDecl->getUnderlyingType()->getAsTagDecl();
if (auto specializationDecl =
dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
underlyingDecl)) {
auto name = nameImporter.importName(specializationDecl, currentVersion);
// Avoid adding duplicate entries into the table.
auto existingEntries =
table.lookup(DeclBaseName(name.getDeclName().getBaseName()),
name.getEffectiveContext());
if (existingEntries.empty()) {
table.addEntry(name.getDeclName(), specializationDecl,
name.getEffectiveContext());
}
}
}
// Walk the members of any context that can have nested members.
if (isa<clang::TagDecl>(named) || isa<clang::ObjCInterfaceDecl>(named) ||
isa<clang::ObjCProtocolDecl>(named) ||