mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Initial support for C++ function pointers (#7788)
This change introduces a new inst kind `CppFunctionPointerType`, which represents an imported C++ function pointer that can be invoked from Carbon (support for forming such a pointer from a Carbon function is in a follow-up PR). This is implemented by treating the operation of invoking a function pointer in C++ as if it were a call to an `__invoke` method on the function pointer type, and extending the existing function-import logic to support importing this fictitious method. --------- Co-authored-by: Nicholas Bishop <nbishop@nbishop.net>
This commit is contained in:
co-authored by
Nicholas Bishop
parent
f65572a1e6
commit
12e1afeb15
+287
-149
@@ -440,10 +440,22 @@ static auto ClangLookupName(Context& context, SemIR::NameScopeId scope_id,
|
||||
return lookup;
|
||||
}
|
||||
|
||||
// Returns whether `decl` already mapped to an instruction.
|
||||
static auto IsClangDeclImported(Context& context, SemIR::ClangDeclKey key)
|
||||
-> bool {
|
||||
return context.clang_decls().LookupId(key).has_value();
|
||||
namespace {
|
||||
// A key that identifies a C++ declaration to import. A `ClangDeclKey`
|
||||
// represents an ordinary clang declaration, and a `clang::Type*` represents
|
||||
// that function pointer type's notional `__invoke` method, which has no clang
|
||||
// declaration.
|
||||
using ImportKey = std::variant<SemIR::ClangDeclKey, const clang::Type*>;
|
||||
} // namespace
|
||||
|
||||
// Returns whether `key` already mapped to an instruction.
|
||||
static auto IsImported(Context& context, ImportKey key) -> bool {
|
||||
CARBON_KIND_SWITCH(key) {
|
||||
case CARBON_KIND(SemIR::ClangDeclKey decl_key):
|
||||
return context.clang_decls().LookupId(decl_key).has_value();
|
||||
case CARBON_KIND(const clang::Type* type):
|
||||
return context.clang_function_pointer_types().Lookup(type).has_value();
|
||||
}
|
||||
}
|
||||
|
||||
// If `decl` already mapped to an instruction, returns that instruction.
|
||||
@@ -1073,7 +1085,7 @@ static auto ImportEnumConstantDecl(Context& context,
|
||||
clang::EnumConstantDecl* enumerator_decl)
|
||||
-> SemIR::InstId {
|
||||
auto key = SemIR::ClangDeclKey(enumerator_decl);
|
||||
CARBON_CHECK(!IsClangDeclImported(context, key));
|
||||
CARBON_CHECK(!IsImported(context, key));
|
||||
|
||||
// Find the enclosing enum type.
|
||||
auto enum_key = SemIR::ClangDeclKey(
|
||||
@@ -1311,6 +1323,20 @@ static auto MapTagType(Context& context, const clang::TagType& type)
|
||||
.type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)};
|
||||
}
|
||||
|
||||
static auto MapFunctionPointerType(Context& context, SemIR::LocId /*loc_id*/,
|
||||
clang::QualType type) -> TypeExpr {
|
||||
CARBON_CHECK(type->isFunctionPointerType());
|
||||
|
||||
auto clang_type_id = context.clang_function_pointer_types().Lookup(
|
||||
type.getCanonicalType().getTypePtr());
|
||||
CARBON_CHECK(clang_type_id.has_value());
|
||||
|
||||
// TODO: wrap the pointer type in `Optional` unless it was marked
|
||||
// non-nullable.
|
||||
return TypeExpr::ForUnsugared(
|
||||
context, GetCppFunctionPointerType(context, clang_type_id));
|
||||
}
|
||||
|
||||
// Maps a C++ type that is not a wrapper type such as a pointer to a Carbon
|
||||
// type.
|
||||
// TODO: Support more types.
|
||||
@@ -1324,6 +1350,10 @@ static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id,
|
||||
return MapTagType(context, *tag_type);
|
||||
}
|
||||
|
||||
if (type->isFunctionPointerType()) {
|
||||
return MapFunctionPointerType(context, loc_id, type);
|
||||
}
|
||||
|
||||
CARBON_CHECK(!type.hasQualifiers() && !type->isPointerType(),
|
||||
"Should not see wrapper types here");
|
||||
|
||||
@@ -1378,11 +1408,11 @@ static auto MakeOptionalType(Context& context, SemIR::LocId loc_id,
|
||||
return ExprAsType(context, loc_id, call_id);
|
||||
}
|
||||
|
||||
// Maps a C++ pointer type to a Carbon pointer type.
|
||||
static auto MapPointerType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type, TypeExpr pointee_type_expr)
|
||||
-> TypeExpr {
|
||||
CARBON_CHECK(type->isPointerType());
|
||||
// Maps a C++ object pointer type to a Carbon pointer type.
|
||||
static auto MapObjectPointerType(Context& context, SemIR::LocId loc_id,
|
||||
clang::QualType type,
|
||||
TypeExpr pointee_type_expr) -> TypeExpr {
|
||||
CARBON_CHECK(type->isObjectPointerType());
|
||||
|
||||
bool optional =
|
||||
!IsClangTypeNonNull(type) &&
|
||||
@@ -1444,7 +1474,7 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
clang::QualType orig_type = type;
|
||||
if (type.hasQualifiers()) {
|
||||
type = ClangGetUnqualifiedTypePreserveNonNull(context, type);
|
||||
} else if (type->isPointerType()) {
|
||||
} else if (type->isObjectPointerType()) {
|
||||
type = type->getPointeeType();
|
||||
} else if (type->isReferenceType()) {
|
||||
type = type.getNonReferenceType();
|
||||
@@ -1466,8 +1496,8 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
|
||||
if (wrapper.hasQualifiers()) {
|
||||
mapped = MapQualifiedType(context, wrapper, mapped);
|
||||
} else if (wrapper->isPointerType()) {
|
||||
mapped = MapPointerType(context, loc_id, wrapper, mapped);
|
||||
} else if (wrapper->isObjectPointerType()) {
|
||||
mapped = MapObjectPointerType(context, loc_id, wrapper, mapped);
|
||||
} else if (wrapper->isReferenceType()) {
|
||||
mapped = MapReferenceType(context, wrapper, mapped);
|
||||
} else if (const auto* array_type = wrapper->getAsArrayTypeUnsafe()) {
|
||||
@@ -1956,6 +1986,50 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id,
|
||||
return decl_id;
|
||||
}
|
||||
|
||||
// Given a C++ callee and its imported Carbon function (as produced by
|
||||
// `ImportFunction`), this builds a simple-ABI thunk that invokes the callee,
|
||||
// and defines the imported function as calling it.
|
||||
static auto DefineAsThunkCall(Context& context, SemIR::LocId loc_id,
|
||||
const CalleeFunctionInfo& callee_info,
|
||||
SemIR::Function& function) -> void {
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCppThunk, Note,
|
||||
"in thunk for C++ function used here");
|
||||
builder.Note(loc_id, InCppThunk);
|
||||
});
|
||||
|
||||
clang::FunctionDecl* thunk_clang_decl = BuildCppThunk(context, callee_info);
|
||||
if (thunk_clang_decl == nullptr) {
|
||||
return;
|
||||
}
|
||||
SemIR::ClangDeclSignature thunk_signature;
|
||||
thunk_signature.kind = SemIR::ClangDeclSignature::Normal;
|
||||
thunk_signature.num_params =
|
||||
static_cast<int32_t>(thunk_clang_decl->getNumParams());
|
||||
thunk_signature.passing_modes.assign(
|
||||
thunk_signature.num_params,
|
||||
SemIR::ClangDeclSignature::PassingMode::ByValue);
|
||||
SemIR::ClangDeclSignatureId thunk_signature_id =
|
||||
context.clang_decl_signatures().Add(std::move(thunk_signature));
|
||||
|
||||
CalleeFunctionInfo thunk_callee_info(context, thunk_clang_decl,
|
||||
thunk_signature_id);
|
||||
auto thunk_decl_id = ImportFunction(context, loc_id, thunk_callee_info);
|
||||
if (thunk_decl_id == std::nullopt) {
|
||||
return;
|
||||
}
|
||||
context.clang_decls().Add({.key = SemIR::ClangDeclKey::ForFunctionDecl(
|
||||
thunk_clang_decl, thunk_signature_id),
|
||||
.inst_id = *thunk_decl_id,
|
||||
.is_imported = true});
|
||||
auto thunk_function_id =
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(*thunk_decl_id).function_id;
|
||||
auto& thunk_function = context.functions().Get(thunk_function_id);
|
||||
thunk_function.SetCppThunk(function.first_owning_decl_id);
|
||||
function.SetHasCppThunk(*thunk_decl_id);
|
||||
}
|
||||
|
||||
// Imports a C++ function, returning a corresponding Carbon function.
|
||||
// `signature` specifies how to convert the C++ function signature to the Carbon
|
||||
// function signature. `signature.num_params` may be less than the number of
|
||||
@@ -2001,41 +2075,7 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(*function_decl_id).function_id;
|
||||
SemIR::Function& imported_function = context.functions().Get(function_id);
|
||||
if (IsCppThunkRequired(context, callee_info)) {
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCppThunk, Note,
|
||||
"in thunk for C++ function used here");
|
||||
builder.Note(loc_id, InCppThunk);
|
||||
});
|
||||
|
||||
if (clang::FunctionDecl* thunk_clang_decl =
|
||||
BuildCppThunk(context, callee_info)) {
|
||||
SemIR::ClangDeclSignature thunk_signature;
|
||||
thunk_signature.kind = SemIR::ClangDeclSignature::Normal;
|
||||
thunk_signature.num_params =
|
||||
static_cast<int32_t>(thunk_clang_decl->getNumParams());
|
||||
thunk_signature.passing_modes.assign(
|
||||
thunk_signature.num_params,
|
||||
SemIR::ClangDeclSignature::PassingMode::ByValue);
|
||||
SemIR::ClangDeclSignatureId thunk_signature_id =
|
||||
context.clang_decl_signatures().Add(std::move(thunk_signature));
|
||||
|
||||
CalleeFunctionInfo thunk_callee_info(context, thunk_clang_decl,
|
||||
thunk_signature_id);
|
||||
if (auto thunk_decl_id =
|
||||
ImportFunction(context, loc_id, thunk_callee_info)) {
|
||||
context.clang_decls().Add({.key = SemIR::ClangDeclKey::ForFunctionDecl(
|
||||
thunk_clang_decl, thunk_signature_id),
|
||||
.inst_id = *thunk_decl_id,
|
||||
.is_imported = true});
|
||||
auto thunk_function_id = context.insts()
|
||||
.GetAs<SemIR::FunctionDecl>(*thunk_decl_id)
|
||||
.function_id;
|
||||
auto& thunk_function = context.functions().Get(thunk_function_id);
|
||||
thunk_function.SetCppThunk(imported_function.first_owning_decl_id);
|
||||
imported_function.SetHasCppThunk(*thunk_decl_id);
|
||||
}
|
||||
}
|
||||
DefineAsThunkCall(context, loc_id, callee_info, imported_function);
|
||||
} else {
|
||||
// Inform Clang that the function has been referenced. This will trigger
|
||||
// instantiation if needed.
|
||||
@@ -2059,13 +2099,70 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
return *function_decl_id;
|
||||
}
|
||||
|
||||
// Imports a C++ function pointer type, and prepares to import its `__invoke`
|
||||
// function. The function itself must be imported separately with
|
||||
// `ImportFunctionPointerInvoke` when it's called, because that requires the
|
||||
// types in the signature to be complete.
|
||||
static auto ImportFunctionPointer(Context& context,
|
||||
const clang::Type* pointer_type)
|
||||
-> SemIR::InstId {
|
||||
CARBON_CHECK(pointer_type->isFunctionPointerType());
|
||||
// Allocate an ID for the function pointer type and return it.
|
||||
pointer_type = clang::QualType(pointer_type, /*Quals=*/0)
|
||||
.getCanonicalType()
|
||||
.getTypePtr();
|
||||
auto clang_type_id =
|
||||
context.clang_function_pointer_types().Lookup(pointer_type);
|
||||
if (!clang_type_id.has_value()) {
|
||||
clang_type_id = context.clang_function_pointer_types().Add(
|
||||
{.clang_type = pointer_type,
|
||||
.decl_id = SemIR::InstId::None,
|
||||
.function_id = SemIR::FunctionId::None});
|
||||
}
|
||||
return context.types().GetTypeInstId(
|
||||
GetCppFunctionPointerType(context, clang_type_id));
|
||||
}
|
||||
|
||||
auto ImportFunctionPointerInvoke(
|
||||
Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ClangFunctionPointerTypeId clang_type_id)
|
||||
-> SemIR::ClangFunctionPointerTypeInfo {
|
||||
const auto& info = context.clang_function_pointer_types().Get(clang_type_id);
|
||||
if (info.decl_id.has_value()) {
|
||||
return info;
|
||||
}
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCppFunctionPointerThunk, Note,
|
||||
"in thunk for C++ function pointer type used here");
|
||||
builder.Note(loc_id, InCppFunctionPointerThunk);
|
||||
});
|
||||
|
||||
CalleeFunctionInfo callee_info(context, info.clang_type);
|
||||
SemIR::ClangFunctionPointerTypeInfo result = {
|
||||
.clang_type = info.clang_type,
|
||||
.decl_id = SemIR::ErrorInst::InstId,
|
||||
.function_id = SemIR::FunctionId::None};
|
||||
auto function_decl_id = ImportFunction(context, loc_id, callee_info);
|
||||
if (function_decl_id.has_value()) {
|
||||
result.decl_id = *function_decl_id;
|
||||
result.function_id = context.insts()
|
||||
.GetAs<SemIR::FunctionDecl>(*function_decl_id)
|
||||
.function_id;
|
||||
DefineAsThunkCall(context, loc_id, callee_info,
|
||||
context.functions().Get(result.function_id));
|
||||
}
|
||||
context.clang_function_pointer_types().Update(clang_type_id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// An item to be imported in an import worklist.
|
||||
// TODO: If worklists ever become particularly large, consider changing this
|
||||
// to use a `PointerIntPair`.
|
||||
// to use a `PointerUnion` and/or `PointerIntPair`.
|
||||
struct ImportItem {
|
||||
// A declaration that we want to import.
|
||||
SemIR::ClangDeclKey decl_key;
|
||||
ImportKey key;
|
||||
// Whether we have added `decl`'s dependencies to the worklist.
|
||||
bool added_dependencies;
|
||||
};
|
||||
@@ -2073,20 +2170,27 @@ struct ImportItem {
|
||||
using ImportWorklist = llvm::SmallVector<ImportItem>;
|
||||
} // namespace
|
||||
|
||||
// Adds the given declaration to our list of declarations to import.
|
||||
static auto AddDependentDecl(Context& context, SemIR::ClangDeclKey decl,
|
||||
ImportWorklist& worklist) -> void {
|
||||
if (!IsClangDeclImported(context, decl)) {
|
||||
worklist.push_back({.decl_key = decl, .added_dependencies = false});
|
||||
// Adds the given declaration to the worklist. As an optimization, does nothing
|
||||
// if the declaration has already been imported.
|
||||
static auto PushDecl(Context& context, SemIR::ClangDeclKey decl,
|
||||
ImportWorklist& worklist) -> void {
|
||||
if (!IsImported(context, decl)) {
|
||||
worklist.push_back({.key = decl, .added_dependencies = false});
|
||||
}
|
||||
}
|
||||
|
||||
// Finds all decls that need to be imported before importing the given type and
|
||||
// adds them to the given set.
|
||||
static auto AddDependentUnimportedTypeDecls(Context& context,
|
||||
clang::QualType type,
|
||||
ImportWorklist& worklist) -> void {
|
||||
// Adds the declarations that the given type directly depends on to the
|
||||
// worklist.
|
||||
static auto PushType(Context& context, clang::QualType type,
|
||||
ImportWorklist& worklist) -> void {
|
||||
while (true) {
|
||||
if (type->isFunctionPointerType()) {
|
||||
const clang::Type* type_ptr = type.getCanonicalType().getTypePtr();
|
||||
if (!IsImported(context, type_ptr)) {
|
||||
worklist.push_back({.key = type_ptr, .added_dependencies = false});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (type->isPointerType() || type->isReferenceType()) {
|
||||
type = type->getPointeeType();
|
||||
} else if (const clang::ArrayType* array_type =
|
||||
@@ -2098,52 +2202,68 @@ static auto AddDependentUnimportedTypeDecls(Context& context,
|
||||
}
|
||||
|
||||
if (const auto* tag_type = type->getAs<clang::TagType>()) {
|
||||
AddDependentDecl(context, SemIR::ClangDeclKey(tag_type->getDecl()),
|
||||
worklist);
|
||||
PushDecl(context, SemIR::ClangDeclKey(tag_type->getDecl()), worklist);
|
||||
}
|
||||
}
|
||||
|
||||
// Finds all decls that need to be imported before importing the given function
|
||||
// and adds them to the given set.
|
||||
static auto AddDependentUnimportedFunctionDecls(
|
||||
Context& context, const clang::FunctionDecl& clang_decl,
|
||||
SemIR::ClangDeclSignatureId signature_id, ImportWorklist& worklist)
|
||||
// Finds all decls that need to be imported before importing the given type,
|
||||
// which must be a `FunctionProtoType`, and adds them to the worklist. If
|
||||
// `num_params` is non-negative, only the first `num_params` parameter types
|
||||
// will be added.
|
||||
static auto AddUnimportedDependenciesForFunctionType(Context& context,
|
||||
clang::QualType type,
|
||||
int num_params,
|
||||
ImportWorklist& worklist)
|
||||
-> void {
|
||||
const auto& signature = context.clang_decl_signatures().Get(signature_id);
|
||||
const auto* function_type =
|
||||
clang_decl.getType()->castAs<clang::FunctionProtoType>();
|
||||
for (int i : llvm::seq(clang_decl.hasCXXExplicitFunctionObjectParameter() +
|
||||
signature.num_params)) {
|
||||
AddDependentUnimportedTypeDecls(context, function_type->getParamType(i),
|
||||
worklist);
|
||||
const auto* function_type = type->castAs<clang::FunctionProtoType>();
|
||||
if (num_params < 0) {
|
||||
num_params = function_type->getNumParams();
|
||||
}
|
||||
AddDependentUnimportedTypeDecls(context, clang_decl.getReturnType(),
|
||||
worklist);
|
||||
for (int i : llvm::seq(num_params)) {
|
||||
PushType(context, function_type->getParamType(i), worklist);
|
||||
}
|
||||
PushType(context, function_type->getReturnType(), worklist);
|
||||
}
|
||||
|
||||
// Finds all decls that need to be imported before importing the given
|
||||
// declaration and adds them to the given set.
|
||||
static auto AddDependentUnimportedDecls(Context& context,
|
||||
SemIR::ClangDeclKey key,
|
||||
ImportWorklist& worklist) -> void {
|
||||
clang::Decl* clang_decl = key.decl;
|
||||
if (auto* clang_function_decl = clang_decl->getAsFunction()) {
|
||||
AddDependentUnimportedFunctionDecls(context, *clang_function_decl,
|
||||
key.signature_id, worklist);
|
||||
} else if (auto* type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
|
||||
if (!isa<clang::TagDecl>(clang_decl)) {
|
||||
AddDependentUnimportedTypeDecls(
|
||||
context, type_decl->getASTContext().getTypeDeclType(type_decl),
|
||||
worklist);
|
||||
// declaration and adds them to the worklist.
|
||||
static auto AddUnimportedDependencies(Context& context, ImportKey key,
|
||||
ImportWorklist& worklist) -> void {
|
||||
CARBON_KIND_SWITCH(key) {
|
||||
case CARBON_KIND(SemIR::ClangDeclKey decl_key): {
|
||||
clang::Decl* clang_decl = decl_key.decl;
|
||||
if (auto* clang_function_decl = clang_decl->getAsFunction()) {
|
||||
const auto& signature =
|
||||
context.clang_decl_signatures().Get(decl_key.signature_id);
|
||||
int num_params =
|
||||
clang_function_decl->hasCXXExplicitFunctionObjectParameter() +
|
||||
signature.num_params;
|
||||
AddUnimportedDependenciesForFunctionType(
|
||||
context, clang_function_decl->getType(), num_params, worklist);
|
||||
} else if (auto* type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
|
||||
if (!isa<clang::TagDecl>(clang_decl)) {
|
||||
PushType(context,
|
||||
type_decl->getASTContext().getTypeDeclType(type_decl),
|
||||
worklist);
|
||||
}
|
||||
} else if (auto* var_decl = dyn_cast<clang::VarDecl>(clang_decl)) {
|
||||
PushType(context, var_decl->getType(), worklist);
|
||||
}
|
||||
auto* parent = GetParentDecl(clang_decl);
|
||||
if (llvm::isa_and_nonnull<clang::TagDecl, clang::NamespaceDecl,
|
||||
clang::TranslationUnitDecl>(parent)) {
|
||||
PushDecl(context, SemIR::ClangDeclKey::ForNonFunctionDecl(parent),
|
||||
worklist);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(const clang::Type* type): {
|
||||
if (type->isFunctionPointerType()) {
|
||||
AddUnimportedDependenciesForFunctionType(
|
||||
context, type->getPointeeType(), -1, worklist);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (auto* var_decl = dyn_cast<clang::VarDecl>(clang_decl)) {
|
||||
AddDependentUnimportedTypeDecls(context, var_decl->getType(), worklist);
|
||||
}
|
||||
auto* parent = GetParentDecl(clang_decl);
|
||||
if (llvm::isa_and_nonnull<clang::TagDecl, clang::NamespaceDecl,
|
||||
clang::TranslationUnitDecl>(parent)) {
|
||||
AddDependentDecl(context, SemIR::ClangDeclKey::ForNonFunctionDecl(parent),
|
||||
worklist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2243,54 +2363,72 @@ static auto ImportTemplateDecl(Context& context,
|
||||
// Imports a declaration from Clang to Carbon. Returns the instruction for the
|
||||
// new Carbon declaration, which will be an ErrorInst on failure. Assumes all
|
||||
// dependencies have already been imported.
|
||||
static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ClangDeclKey key)
|
||||
-> SemIR::InstId {
|
||||
clang::Decl* clang_decl = key.decl;
|
||||
if (auto* clang_function_decl = clang_decl->getAsFunction()) {
|
||||
return ImportFunctionDecl(context, loc_id, clang_function_decl,
|
||||
key.signature_id);
|
||||
}
|
||||
if (auto* clang_namespace_decl = dyn_cast<clang::NamespaceDecl>(clang_decl)) {
|
||||
return ImportNamespaceDecl(context, clang_namespace_decl);
|
||||
}
|
||||
if (auto* type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
|
||||
auto type = clang_decl->getASTContext().getTypeDeclType(type_decl);
|
||||
auto type_inst_id = MapType(context, loc_id, type).inst_id;
|
||||
if (!type_inst_id.has_value()) {
|
||||
context.TODO(AddImportIRInst(context.sem_ir(), type_decl->getLocation()),
|
||||
llvm::formatv("Unsupported: Type declaration: {0}",
|
||||
type.getAsString()));
|
||||
static auto ImportAfterDependencies(Context& context, SemIR::LocId loc_id,
|
||||
ImportKey key) -> SemIR::InstId {
|
||||
CARBON_KIND_SWITCH(key) {
|
||||
case CARBON_KIND(SemIR::ClangDeclKey decl_key): {
|
||||
clang::Decl* clang_decl = decl_key.decl;
|
||||
if (auto* clang_function_decl = clang_decl->getAsFunction()) {
|
||||
return ImportFunctionDecl(context, loc_id, clang_function_decl,
|
||||
decl_key.signature_id);
|
||||
}
|
||||
if (auto* clang_namespace_decl =
|
||||
dyn_cast<clang::NamespaceDecl>(clang_decl)) {
|
||||
return ImportNamespaceDecl(context, clang_namespace_decl);
|
||||
}
|
||||
if (auto* type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
|
||||
auto type = clang_decl->getASTContext().getTypeDeclType(type_decl);
|
||||
auto type_inst_id = MapType(context, loc_id, type).inst_id;
|
||||
if (!type_inst_id.has_value()) {
|
||||
context.TODO(
|
||||
AddImportIRInst(context.sem_ir(), type_decl->getLocation()),
|
||||
llvm::formatv("Unsupported: Type declaration: {0}",
|
||||
type.getAsString()));
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
context.clang_decls().Add(
|
||||
{.key = decl_key, .inst_id = type_inst_id, .is_imported = true});
|
||||
return type_inst_id;
|
||||
}
|
||||
if (isa<clang::FieldDecl, clang::IndirectFieldDecl>(clang_decl)) {
|
||||
// Usable fields get imported as a side effect of importing the class.
|
||||
if (SemIR::InstId existing_inst_id =
|
||||
LookupClangDeclInstId(context, decl_key);
|
||||
existing_inst_id.has_value()) {
|
||||
return existing_inst_id;
|
||||
}
|
||||
context.TODO(
|
||||
AddImportIRInst(context.sem_ir(), clang_decl->getLocation()),
|
||||
"Unsupported: field declaration has unhandled type or kind");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
if (auto* enum_const_decl =
|
||||
dyn_cast<clang::EnumConstantDecl>(clang_decl)) {
|
||||
return ImportEnumConstantDecl(context, enum_const_decl);
|
||||
}
|
||||
if (auto* var_decl = dyn_cast<clang::VarDecl>(clang_decl)) {
|
||||
return ImportVarDecl(context, loc_id, var_decl);
|
||||
}
|
||||
if (auto* template_decl = dyn_cast<clang::TemplateDecl>(clang_decl)) {
|
||||
return ImportTemplateDecl(context, template_decl);
|
||||
}
|
||||
|
||||
context.TODO(AddImportIRInst(context.sem_ir(), clang_decl->getLocation()),
|
||||
llvm::formatv("Unsupported: Declaration type {0}",
|
||||
clang_decl->getDeclKindName()));
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
context.clang_decls().Add(
|
||||
{.key = key, .inst_id = type_inst_id, .is_imported = true});
|
||||
return type_inst_id;
|
||||
}
|
||||
if (isa<clang::FieldDecl, clang::IndirectFieldDecl>(clang_decl)) {
|
||||
// Usable fields get imported as a side effect of importing the class.
|
||||
if (SemIR::InstId existing_inst_id = LookupClangDeclInstId(context, key);
|
||||
existing_inst_id.has_value()) {
|
||||
return existing_inst_id;
|
||||
}
|
||||
context.TODO(AddImportIRInst(context.sem_ir(), clang_decl->getLocation()),
|
||||
"Unsupported: field declaration has unhandled type or kind");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
if (auto* enum_const_decl = dyn_cast<clang::EnumConstantDecl>(clang_decl)) {
|
||||
return ImportEnumConstantDecl(context, enum_const_decl);
|
||||
}
|
||||
if (auto* var_decl = dyn_cast<clang::VarDecl>(clang_decl)) {
|
||||
return ImportVarDecl(context, loc_id, var_decl);
|
||||
}
|
||||
if (auto* template_decl = dyn_cast<clang::TemplateDecl>(clang_decl)) {
|
||||
return ImportTemplateDecl(context, template_decl);
|
||||
}
|
||||
case CARBON_KIND(const clang::Type* type): {
|
||||
if (type->isFunctionPointerType()) {
|
||||
return ImportFunctionPointer(context, type);
|
||||
}
|
||||
|
||||
context.TODO(AddImportIRInst(context.sem_ir(), clang_decl->getLocation()),
|
||||
llvm::formatv("Unsupported: Declaration type {0}",
|
||||
clang_decl->getDeclKindName()));
|
||||
return SemIR::ErrorInst::InstId;
|
||||
context.TODO(loc_id,
|
||||
llvm::formatv("Unsupported: type {0}",
|
||||
clang::QualType(type, 0).getAsString()));
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to import a set of declarations. Returns `false` if an error was
|
||||
@@ -2306,7 +2444,7 @@ static auto ImportDeclSet(Context& context, SemIR::LocId loc_id,
|
||||
// adding the item to the worklist, but it might have been added to the
|
||||
// worklist twice before the first time we visited it. For example, this
|
||||
// happens for `fn F(a: Cpp.T, b: Cpp.T)`.
|
||||
if (IsClangDeclImported(context, item.decl_key)) {
|
||||
if (IsImported(context, item.key)) {
|
||||
worklist.pop_back();
|
||||
continue;
|
||||
}
|
||||
@@ -2314,17 +2452,17 @@ static auto ImportDeclSet(Context& context, SemIR::LocId loc_id,
|
||||
// First time visiting this declaration (preorder): add its dependencies
|
||||
// to the work list.
|
||||
item.added_dependencies = true;
|
||||
AddDependentUnimportedDecls(context, item.decl_key, worklist);
|
||||
AddUnimportedDependencies(context, item.key, worklist);
|
||||
} else {
|
||||
// Second time visiting this declaration (postorder): its dependencies are
|
||||
// already imported, so we can import it now.
|
||||
auto decl_key = worklist.pop_back_val().decl_key;
|
||||
auto inst_id = ImportDeclAfterDependencies(context, loc_id, decl_key);
|
||||
auto decl_key = worklist.pop_back_val().key;
|
||||
auto inst_id = ImportAfterDependencies(context, loc_id, decl_key);
|
||||
CARBON_CHECK(inst_id.has_value());
|
||||
if (inst_id == SemIR::ErrorInst::InstId) {
|
||||
return false;
|
||||
}
|
||||
CARBON_CHECK(IsClangDeclImported(context, decl_key));
|
||||
CARBON_CHECK(IsImported(context, decl_key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2335,7 +2473,7 @@ auto ImportCppDecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ClangDeclKey key) -> SemIR::InstId {
|
||||
// Collect dependencies by walking the dependency graph in depth-first order.
|
||||
ImportWorklist worklist;
|
||||
AddDependentDecl(context, key, worklist);
|
||||
PushDecl(context, key, worklist);
|
||||
if (!ImportDeclSet(context, loc_id, worklist)) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
@@ -2346,7 +2484,7 @@ auto ImportCppType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
-> TypeExpr {
|
||||
// Collect dependencies by walking the dependency graph in depth-first order.
|
||||
ImportWorklist worklist;
|
||||
AddDependentUnimportedTypeDecls(context, type, worklist);
|
||||
PushType(context, type, worklist);
|
||||
if (!ImportDeclSet(context, loc_id, worklist)) {
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
|
||||
Reference in New Issue
Block a user