mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-01 22:02:45 +01:00
This doesn't actually track whether a declaration is `extern`. It does, however: - Factor out and expand merge support for classes, sharing handling with functions. - This makes the ClassRedefinition diagnostic redundant, as the redeclaration checking overlaps. - Add partial `extern` handling to class handling; just some verifications of correct use. - Factor out `extern` on member handling for sharing with `fn`. - Fixes a bug in import_ref where a class's definition_id wasn't assigned when defining. This changes how a redefinition is handled (replaced, rather than merged). I don't know whether that's ideal, but I think it results in easy-to-understand consequences, and it's more consistent with how `fn` works. There's enough work here that this felt like a decent cut point, particularly as the amount of work to actually add `extern` tracking will be significant.
58 lines
2.3 KiB
C++
58 lines
2.3 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/check/class.h"
|
|
|
|
#include "toolchain/check/merge.h"
|
|
|
|
namespace Carbon::Check {
|
|
|
|
auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
|
|
SemIR::Class& new_class, bool /*new_is_import*/,
|
|
bool new_is_definition, bool new_is_extern,
|
|
SemIR::ClassId prev_class_id, bool prev_is_extern,
|
|
SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool {
|
|
auto& prev_class = context.classes().Get(prev_class_id);
|
|
SemIRLoc prev_loc =
|
|
prev_class.is_defined() ? prev_class.definition_id : prev_class.decl_id;
|
|
|
|
// TODO: Check that the generic parameter list agrees with the prior
|
|
// declaration.
|
|
|
|
CheckIsAllowedRedecl(context, Lex::TokenKind::Class, prev_class.name_id,
|
|
{.loc = new_loc,
|
|
.is_definition = new_is_definition,
|
|
.is_extern = new_is_extern},
|
|
{.loc = prev_loc,
|
|
.is_definition = prev_class.is_defined(),
|
|
.is_extern = prev_is_extern},
|
|
prev_import_ir_inst_id);
|
|
|
|
// The introducer kind must match the previous declaration.
|
|
// TODO: The rule here is not yet decided. See #3384.
|
|
if (prev_class.inheritance_kind != new_class.inheritance_kind) {
|
|
CARBON_DIAGNOSTIC(ClassRedeclarationDifferentIntroducer, Error,
|
|
"Class redeclared with different inheritance kind.");
|
|
CARBON_DIAGNOSTIC(ClassRedeclarationDifferentIntroducerPrevious, Note,
|
|
"Previously declared here.");
|
|
context.emitter()
|
|
.Build(new_loc, ClassRedeclarationDifferentIntroducer)
|
|
.Note(prev_loc, ClassRedeclarationDifferentIntroducerPrevious)
|
|
.Emit();
|
|
}
|
|
|
|
if (new_is_definition) {
|
|
prev_class.definition_id = new_class.definition_id;
|
|
prev_class.scope_id = new_class.scope_id;
|
|
prev_class.body_block_id = new_class.body_block_id;
|
|
prev_class.adapt_id = new_class.adapt_id;
|
|
prev_class.base_id = new_class.base_id;
|
|
prev_class.object_repr_id = new_class.object_repr_id;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace Carbon::Check
|