mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Limited support for indirect import of template specializations. (#7121)
When a class template specialization is indirectly imported, map the template arguments into the importing File and find the corresponding local class template specialization. This is a short-term fix: eventually we should import the C++ AST from the imported file into the C++ AST for the current file, but we're not ready to do that yet. So far we only support very simple template arguments: just classes and builtin types. Unfortunately we can't just map the C++ template arguments to Carbon types, then import the Carbon types, then map them back, because mapping from C++ template arguments to Carbon types would require a `Check::Context` for the imported code, which we don't have. As this is only a temporary workaround, directly mapping from one C++ AST to another will do for now. Assisted-by: Gemini via Antigravity
This commit is contained in:
@@ -150,22 +150,62 @@ auto ImportCpp(Context& context,
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
static auto FindCorrespondingType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type) -> clang::QualType;
|
||||
|
||||
// Given a class template specialization in some C++ AST which is *not* expected
|
||||
// to be `context`, find the corresponding declaration in `context`, if there is
|
||||
// one.
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
static auto FindCorrespondingTemplateSpecialization(
|
||||
Context& context, SemIR::LocId loc_id,
|
||||
const clang::ClassTemplateSpecializationDecl* source_spec,
|
||||
clang::ClassTemplateDecl* target_template) -> clang::Decl* {
|
||||
const auto& args = source_spec->getTemplateArgs();
|
||||
auto loc = GetCppLocation(context, loc_id);
|
||||
clang::TemplateArgumentListInfo arg_list(loc, loc);
|
||||
for (unsigned i = 0; i < args.size(); ++i) {
|
||||
const auto& arg = args[i];
|
||||
if (arg.getKind() == clang::TemplateArgument::Type) {
|
||||
auto type = FindCorrespondingType(context, loc_id, arg.getAsType());
|
||||
if (type.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
arg_list.addArgument(clang::TemplateArgumentLoc(
|
||||
clang::TemplateArgument(type),
|
||||
context.ast_context().getTrivialTypeSourceInfo(type, loc)));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
clang::TemplateName template_name(target_template);
|
||||
auto clang_type = context.clang_sema().CheckTemplateIdType(
|
||||
clang::ElaboratedTypeKeyword::None, template_name, loc, arg_list,
|
||||
/*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false);
|
||||
if (!clang_type.isNull()) {
|
||||
return clang_type->getAsCXXRecordDecl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Given a declaration in some C++ AST which is *not* expected to be `context`,
|
||||
// find the corresponding declaration in `context`, if there is one.
|
||||
// TODO: Make this non-recursive, or remove it once we support importing C++
|
||||
// ASTs for cross file imports.
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
static auto FindCorrespondingDecl(clang::ASTContext& context,
|
||||
static auto FindCorrespondingDecl(Context& context, SemIR::LocId loc_id,
|
||||
const clang::Decl* decl) -> clang::Decl* {
|
||||
if (const auto* named_decl = dyn_cast<clang::NamedDecl>(decl)) {
|
||||
auto* parent = dyn_cast_or_null<clang::DeclContext>(FindCorrespondingDecl(
|
||||
context, cast<clang::Decl>(named_decl->getDeclContext())));
|
||||
context, loc_id, cast<clang::Decl>(named_decl->getDeclContext())));
|
||||
if (!parent) {
|
||||
return nullptr;
|
||||
}
|
||||
clang::DeclarationName name;
|
||||
if (auto* identifier = named_decl->getDeclName().getAsIdentifierInfo()) {
|
||||
name = &context.Idents.get(identifier->getName());
|
||||
name = &context.ast_context().Idents.get(identifier->getName());
|
||||
} else {
|
||||
// TODO: Handle more name kinds.
|
||||
return nullptr;
|
||||
@@ -174,20 +214,65 @@ static auto FindCorrespondingDecl(clang::ASTContext& context,
|
||||
// TODO: If there are multiple results, try to pick the right one.
|
||||
if (!decls.isSingleResult() ||
|
||||
decls.front()->getKind() != named_decl->getKind()) {
|
||||
// TODO: If we were looking for a non-template and found a template, try
|
||||
// to form a matching template specialization.
|
||||
if (const auto* source_spec =
|
||||
dyn_cast<clang::ClassTemplateSpecializationDecl>(named_decl)) {
|
||||
if (auto* target_template =
|
||||
dyn_cast<clang::ClassTemplateDecl>(decls.front())) {
|
||||
if (auto* result = FindCorrespondingTemplateSpecialization(
|
||||
context, loc_id, source_spec, target_template)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return decls.front();
|
||||
}
|
||||
|
||||
if (isa<clang::TranslationUnitDecl>(decl)) {
|
||||
return context.getTranslationUnitDecl();
|
||||
return context.ast_context().getTranslationUnitDecl();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Given a type in some C++ AST which is *not* expected to be `context`,
|
||||
// find the corresponding type in `context`, if there is one.
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
static auto FindCorrespondingType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type) -> clang::QualType {
|
||||
if (type.isNull()) {
|
||||
return clang::QualType();
|
||||
}
|
||||
|
||||
if (const auto* builtin = type->getAs<clang::BuiltinType>()) {
|
||||
switch (builtin->getKind()) {
|
||||
#define BUILTIN_TYPE(Id, SingletonId) \
|
||||
case clang::BuiltinType::Id: \
|
||||
return context.ast_context().SingletonId;
|
||||
#include "clang/AST/BuiltinTypes.def"
|
||||
#undef BUILTIN_TYPE
|
||||
default:
|
||||
return clang::QualType();
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto* record = type->getAs<clang::RecordType>()) {
|
||||
const auto* decl = record->getDecl();
|
||||
auto* corresponding_decl = FindCorrespondingDecl(context, loc_id, decl);
|
||||
if (!corresponding_decl) {
|
||||
return clang::QualType();
|
||||
}
|
||||
if (const auto* tag_decl = dyn_cast<clang::TagDecl>(corresponding_decl)) {
|
||||
return context.ast_context().getTypeDeclType(
|
||||
cast<clang::TypeDecl>(tag_decl));
|
||||
}
|
||||
return clang::QualType();
|
||||
}
|
||||
|
||||
return clang::QualType();
|
||||
}
|
||||
|
||||
auto ImportCppDeclFromFile(Context& context, SemIR::LocId loc_id,
|
||||
const SemIR::File& file,
|
||||
SemIR::ClangDeclId clang_decl_id)
|
||||
@@ -195,7 +280,7 @@ auto ImportCppDeclFromFile(Context& context, SemIR::LocId loc_id,
|
||||
CARBON_CHECK(clang_decl_id.has_value());
|
||||
auto key = file.clang_decls().Get(clang_decl_id).key;
|
||||
const auto* decl = key.decl;
|
||||
auto* corresponding = FindCorrespondingDecl(context.ast_context(), decl);
|
||||
auto* corresponding = FindCorrespondingDecl(context, loc_id, decl);
|
||||
if (!corresponding) {
|
||||
// TODO: This needs a proper diagnostic.
|
||||
context.TODO(
|
||||
|
||||
Reference in New Issue
Block a user