@@ -656,8 +656,11 @@ static auto LookupClangDeclInstId(const Context& context, clang::Decl* decl)
656
656
// Returns the parent of the given declaration. Skips declaration types we
657
657
// ignore.
658
658
static auto GetParentDecl (clang::Decl* clang_decl) -> clang::Decl* {
659
- return cast<clang::Decl>(
660
- clang_decl->getDeclContext ()->getNonTransparentContext ());
659
+ auto * parent_dc = clang_decl->getDeclContext ();
660
+ while (!parent_dc->isLookupContext ()) {
661
+ parent_dc = parent_dc->getParent ();
662
+ }
663
+ return cast<clang::Decl>(parent_dc);
661
664
}
662
665
663
666
// Returns the given declaration's parent scope. Assumes the parent declaration
@@ -756,10 +759,10 @@ static auto BuildClassDecl(Context& context,
756
759
return {class_decl.class_id , context.types ().GetAsTypeInstId (class_decl_id)};
757
760
}
758
761
759
- // Imports a record declaration from Clang to Carbon. If successful, returns
760
- // the new Carbon class declaration `InstId`.
761
- static auto ImportCXXRecordDecl (Context& context,
762
- clang::CXXRecordDecl * clang_decl)
762
+ // Imports a tag declaration from Clang to Carbon. This covers classes (which
763
+ // includes structs and unions) as well as enums. If successful, returns the new
764
+ // Carbon class declaration `InstId`.
765
+ static auto ImportTagDecl (Context& context, clang::TagDecl * clang_decl)
763
766
-> SemIR::InstId {
764
767
auto import_ir_inst_id =
765
768
AddImportIRInst (context.sem_ir (), clang_decl->getLocation ());
@@ -973,8 +976,8 @@ static auto ImportClassObjectRepr(Context& context, SemIR::ClassId class_id,
973
976
.layout_id = context.custom_layouts ().Add (layout)});
974
977
}
975
978
976
- // Creates a class definition based on the information in the given Clang
977
- // declaration, which is assumed to be for a class definition.
979
+ // Creates a Carbon class definition based on the information in the given Clang
980
+ // class declaration, which is assumed to be for a class definition.
978
981
static auto BuildClassDefinition (Context& context,
979
982
SemIR::ImportIRInstId import_ir_inst_id,
980
983
SemIR::ClassId class_id,
@@ -999,13 +1002,70 @@ static auto BuildClassDefinition(Context& context,
999
1002
class_info.body_block_id = context.inst_block_stack ().Pop ();
1000
1003
}
1001
1004
1002
- auto ImportCppClassDefinition (Context& context, SemIR::LocId loc_id,
1003
- SemIR::ClassId class_id,
1004
- SemIR::ClangDeclId clang_decl_id) -> bool {
1005
+ // Computes and returns the Carbon type to use as the object representation of
1006
+ // the given C++ enum type. This is a builtin int type matching the enum's
1007
+ // representation.
1008
+ static auto ImportEnumObjectRepresentation (
1009
+ Context& context, SemIR::ImportIRInstId import_ir_inst_id,
1010
+ clang::EnumDecl* enum_decl) -> SemIR::TypeInstId {
1011
+ auto int_type = enum_decl->getIntegerType ();
1012
+ CARBON_CHECK (!int_type.isNull (), " incomplete enum type {0}" ,
1013
+ enum_decl->getNameAsString ());
1014
+
1015
+ auto int_kind = int_type->isSignedIntegerType () ? SemIR::IntKind::Signed
1016
+ : SemIR::IntKind::Unsigned;
1017
+ auto bit_width_id = GetOrAddInst<SemIR::IntValue>(
1018
+ context, import_ir_inst_id,
1019
+ {.type_id = GetSingletonType (context, SemIR::IntLiteralType::TypeInstId),
1020
+ .int_id = context.ints ().AddUnsigned (
1021
+ llvm::APInt (64 , context.ast_context ().getIntWidth (int_type)))});
1022
+ return context.types ().GetAsTypeInstId (
1023
+ GetOrAddInst (context, SemIR::LocIdAndInst::NoLoc (SemIR::IntType{
1024
+ .type_id = SemIR::TypeType::TypeId,
1025
+ .int_kind = int_kind,
1026
+ .bit_width_id = bit_width_id})));
1027
+ }
1028
+
1029
+ // Creates a Carbon class definition based on the information in the given Clang
1030
+ // enum declaration.
1031
+ static auto BuildEnumDefinition (Context& context,
1032
+ SemIR::ImportIRInstId import_ir_inst_id,
1033
+ SemIR::ClassId class_id,
1034
+ SemIR::TypeInstId class_inst_id,
1035
+ clang::EnumDecl* enum_decl) -> void {
1036
+ auto & class_info = context.classes ().Get (class_id);
1037
+ CARBON_CHECK (!class_info.has_definition_started ());
1038
+ class_info.definition_id = class_inst_id;
1039
+
1040
+ context.inst_block_stack ().Push ();
1041
+
1042
+ // Don't allow inheritance from C++ enums, to match the behavior in C++.
1043
+ class_info.inheritance_kind = SemIR::Class::Final;
1044
+
1045
+ // Compute the enum type's object representation. An enum is an adapter for
1046
+ // the corresponding builtin integer type.
1047
+ auto object_repr_id =
1048
+ ImportEnumObjectRepresentation (context, import_ir_inst_id, enum_decl);
1049
+ class_info.adapt_id = AddInst (
1050
+ context, SemIR::LocIdAndInst::UncheckedLoc (
1051
+ import_ir_inst_id,
1052
+ SemIR::AdaptDecl{.adapted_type_inst_id = object_repr_id}));
1053
+ class_info.complete_type_witness_id = AddInst<SemIR::CompleteTypeWitness>(
1054
+ context, import_ir_inst_id,
1055
+ {.type_id = GetSingletonType (context, SemIR::WitnessType::TypeInstId),
1056
+ .object_repr_type_inst_id = object_repr_id});
1057
+
1058
+ class_info.body_block_id = context.inst_block_stack ().Pop ();
1059
+ }
1060
+
1061
+ auto ImportClassDefinitionForClangDecl (Context& context, SemIR::LocId loc_id,
1062
+ SemIR::ClassId class_id,
1063
+ SemIR::ClangDeclId clang_decl_id)
1064
+ -> bool {
1005
1065
clang::ASTUnit* ast = context.sem_ir ().clang_ast_unit ();
1006
1066
CARBON_CHECK (ast);
1007
1067
1008
- auto * clang_decl = cast<clang::CXXRecordDecl >(
1068
+ auto * clang_decl = cast<clang::TagDecl >(
1009
1069
context.sem_ir ().clang_decls ().Get (clang_decl_id).decl );
1010
1070
auto class_inst_id = context.types ().GetAsTypeInstId (
1011
1071
context.classes ().Get (class_id).first_owning_decl_id );
@@ -1017,7 +1077,7 @@ auto ImportCppClassDefinition(Context& context, SemIR::LocId loc_id,
1017
1077
Diagnostics::AnnotationScope annotate_diagnostics (
1018
1078
&context.emitter (), [&](auto & builder) {
1019
1079
CARBON_DIAGNOSTIC (InCppTypeCompletion, Note,
1020
- " while completing C++ class type {0}" , SemIR::TypeId);
1080
+ " while completing C++ type {0}" , SemIR::TypeId);
1021
1081
builder.Note (loc_id, InCppTypeCompletion,
1022
1082
context.classes ().Get (class_id).self_type_id );
1023
1083
});
@@ -1026,33 +1086,62 @@ auto ImportCppClassDefinition(Context& context, SemIR::LocId loc_id,
1026
1086
// instantiation if necessary.
1027
1087
clang::DiagnosticErrorTrap trap (ast->getDiagnostics ());
1028
1088
if (!ast->getSema ().isCompleteType (
1029
- loc, context.ast_context ().getRecordType (clang_decl))) {
1089
+ loc, context.ast_context ().getTypeDeclType (clang_decl))) {
1030
1090
// Type is incomplete. Nothing more to do, but tell the caller if we
1031
1091
// produced an error.
1032
1092
return !trap.hasErrorOccurred ();
1033
1093
}
1034
1094
1035
- clang::CXXRecordDecl* clang_def = clang_decl->getDefinition ();
1036
- CARBON_CHECK (clang_def, " Complete type has no definition" );
1037
-
1038
- if (clang_def->getNumVBases ()) {
1039
- // TODO: Handle virtual bases. We don't actually know where they go in the
1040
- // layout. We may also want to use a different size in the layout for
1041
- // `partial C`, excluding the virtual base. It's also not entirely safe to
1042
- // just skip over the virtual base, as the type we would construct would
1043
- // have a misleading size. For now, treat a C++ class with vbases as
1044
- // incomplete in Carbon.
1045
- context.TODO (loc_id, " class with virtual bases" );
1046
- return false ;
1047
- }
1048
-
1049
1095
auto import_ir_inst_id =
1050
1096
context.insts ().GetCanonicalLocId (class_inst_id).import_ir_inst_id ();
1051
- BuildClassDefinition (context, import_ir_inst_id, class_id, class_inst_id,
1052
- clang_def);
1097
+
1098
+ if (auto * class_decl = dyn_cast<clang::CXXRecordDecl>(clang_decl)) {
1099
+ auto * class_def = class_decl->getDefinition ();
1100
+ CARBON_CHECK (class_def, " Complete type has no definition" );
1101
+
1102
+ if (class_def->getNumVBases ()) {
1103
+ // TODO: Handle virtual bases. We don't actually know where they go in the
1104
+ // layout. We may also want to use a different size in the layout for
1105
+ // `partial C`, excluding the virtual base. It's also not entirely safe to
1106
+ // just skip over the virtual base, as the type we would construct would
1107
+ // have a misleading size. For now, treat a C++ class with vbases as
1108
+ // incomplete in Carbon.
1109
+ context.TODO (loc_id, " class with virtual bases" );
1110
+ return false ;
1111
+ }
1112
+
1113
+ BuildClassDefinition (context, import_ir_inst_id, class_id, class_inst_id,
1114
+ class_def);
1115
+ } else if (auto * enum_decl = dyn_cast<clang::EnumDecl>(clang_decl)) {
1116
+ BuildEnumDefinition (context, import_ir_inst_id, class_id, class_inst_id,
1117
+ enum_decl);
1118
+ }
1053
1119
return true ;
1054
1120
}
1055
1121
1122
+ // Imports an enumerator declaration from Clang to Carbon.
1123
+ static auto ImportEnumConstantDecl (Context& context,
1124
+ clang::EnumConstantDecl* enumerator_decl)
1125
+ -> SemIR::InstId {
1126
+ CARBON_CHECK (!IsClangDeclImported (context, enumerator_decl));
1127
+
1128
+ // Find the enclosing enum type.
1129
+ auto type_inst_id = LookupClangDeclInstId (
1130
+ context, cast<clang::EnumDecl>(enumerator_decl->getDeclContext ()));
1131
+ auto type_id = context.types ().GetTypeIdForTypeInstId (type_inst_id);
1132
+
1133
+ // Build a corresponding IntValue.
1134
+ auto int_id = context.ints ().Add (enumerator_decl->getInitVal ());
1135
+ auto loc_id =
1136
+ AddImportIRInst (context.sem_ir (), enumerator_decl->getLocation ());
1137
+ auto inst_id = AddInstInNoBlock<SemIR::IntValue>(
1138
+ context, loc_id, {.type_id = type_id, .int_id = int_id});
1139
+ context.imports ().push_back (inst_id);
1140
+ context.sem_ir ().clang_decls ().Add (
1141
+ {.decl = enumerator_decl->getCanonicalDecl (), .inst_id = inst_id});
1142
+ return inst_id;
1143
+ }
1144
+
1056
1145
// Mark the given `Decl` as failed in `clang_decls`.
1057
1146
static auto MarkFailedDecl (Context& context, clang::Decl* clang_decl) {
1058
1147
context.sem_ir ().clang_decls ().Add ({.decl = clang_decl->getCanonicalDecl (),
@@ -1114,18 +1203,16 @@ static auto MapBuiltinType(Context& context, SemIR::LocId loc_id,
1114
1203
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
1115
1204
}
1116
1205
1117
- // Maps a C++ record type to a Carbon type.
1118
- static auto MapRecordType (Context& context, const clang::RecordType & type)
1206
+ // Maps a C++ tag type (class, struct, union, enum) to a Carbon type.
1207
+ static auto MapTagType (Context& context, const clang::TagType & type)
1119
1208
-> TypeExpr {
1120
- auto * record_decl = dyn_cast<clang::CXXRecordDecl>(type.getDecl ());
1121
- if (!record_decl) {
1122
- return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
1123
- }
1209
+ auto * tag_decl = type.getDecl ();
1210
+ CARBON_CHECK (tag_decl);
1124
1211
1125
1212
// Check if the declaration is already mapped.
1126
- SemIR::InstId record_inst_id = LookupClangDeclInstId (context, record_decl );
1213
+ SemIR::InstId record_inst_id = LookupClangDeclInstId (context, tag_decl );
1127
1214
if (!record_inst_id.has_value ()) {
1128
- record_inst_id = ImportCXXRecordDecl (context, record_decl );
1215
+ record_inst_id = ImportTagDecl (context, tag_decl );
1129
1216
}
1130
1217
SemIR::TypeInstId record_type_inst_id =
1131
1218
context.types ().GetAsTypeInstId (record_inst_id);
@@ -1143,8 +1230,8 @@ static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id,
1143
1230
return MapBuiltinType (context, loc_id, type, *builtin_type);
1144
1231
}
1145
1232
1146
- if (const auto * record_type = type->getAs <clang::RecordType >()) {
1147
- return MapRecordType (context, *record_type );
1233
+ if (const auto * tag_type = type->getAs <clang::TagType >()) {
1234
+ return MapTagType (context, *tag_type );
1148
1235
}
1149
1236
1150
1237
CARBON_CHECK (!type.hasQualifiers () && !type->isPointerType (),
@@ -1640,8 +1727,8 @@ static auto AddDependentUnimportedTypeDecls(const Context& context,
1640
1727
}
1641
1728
}
1642
1729
1643
- if (const auto * record_type = type->getAs <clang::RecordType >()) {
1644
- AddDependentDecl (context, record_type ->getDecl (), worklist);
1730
+ if (const auto * tag_type = type->getAs <clang::TagType >()) {
1731
+ AddDependentDecl (context, tag_type ->getDecl (), worklist);
1645
1732
}
1646
1733
}
1647
1734
@@ -1666,7 +1753,7 @@ static auto AddDependentUnimportedDecls(const Context& context,
1666
1753
AddDependentUnimportedFunctionDecls (context, *clang_function_decl,
1667
1754
worklist);
1668
1755
} else if (auto * type_decl = dyn_cast<clang::TypeDecl>(clang_decl)) {
1669
- if (!isa<clang::RecordDecl >(clang_decl)) {
1756
+ if (!isa<clang::TagDecl >(clang_decl)) {
1670
1757
AddDependentUnimportedTypeDecls (
1671
1758
context, type_decl->getASTContext ().getTypeDeclType (type_decl),
1672
1759
worklist);
@@ -1713,6 +1800,9 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id,
1713
1800
" Unsupported: field declaration has unhandled type or kind" );
1714
1801
return SemIR::ErrorInst::InstId;
1715
1802
}
1803
+ if (auto * enum_const_decl = dyn_cast<clang::EnumConstantDecl>(clang_decl)) {
1804
+ return ImportEnumConstantDecl (context, enum_const_decl);
1805
+ }
1716
1806
1717
1807
context.TODO (AddImportIRInst (context.sem_ir (), clang_decl->getLocation ()),
1718
1808
llvm::formatv (" Unsupported: Declaration type {0}" ,
0 commit comments