mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-28 19:14:54 +01:00
Remove Class::fields_exported (#7586)
In preparation for exporting specific classes, remove `fields_exported`. A class's fields will be exported for each specific, so a single boolean won't work. Instead, check in `ExportAllFieldsToCpp` if `clang_decls` already has an export for this field, and skip if so. Once specifics are supported, this lookup will use both the field's `InstId` and `SpecificId`. The above changes aren't quite sufficient, because if a field fails to be exported, it will keep being attempted on each call to `ExportAllFieldsToCpp` resulting in multiple errors. Fix this by storing an invalid `FieldDecl` in `ClangDeclStore` if an error occurs. This lets `ExportAllFieldsToCpp` know not to reattempt export, and `ExportFieldToCpp` returns `nullptr` for invalid fields same as before.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/EnterExpressionEvaluationContext.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
@@ -251,11 +252,25 @@ static auto CreateCppFieldDecl(Context& context,
|
||||
return cpp_field_decl;
|
||||
}
|
||||
|
||||
auto ExportAllFieldsToCpp(Context& context, SemIR::Class& class_info) -> void {
|
||||
if (class_info.fields_exported) {
|
||||
return;
|
||||
}
|
||||
// Create an invalid `clang::FieldDecl`. This is only used as an error marker
|
||||
// to indicate that a Carbon field has already been unsuccessfully exported.
|
||||
static auto CreateInvalidFieldDecl(Context& context,
|
||||
clang::DeclContext* decl_context)
|
||||
-> clang::FieldDecl* {
|
||||
clang::SourceLocation clang_loc;
|
||||
auto* identifier_info =
|
||||
context.clang_sema().getPreprocessor().getIdentifierInfo("invalid_field");
|
||||
auto cpp_type = context.ast_context().IntTy;
|
||||
auto* field_decl = clang::FieldDecl::Create(
|
||||
context.ast_context(), decl_context, /*StartLoc=*/clang_loc,
|
||||
/*IdLoc=*/clang_loc, identifier_info, cpp_type, /*TInfo=*/nullptr,
|
||||
/*BW=*/nullptr,
|
||||
/*Mutable=*/true, clang::ICIS_NoInit);
|
||||
field_decl->setInvalidDecl();
|
||||
return field_decl;
|
||||
}
|
||||
|
||||
auto ExportAllFieldsToCpp(Context& context, SemIR::Class& class_info) -> void {
|
||||
const auto& class_scope = context.name_scopes().Get(class_info.scope_id);
|
||||
|
||||
for (const auto& struct_field :
|
||||
@@ -266,6 +281,13 @@ auto ExportAllFieldsToCpp(Context& context, SemIR::Class& class_info) -> void {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Return early if the field is already exported. Since fields are always
|
||||
// exported as a group, this indicates all fields have been exported so
|
||||
// there's no need to continue to the rest.
|
||||
if (context.clang_decls().Lookup(class_field->inst_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Map the parent scope into the C++ AST.
|
||||
auto* decl_context = ExportNameScopeToCpp(
|
||||
context, SemIR::LocId(class_field->inst_id), class_info.scope_id);
|
||||
@@ -276,16 +298,19 @@ auto ExportAllFieldsToCpp(Context& context, SemIR::Class& class_info) -> void {
|
||||
auto* cpp_field_decl = CreateCppFieldDecl(
|
||||
context, class_scope, cast<clang::CXXRecordDecl>(decl_context),
|
||||
class_field->inst_id, class_field->inst);
|
||||
|
||||
// If the field cannot be exported, create an invalid `FieldDecl` to store
|
||||
// in `clang_decls`. This marks the field as unsuccessfully exported, so
|
||||
// that we know not to attempt export again (which could create duplicate
|
||||
// error diagnostics).
|
||||
if (!cpp_field_decl) {
|
||||
continue;
|
||||
cpp_field_decl = CreateInvalidFieldDecl(context, decl_context);
|
||||
}
|
||||
|
||||
// Create and store the `ClangDeclId`.
|
||||
auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(cpp_field_decl);
|
||||
context.clang_decls().Add({.key = key, .inst_id = class_field->inst_id});
|
||||
}
|
||||
|
||||
class_info.fields_exported = true;
|
||||
}
|
||||
|
||||
auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id,
|
||||
@@ -303,7 +328,9 @@ auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id,
|
||||
|
||||
// Get the exported `clang::FieldDecl`.
|
||||
if (const auto* clang_decl = context.clang_decls().Lookup(field_inst_id)) {
|
||||
return cast<clang::FieldDecl>(clang_decl->decl());
|
||||
if (!clang_decl->decl()->isInvalidDecl()) {
|
||||
return cast<clang::FieldDecl>(clang_decl->decl());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user