Skip to content

Commit 26e23ea

Browse files
authored
Support import of typedefs. (#5787)
Unify code paths for importing classes by name and importing them indirectly when their type is referenced. Switch to using the general type import machinery to import all type declarations, which allows typedef declarations naming importable types to be used too. Fix up handling of error cases to consistently only produce an Error InstId after actually producing an error message, so that we can produce exactly one diagnostic in failure cases. Remove TODO error for unions that previously was only produced when importing them indirectly, not when importing them by name. Import of unions is exactly as complete / incomplete as import of other class types, so treating them differently doesn't seem necessary.
1 parent 6ca4e2e commit 26e23ea

File tree

10 files changed

+816
-538
lines changed

10 files changed

+816
-538
lines changed

toolchain/check/import_cpp.cpp

Lines changed: 55 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,12 @@ static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id,
618618
return SemIR::ErrorInst::InstId;
619619
}
620620

621+
if (clang_def->isUnion() && !clang_def->fields().empty()) {
622+
context.TODO(loc_id, "Unsupported: Non-empty union");
623+
MarkFailedDecl(context, clang_decl);
624+
return SemIR::ErrorInst::InstId;
625+
}
626+
621627
auto [class_id, class_def_id] =
622628
BuildClassDefinition(context, parent_scope_id, name_id, clang_def);
623629

@@ -662,61 +668,60 @@ static auto MapBuiltinType(Context& context, const clang::BuiltinType& type)
662668
default:
663669
break;
664670
}
665-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
666-
.type_id = SemIR::ErrorInst::TypeId};
671+
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
667672
}
668673

669674
// Maps a C++ record type to a Carbon type.
670675
// TODO: Support more record types.
671676
static auto MapRecordType(Context& context, SemIR::LocId loc_id,
672677
const clang::RecordType& type) -> TypeExpr {
673678
auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(type.getDecl());
674-
if (record_decl && !record_decl->isUnion()) {
675-
auto& clang_decls = context.sem_ir().clang_decls();
676-
SemIR::InstId record_inst_id = SemIR::InstId::None;
677-
if (auto record_clang_decl_id = clang_decls.Lookup(record_decl);
678-
record_clang_decl_id.has_value()) {
679-
record_inst_id = clang_decls.Get(record_clang_decl_id).inst_id;
680-
} else {
681-
auto parent_inst_id =
682-
AsCarbonNamespace(context, record_decl->getDeclContext());
683-
auto parent_name_scope_id =
684-
context.insts().GetAs<SemIR::Namespace>(parent_inst_id).name_scope_id;
685-
SemIR::NameId record_name_id =
686-
AddIdentifierName(context, record_decl->getName());
687-
record_inst_id = ImportCXXRecordDecl(
688-
context, loc_id, parent_name_scope_id, record_name_id, record_decl);
689-
AddNameToScope(context, parent_name_scope_id, record_name_id,
690-
record_inst_id);
691-
}
692-
SemIR::TypeInstId record_type_inst_id =
693-
context.types().GetAsTypeInstId(record_inst_id);
694-
return {
695-
.inst_id = record_type_inst_id,
696-
.type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)};
679+
if (!record_decl) {
680+
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
697681
}
698682

699-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
700-
.type_id = SemIR::ErrorInst::TypeId};
683+
auto& clang_decls = context.sem_ir().clang_decls();
684+
SemIR::InstId record_inst_id = SemIR::InstId::None;
685+
if (auto record_clang_decl_id = clang_decls.Lookup(record_decl);
686+
record_clang_decl_id.has_value()) {
687+
record_inst_id = clang_decls.Get(record_clang_decl_id).inst_id;
688+
} else {
689+
auto parent_inst_id =
690+
AsCarbonNamespace(context, record_decl->getDeclContext());
691+
auto parent_name_scope_id =
692+
context.insts().GetAs<SemIR::Namespace>(parent_inst_id).name_scope_id;
693+
SemIR::NameId record_name_id =
694+
AddIdentifierName(context, record_decl->getName());
695+
record_inst_id = ImportCXXRecordDecl(context, loc_id, parent_name_scope_id,
696+
record_name_id, record_decl);
697+
}
698+
SemIR::TypeInstId record_type_inst_id =
699+
context.types().GetAsTypeInstId(record_inst_id);
700+
return {
701+
.inst_id = record_type_inst_id,
702+
.type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)};
701703
}
702704

703705
// Maps a C++ non-pointer type to a Carbon type.
704706
// TODO: Support more types.
705707
static auto MapNonPointerType(Context& context, SemIR::LocId loc_id,
706708
clang::QualType type) -> TypeExpr {
707-
type = type.getCanonicalType();
709+
if (type.hasQualifiers()) {
710+
// TODO: Support type qualifiers.
711+
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
712+
}
713+
708714
CARBON_CHECK(!type->isPointerType());
709715

710-
if (const auto* builtin_type = dyn_cast<clang::BuiltinType>(type)) {
716+
if (const auto* builtin_type = type->getAs<clang::BuiltinType>()) {
711717
return MapBuiltinType(context, *builtin_type);
712718
}
713719

714-
if (const auto* record_type = clang::dyn_cast<clang::RecordType>(type)) {
720+
if (const auto* record_type = type->getAs<clang::RecordType>()) {
715721
return MapRecordType(context, loc_id, *record_type);
716722
}
717723

718-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
719-
.type_id = SemIR::ErrorInst::TypeId};
724+
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
720725
}
721726

722727
// Maps a C++ pointer type to a Carbon pointer type.
@@ -744,10 +749,8 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id,
744749
}
745750

746751
TypeExpr pointee_type_expr = MapNonPointerType(context, loc_id, pointee_type);
747-
if (pointee_type_expr.inst_id == SemIR::ErrorInst::InstId ||
748-
pointee_type_expr.type_id == SemIR::ErrorInst::TypeId) {
749-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
750-
.type_id = SemIR::ErrorInst::TypeId};
752+
if (!pointee_type_expr.inst_id.has_value()) {
753+
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
751754
}
752755

753756
SemIR::TypeId pointer_type_id =
@@ -770,7 +773,7 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
770773
// Returns a block id for the explicit parameters of the given function
771774
// declaration. If the function declaration has no parameters, it returns
772775
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
773-
// returns `SemIR::InstBlockId::None`.
776+
// produces an error and returns `SemIR::InstBlockId::None`.
774777
// TODO: Consider refactoring to extract and reuse more logic from
775778
// `HandleAnyBindingPattern()`.
776779
static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
@@ -794,7 +797,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
794797
SemIR::ExprRegionId type_expr_region_id =
795798
EndSubpatternAsExpr(context, type_inst_id);
796799

797-
if (type_id == SemIR::ErrorInst::TypeId) {
800+
if (!type_id.has_value()) {
798801
context.TODO(loc_id, llvm::formatv("Unsupported: parameter type: {0}",
799802
param_type.getAsString()));
800803
return SemIR::InstBlockId::None;
@@ -830,7 +833,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
830833
}
831834

832835
// Returns the return type of the given function declaration. In case of an
833-
// unsupported return type, it returns `SemIR::ErrorInst::InstId`.
836+
// unsupported return type, it produces a diagnostic and returns
837+
// `SemIR::ErrorInst::InstId`.
834838
// TODO: Support more return types.
835839
static auto GetReturnType(Context& context, SemIR::LocId loc_id,
836840
const clang::FunctionDecl* clang_decl)
@@ -841,7 +845,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
841845
}
842846

843847
auto [type_inst_id, type_id] = MapType(context, loc_id, ret_type);
844-
if (type_id == SemIR::ErrorInst::TypeId) {
848+
if (!type_inst_id.has_value()) {
845849
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
846850
ret_type.getAsString()));
847851
return SemIR::ErrorInst::InstId;
@@ -878,8 +882,8 @@ struct FunctionParamsInsts {
878882
// to create the Call parameters instructions block. Currently the implicit
879883
// parameter patterns are not taken into account. Returns the parameter patterns
880884
// block id, the return slot pattern id, and the call parameters block id.
881-
// Returns `std::nullopt` if the function declaration has an unsupported
882-
// parameter type.
885+
// Produces a diagnostic and returns `std::nullopt` if the function declaration
886+
// has an unsupported parameter type.
883887
static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
884888
const clang::FunctionDecl* clang_decl)
885889
-> std::optional<FunctionParamsInsts> {
@@ -992,10 +996,15 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id,
992996
return ImportNamespaceDecl(context, scope_id, name_id,
993997
clang_namespace_decl);
994998
}
995-
if (auto* clang_record_decl =
996-
clang::dyn_cast<clang::CXXRecordDecl>(clang_decl)) {
997-
return ImportCXXRecordDecl(context, loc_id, scope_id, name_id,
998-
clang_record_decl);
999+
if (auto* type_decl = clang::dyn_cast<clang::TypeDecl>(clang_decl)) {
1000+
auto type = type_decl->getASTContext().getTypeDeclType(type_decl);
1001+
auto type_inst_id = MapType(context, loc_id, type).inst_id;
1002+
if (!type_inst_id.has_value()) {
1003+
context.TODO(loc_id, llvm::formatv("Unsupported: Type declaration: {0}",
1004+
type.getAsString()));
1005+
return SemIR::ErrorInst::InstId;
1006+
}
1007+
return type_inst_id;
9991008
}
10001009

10011010
context.TODO(loc_id, llvm::formatv("Unsupported: Declaration type {0}",

0 commit comments

Comments
 (0)