mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Basic support for indirect import of C++ classes. (#7094)
When importing Carbon code that refers to a C++ class, look for a corresponding C++ class in the current context and import that instead. This is a workaround for not having proper cross-file C++ import support. For now, we only support non-templated namespace-scope class types. Assisted-by: Gemini via Antigravity
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
#include "toolchain/check/cpp/location.h"
|
||||
#include "toolchain/check/cpp/macros.h"
|
||||
#include "toolchain/check/cpp/thunk.h"
|
||||
#include "toolchain/check/cpp/type_mapping.h"
|
||||
#include "toolchain/check/diagnostic_helpers.h"
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/function.h"
|
||||
@@ -149,6 +150,107 @@ auto ImportCpp(Context& context,
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
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())));
|
||||
if (!parent) {
|
||||
return nullptr;
|
||||
}
|
||||
clang::DeclarationName name;
|
||||
if (auto* identifier = named_decl->getDeclName().getAsIdentifierInfo()) {
|
||||
name = &context.Idents.get(identifier->getName());
|
||||
} else {
|
||||
// TODO: Handle more name kinds.
|
||||
return nullptr;
|
||||
}
|
||||
auto decls = parent->lookup(name);
|
||||
// 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.
|
||||
return nullptr;
|
||||
}
|
||||
return decls.front();
|
||||
}
|
||||
|
||||
if (isa<clang::TranslationUnitDecl>(decl)) {
|
||||
return context.getTranslationUnitDecl();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ImportCppDeclFromFile(Context& context, SemIR::LocId loc_id,
|
||||
const SemIR::File& file,
|
||||
SemIR::ClangDeclId clang_decl_id)
|
||||
-> SemIR::ConstantId {
|
||||
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);
|
||||
if (!corresponding) {
|
||||
// TODO: This needs a proper diagnostic.
|
||||
context.TODO(
|
||||
loc_id,
|
||||
"use of imported C++ declaration with no corresponding local import");
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
|
||||
key.decl = corresponding;
|
||||
auto imported_inst_id = ImportCppDecl(context, loc_id, key);
|
||||
auto imported_const_id = context.constant_values().Get(imported_inst_id);
|
||||
if (!imported_const_id.is_constant()) {
|
||||
context.TODO(loc_id, "imported C++ declant is not constant");
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
return imported_const_id;
|
||||
}
|
||||
|
||||
auto ImportCppConstantFromFile(Context& context, SemIR::LocId loc_id,
|
||||
const SemIR::File& file, SemIR::InstId inst_id)
|
||||
-> SemIR::ConstantId {
|
||||
// TODO: We should perform cross-file imports by importing the C++ AST. For
|
||||
// now we require the C++ declaration to already be imported into the
|
||||
// destination file, and find the corresponding declaration there and import
|
||||
// that.
|
||||
if (!context.cpp_context()) {
|
||||
context.TODO(
|
||||
loc_id, "indirect import of C++ declaration with no direct Cpp import");
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
|
||||
auto const_inst_id = file.constant_values().GetConstantInstId(inst_id);
|
||||
CARBON_KIND_SWITCH(file.insts().Get(const_inst_id)) {
|
||||
case CARBON_KIND(SemIR::ClassType class_type): {
|
||||
const auto& class_info = file.classes().Get(class_type.class_id);
|
||||
CARBON_CHECK(class_info.scope_id.has_value());
|
||||
return ImportCppDeclFromFile(
|
||||
context, loc_id, file,
|
||||
file.name_scopes().Get(class_info.scope_id).clang_decl_context_id());
|
||||
}
|
||||
|
||||
case CARBON_KIND(SemIR::Namespace namespace_decl): {
|
||||
return ImportCppDeclFromFile(context, loc_id, file,
|
||||
file.name_scopes()
|
||||
.Get(namespace_decl.name_scope_id)
|
||||
.clang_decl_context_id());
|
||||
}
|
||||
|
||||
default: {
|
||||
context.TODO(loc_id, "indirect import of unsupported C++ declaration");
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the Clang `DeclContext` for the given name scope. Return the
|
||||
// translation unit decl if no scope is provided.
|
||||
static auto GetDeclContext(Context& context, SemIR::NameScopeId scope_id)
|
||||
|
||||
Reference in New Issue
Block a user