Export fields of imported Carbon classes to C++ (#8021)

When a Carbon class from another library was used from C++, its fields
were never exported, so C++ member access failed with 'no member named'.
The class scope of an imported class holds import references rather than
`FieldDecl`s, so `LookupClassFieldByStructField` didn't find them.
Resolve scope entries to their constant `FieldDecl`, load the import
references before exporting fields, and consistently key exported fields
by the `FieldDecl`.

Unfortunately `SemIR::LookupClassFieldByStructField` can't call
`LoadImportRef` because `SemIR::LookupClassFieldByStructField` is in
`SemIR` and `LoadImportRef` needs a `Check::Context` (and `check`
depends on `sem_ir`, not the other way around, so `sem_ir` can't use
check). So instead, make a `Check::LookupClassFieldByStructField` that
wraps the `SemIR` version, and does the `LoadImportRef`

Assisted-By: Claude

---------

Co-authored-by: Christopher Di Bella <cjdb.ns@gmail.com>
This commit is contained in:
David BlaikieandChristopher Di Bella authored and GitHub committed 2026-11-02 20:37:01 +00:00
1 parent be0f11be95
commit d99b767dde
7 files changed
+297 -8

No files matched your search

+9 -5
View File
@@ -13,6 +13,7 @@
#include "clang/Sema/Sema.h"
#include "llvm/Support/Casting.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/class.h"
#include "toolchain/check/cpp/access.h"
#include "toolchain/check/cpp/context.h"
#include "toolchain/check/cpp/import.h"
@@ -684,8 +685,8 @@ auto ExportAllFieldsToCpp(Context& context,
for (const auto& struct_field : class_info.GetStructTypeFields(
context.sem_ir(), class_type.specific_id)) {
auto class_field = LookupClassFieldByStructField(context.sem_ir(),
class_scope, struct_field);
auto class_field =
LookupClassFieldByStructField(context, class_scope, struct_field);
if (!class_field) {
continue;
}
@@ -744,9 +745,12 @@ auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id,
GetClassTypeInstId(context, class_type.class_id, specific_id);
ExportAllFieldsToCpp(context, class_type_inst_id);
// Get the exported `clang::FieldDecl`.
if (const auto* clang_decl =
context.clang_decls().Lookup(field_inst_id, specific_id)) {
// Get the exported `clang::FieldDecl`. Exported fields are keyed by the
// `FieldDecl` instruction, but `field_inst_id` is an import ref if the field
// was imported, so look up the instruction it resolves to.
if (const auto* clang_decl = context.clang_decls().Lookup(
context.constant_values().GetConstantInstId(field_inst_id),
specific_id)) {
if (!clang_decl->decl()->isInvalidDecl()) {
return cast<clang::FieldDecl>(clang_decl->decl());
}