Add ExternDecl and ExternType for extern classes. (#3893)

This expands `extern` handling for most cases.
This commit is contained in:
Jon Ross-Perkins
2024-04-22 15:04:16 +00:00
committed by GitHub
parent 459c41ab3c
commit 5694dd152e
18 changed files with 332 additions and 308 deletions
+8 -1
View File
@@ -9,7 +9,7 @@
namespace Carbon::Check {
auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
SemIR::Class& new_class, bool /*new_is_import*/,
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 {
@@ -51,6 +51,13 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
prev_class.object_repr_id = new_class.object_repr_id;
}
if ((prev_import_ir_inst_id.is_valid() && !new_is_import) ||
(prev_is_extern && !new_is_extern)) {
prev_class.decl_id = new_class.decl_id;
ReplacePrevInstForMerge(
context, prev_class.enclosing_scope_id, prev_class.name_id,
new_is_import ? new_loc.inst_id : new_class.decl_id);
}
return true;
}
+2
View File
@@ -977,6 +977,7 @@ class TypeCompleter {
case SemIR::ClassInit::Kind:
case SemIR::Converted::Kind:
case SemIR::Deref::Kind:
case SemIR::ExternDecl::Kind:
case SemIR::FacetTypeAccess::Kind:
case SemIR::FloatLiteral::Kind:
case SemIR::FieldDecl::Kind:
@@ -1056,6 +1057,7 @@ class TypeCompleter {
case SemIR::AssociatedEntityType::Kind:
case SemIR::BindSymbolicName::Kind:
case SemIR::ExternType::Kind:
case SemIR::FloatType::Kind:
case SemIR::IntType::Kind:
case SemIR::PointerType::Kind:
+10
View File
@@ -897,6 +897,15 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::BoundMethod::object_id,
&SemIR::BoundMethod::function_id);
case CARBON_KIND(SemIR::ExternDecl extern_decl): {
// Return an extern form of the declaration's constant value.
auto non_extern_type_id = context.GetTypeIdForTypeConstant(
context.constant_values().Get(extern_decl.decl_id));
return MakeConstantResult(
context,
SemIR::ExternType{SemIR::TypeId::TypeType, non_extern_type_id},
Phase::Template);
}
case SemIR::InterfaceWitness::Kind:
return RebuildIfFieldsAreConstant(context, inst,
&SemIR::InterfaceWitness::elements_id);
@@ -975,6 +984,7 @@ auto TryEvalInst(Context& context, SemIR::InstId inst_id, SemIR::Inst inst)
}
case SemIR::ClassType::Kind:
case SemIR::ExternType::Kind:
case SemIR::InterfaceType::Kind:
CARBON_FATAL() << inst.kind()
<< " is only created during corresponding Decl handling.";
+62 -22
View File
@@ -2,11 +2,14 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/base/kind_switch.h"
#include "toolchain/check/class.h"
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
#include "toolchain/check/decl_name_stack.h"
#include "toolchain/check/merge.h"
#include "toolchain/check/modifiers.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/typed_insts.h"
namespace Carbon::Check {
@@ -35,6 +38,51 @@ auto HandleClassIntroducer(Context& context, Parse::ClassIntroducerId node_id)
return true;
}
// Adds the name to name lookup. If there's a conflict, tries to merge. May
// update class_decl and class_info when merging.
static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
const DeclNameStack::NameContext& name_context,
SemIR::InstId class_decl_id,
SemIR::ClassDecl& class_decl,
SemIR::Class& class_info, bool is_definition,
bool is_extern) -> void {
auto prev_id =
context.decl_name_stack().LookupOrAddName(name_context, class_decl_id);
if (prev_id.is_valid()) {
auto prev_inst_for_merge =
ResolvePrevInstForMerge(context, node_id, prev_id);
auto prev_class_id = SemIR::ClassId::Invalid;
CARBON_KIND_SWITCH(prev_inst_for_merge.inst) {
case CARBON_KIND(SemIR::ClassDecl class_decl): {
prev_class_id = class_decl.class_id;
break;
}
case CARBON_KIND(SemIR::ClassType class_type): {
prev_class_id = class_type.class_id;
break;
}
default:
// This is a redeclaration of something other than a class.
context.DiagnoseDuplicateName(class_decl_id, prev_id);
break;
}
if (prev_class_id.is_valid()) {
if (MergeClassRedecl(context, node_id, class_info,
/*new_is_import=*/false, is_definition, is_extern,
prev_class_id, prev_inst_for_merge.is_extern,
prev_inst_for_merge.import_ir_inst_id)) {
// When merging, use the existing entity rather than adding a new one.
class_decl.class_id = prev_class_id;
}
} else {
// This is a redeclaration of something other than a class.
context.DiagnoseDuplicateName(class_decl_id, prev_id);
}
}
}
static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
bool is_definition)
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
@@ -88,30 +136,16 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
.decl_id = class_decl_id,
.inheritance_kind = inheritance_kind};
// Check whether this is a redeclaration.
auto prev_id =
context.decl_name_stack().LookupOrAddName(name_context, class_decl_id);
if (prev_id.is_valid()) {
auto prev_inst_for_merge =
ResolvePrevInstForMerge(context, node_id, prev_id);
if (auto prev_class_decl =
prev_inst_for_merge.inst.TryAs<SemIR::ClassDecl>()) {
// TODO: Fix prev_is_extern.
if (MergeClassRedecl(context, node_id, class_info,
/*new_is_import=*/false, is_definition, is_extern,
prev_class_decl->class_id,
/*prev_is_extern=*/false,
prev_inst_for_merge.import_ir_inst_id)) {
// When merging, use the existing entity rather than adding a new one.
class_decl.class_id = prev_class_decl->class_id;
}
} else {
// This is a redeclaration of something other than a class.
context.DiagnoseDuplicateName(class_decl_id, prev_id);
}
auto extern_decl_id = SemIR::InstId::Invalid;
if (is_extern) {
extern_decl_id = context.AddPlaceholderInst(
{node_id, SemIR::ExternDecl{SemIR::TypeId::TypeType, class_decl_id}});
}
MergeOrAddName(context, node_id, name_context,
extern_decl_id.is_valid() ? extern_decl_id : class_decl_id,
class_decl, class_info, is_definition, is_extern);
// Create a new class if this isn't a valid redeclaration.
bool is_new_class = !class_decl.class_id.is_valid();
if (is_new_class) {
@@ -130,6 +164,12 @@ static auto BuildClassDecl(Context& context, Parse::AnyClassDeclId node_id,
class_info.self_type_id = context.GetTypeIdForTypeInst(class_decl_id);
}
if (is_extern) {
context.ReplaceInstBeforeConstantUse(
extern_decl_id,
SemIR::ExternDecl{SemIR::TypeId::TypeType, class_decl_id});
}
return {class_decl.class_id, class_decl_id};
}
+2
View File
@@ -118,6 +118,8 @@ static auto BuildFunctionDecl(Context& context,
auto function_decl = SemIR::FunctionDecl{
context.GetBuiltinType(SemIR::BuiltinKind::FunctionType),
SemIR::FunctionId::Invalid, decl_block_id};
// TODO: Should Function replace is_extern with ExternDecl, similar to
// ClassDecl?
auto function_info = SemIR::Function{
.name_id = name_context.name_id_for_new_inst(),
.enclosing_scope_id = name_context.enclosing_scope_id_for_new_inst(),
+5
View File
@@ -36,6 +36,11 @@ static auto GetImportName(const SemIR::File& import_sem_ir,
return {class_info.name_id, class_info.enclosing_scope_id};
}
case CARBON_KIND(SemIR::ExternDecl extern_decl): {
return GetImportName(import_sem_ir,
import_sem_ir.insts().Get(extern_decl.decl_id));
}
case CARBON_KIND(SemIR::FunctionDecl function_decl): {
const auto& function =
import_sem_ir.functions().Get(function_decl.function_id);
+16
View File
@@ -409,6 +409,9 @@ class ImportRefResolver {
case CARBON_KIND(SemIR::ConstType inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::ExternDecl inst): {
return TryResolveTypedInst(inst);
}
case CARBON_KIND(SemIR::FieldDecl inst): {
return TryResolveTypedInst(inst, inst_id);
}
@@ -669,6 +672,19 @@ class ImportRefResolver {
SemIR::ConstType{SemIR::TypeId::TypeType, inner_type_id})};
}
auto TryResolveTypedInst(SemIR::ExternDecl inst) -> ResolveResult {
auto initial_work = work_stack_.size();
CARBON_CHECK(inst.type_id == SemIR::TypeId::TypeType);
auto decl_const_id = GetLocalConstantId(inst.decl_id);
if (HasNewWork(initial_work)) {
return ResolveResult::Retry();
}
auto extern_id = context_.AddInstInNoBlock(SemIR::LocIdAndInst::Untyped(
AddImportIRInst(inst.decl_id),
SemIR::ExternDecl{SemIR::TypeId::TypeType, decl_const_id.inst_id()}));
return {context_.constant_values().Get(extern_id)};
}
auto TryResolveTypedInst(SemIR::FieldDecl inst, SemIR::InstId import_inst_id)
-> ResolveResult {
auto initial_work = work_stack_.size();
+50 -28
View File
@@ -127,30 +127,44 @@ auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind,
auto ResolvePrevInstForMerge(Context& context, Parse::NodeId node_id,
SemIR::InstId prev_inst_id) -> InstForMerge {
auto prev_inst = context.insts().Get(prev_inst_id);
auto import_ref = prev_inst.TryAs<SemIR::AnyImportRef>();
// If not imported, use the instruction directly.
if (!import_ref) {
return {.inst = prev_inst,
.import_ir_inst_id = SemIR::ImportIRInstId::Invalid};
InstForMerge result = {.inst = context.insts().Get(prev_inst_id),
.import_ir_inst_id = SemIR::ImportIRInstId::Invalid,
.is_extern = false};
CARBON_KIND_SWITCH(result.inst) {
case CARBON_KIND(SemIR::ExternDecl extern_decl): {
result.is_extern = true;
result.inst = context.insts().Get(extern_decl.decl_id);
break;
}
case CARBON_KIND(SemIR::ImportRefUsed import_ref): {
CARBON_DIAGNOSTIC(
RedeclOfUsedImport, Error,
"Redeclaration of imported entity that was previously used.");
CARBON_DIAGNOSTIC(UsedImportLoc, Note, "Import used here.");
context.emitter()
.Build(node_id, RedeclOfUsedImport)
.Note(import_ref.used_id, UsedImportLoc)
.Emit();
[[fallthrough]];
}
case SemIR::ImportRefLoaded::Kind: {
// Follow the import ref.
auto import_ref = result.inst.As<SemIR::AnyImportRef>();
result.import_ir_inst_id = import_ref.import_ir_inst_id;
result.inst = context.insts().Get(
context.constant_values().Get(prev_inst_id).inst_id());
if (auto extern_type = result.inst.TryAs<SemIR::ExternType>()) {
result.inst =
context.types().GetAsInst(extern_type->non_extern_type_id);
}
break;
}
default:
break;
}
// If the import ref was previously used, print a diagnostic.
if (auto import_ref_used = prev_inst.TryAs<SemIR::ImportRefUsed>()) {
CARBON_DIAGNOSTIC(
RedeclOfUsedImport, Error,
"Redeclaration of imported entity that was previously used.");
CARBON_DIAGNOSTIC(UsedImportLoc, Note, "Import used here.");
context.emitter()
.Build(node_id, RedeclOfUsedImport)
.Note(import_ref_used->used_id, UsedImportLoc)
.Emit();
}
// Follow the import ref.
return {.inst = context.insts().Get(
context.constant_values().Get(prev_inst_id).inst_id()),
.import_ir_inst_id = import_ref->import_ir_inst_id};
return result;
}
// Returns the instruction to consider when merging the given inst_id. Returns
@@ -185,9 +199,18 @@ static auto ResolveMergeableInst(Context& context, SemIR::InstId inst_id)
if (!const_id.is_constant()) {
return std::nullopt;
}
return {
{.inst = context.insts().Get(const_id.inst_id()),
.import_ir_inst_id = inst.As<SemIR::AnyImportRef>().import_ir_inst_id}};
InstForMerge result = {
.inst = context.insts().Get(const_id.inst_id()),
.import_ir_inst_id = inst.As<SemIR::AnyImportRef>().import_ir_inst_id,
.is_extern = false};
if (auto extern_type = result.inst.TryAs<SemIR::ExternType>()) {
result.is_extern = true;
result.inst = context.types().GetAsInst(extern_type->non_extern_type_id);
}
return result;
}
auto ReplacePrevInstForMerge(Context& context, SemIR::NameScopeId scope_id,
@@ -240,11 +263,10 @@ auto MergeImportRef(Context& context, SemIR::InstId new_inst_id,
}
auto new_class = context.classes().Get(new_type.class_id);
// TODO: Fix new_is_extern and prev_is_extern.
MergeClassRedecl(context, new_inst_id, new_class,
/*new_is_import=*/true, new_class.is_defined(),
/*new_is_extern=*/false, prev_type->class_id,
/*prev_is_extern=*/false, prev_inst->import_ir_inst_id);
new_inst->is_extern, prev_type->class_id,
prev_inst->is_extern, prev_inst->import_ir_inst_id);
return;
}
default:
+2
View File
@@ -40,6 +40,8 @@ struct InstForMerge {
// The imported instruction, or invalid if not an import. This should
// typically only be used for the ImportIRId, but we only load it if needed.
SemIR::ImportIRInstId import_ir_inst_id;
// True if an `extern` declaration.
bool is_extern;
};
// Resolves prev_inst_id for merging (or name conflicts). This handles imports
+23 -41
View File
@@ -44,41 +44,19 @@ library "extern" api;
import Other library "extern";
// CHECK:STDERR: fail_extern.carbon:[[@LINE+10]]:8: ERROR: Variable has incomplete type `C`.
// CHECK:STDERR: fail_extern.carbon:[[@LINE+4]]:1: ERROR: Cannot implicitly convert from `{}` to `extern C`.
// CHECK:STDERR: var c: Other.C = {};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_extern.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import Other library "extern";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: other_extern.carbon:4:1: Class was forward declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
var c: Other.C = {};
// --- fail_todo_merge_define_extern.carbon
// --- merge_define_extern.carbon
library "merge_define_extern" api;
import Other library "define";
// CHECK:STDERR: fail_todo_merge_define_extern.carbon:[[@LINE+12]]:1: In import.
// CHECK:STDERR: import Other library "extern";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: other_extern.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_merge_define_extern.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import Other library "define";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: other_define.carbon:4:1: Previously declared here.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
import Other library "extern";
// CHECK:STDERR: fail_todo_merge_define_extern.carbon:[[@LINE+4]]:8: In name lookup for `C`.
// CHECK:STDERR: var c: Other.C = {};
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR:
var c: Other.C = {};
// --- fail_conflict.carbon
@@ -130,15 +108,17 @@ var c: Other.C = {};
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .C = %.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
@@ -204,7 +184,8 @@ var c: Other.C = {};
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -216,31 +197,32 @@ var c: Other.C = {};
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Other: <namespace> = namespace [template] {}
// CHECK:STDOUT: %Other.ref: <namespace> = name_ref Other, %Other [template = %Other]
// CHECK:STDOUT: %import_ref: type = import_ref ir3, inst+2, loc_14 [template = constants.%C]
// CHECK:STDOUT: %import_ref: type = import_ref ir3, inst+3, loc_14 [template = constants.%.1]
// CHECK:STDOUT: %C.decl: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref [template = constants.%C]
// CHECK:STDOUT: %c.var: ref <error> = var c
// CHECK:STDOUT: %c: ref <error> = bind_name c, %c.var
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref [template = constants.%.1]
// CHECK:STDOUT: %c.var: ref extern C = var c
// CHECK:STDOUT: %c: ref extern C = bind_name c, %c.var
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc16: {} = struct_literal ()
// CHECK:STDOUT: %.loc10: {} = struct_literal ()
// CHECK:STDOUT: assign file.%c.var, <error>
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_merge_define_extern.carbon
// CHECK:STDOUT: --- merge_define_extern.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: %.2: type = tuple_type () [template]
// CHECK:STDOUT: %.3: type = ptr_type {} [template]
// CHECK:STDOUT: %.4: C = struct_value () [template]
// CHECK:STDOUT: %.2: type = extern_type C [template]
// CHECK:STDOUT: %.3: type = tuple_type () [template]
// CHECK:STDOUT: %.4: type = ptr_type {} [template]
// CHECK:STDOUT: %.5: C = struct_value () [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -255,7 +237,7 @@ var c: Other.C = {};
// CHECK:STDOUT: %import_ref.1: type = import_ref ir3, inst+2, loc_19 [template = constants.%C.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %import_ref.2 = import_ref ir3, inst+3, unloaded
// CHECK:STDOUT: %import_ref.3: type = import_ref ir4, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.3: type = import_ref ir4, inst+3, loaded [template = constants.%.2]
// CHECK:STDOUT: %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
// CHECK:STDOUT: %C.ref: type = name_ref C, %import_ref.1 [template = constants.%C.1]
// CHECK:STDOUT: %c.var: ref C = var c
@@ -271,10 +253,10 @@ var c: Other.C = {};
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %.loc23_19.1: {} = struct_literal ()
// CHECK:STDOUT: %.loc23_19.2: init C = class_init (), file.%c.var [template = constants.%.4]
// CHECK:STDOUT: %.loc23_20: init C = converted %.loc23_19.1, %.loc23_19.2 [template = constants.%.4]
// CHECK:STDOUT: assign file.%c.var, %.loc23_20
// CHECK:STDOUT: %.loc7_19.1: {} = struct_literal ()
// CHECK:STDOUT: %.loc7_19.2: init C = class_init (), file.%c.var [template = constants.%.5]
// CHECK:STDOUT: %.loc7_20: init C = converted %.loc7_19.1, %.loc7_19.2 [template = constants.%.5]
// CHECK:STDOUT: assign file.%c.var, %.loc7_20
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
+98 -179
View File
@@ -41,12 +41,12 @@ class C {}
library "fail_decl_fn_in_extern" api;
extern class C;
// CHECK:STDERR: fail_decl_fn_in_extern.carbon:[[@LINE+7]]:4: ERROR: Cannot declare a member of incomplete class `C`.
// CHECK:STDERR: fail_decl_fn_in_extern.carbon:[[@LINE+7]]:6: ERROR: Name qualifiers are only allowed for entities that provide a scope.
// CHECK:STDERR: fn C.F();
// CHECK:STDERR: ^
// CHECK:STDERR: fail_decl_fn_in_extern.carbon:[[@LINE+4]]:4: Non-scope entity referenced here.
// CHECK:STDERR: fn C.F();
// CHECK:STDERR: ^
// CHECK:STDERR: fail_decl_fn_in_extern.carbon:[[@LINE-4]]:1: Class was forward declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
fn C.F();
@@ -100,11 +100,18 @@ class C {
extern class D;
}
// --- todo_fail_def_after_extern_decl.carbon
// --- fail_def_after_extern_decl.carbon
library "fail_def_after_extern_decl" api;
extern class C;
// CHECK:STDERR: fail_def_after_extern_decl.carbon:[[@LINE+7]]:1: ERROR: Redeclarations of `class C` in the same library must match use of `extern`.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_def_after_extern_decl.carbon:[[@LINE-4]]:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
class C {}
// --- fail_extern_decl_after_decl.carbon
@@ -121,64 +128,25 @@ class C;
// CHECK:STDERR:
extern class C;
// --- fail_todo_import_extern_decl_then_decl.carbon
// --- import_extern_decl_then_decl.carbon
library "import_extern_decl_then_decl" api;
import library "extern_decl";
// CHECK:STDERR: fail_todo_import_extern_decl_then_decl.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: import library "decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: decl.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_todo_import_extern_decl_then_decl.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
import library "decl";
// --- fail_todo_import_decl_then_extern_decl.carbon
// --- import_decl_then_extern_decl.carbon
library "import_decl_then_extern_decl" api;
import library "decl";
// CHECK:STDERR: fail_todo_import_decl_then_extern_decl.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_import_decl_then_extern_decl.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
import library "extern_decl";
// --- fail_todo_import_extern_decl_then_def.carbon
// --- import_extern_decl_then_def.carbon
library "import_extern_decl_then_def" api;
import library "extern_decl";
// CHECK:STDERR: fail_todo_import_extern_decl_then_def.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: import library "def";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: def.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_import_extern_decl_then_def.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
import library "def";
// --- fail_import_ownership_conflict.carbon
@@ -186,124 +154,58 @@ import library "def";
library "fail_import_ownership_conflict" api;
import library "extern_decl";
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: import library "decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: decl.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
import library "decl";
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE+12]]:1: In import.
// CHECK:STDERR: import library "def";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: def.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE-21]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: fail_import_ownership_conflict.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
// CHECK:STDERR: decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
import library "def";
// --- fail_todo_import_extern_decl_copy.carbon
// --- import_extern_decl_copy.carbon
library "import_extern_decl_copy" api;
import library "extern_decl";
// CHECK:STDERR: fail_todo_import_extern_decl_copy.carbon:[[@LINE+13]]:1: In import.
// CHECK:STDERR: import library "extern_decl_copy";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl_copy.carbon:4:1: ERROR: Only one library can declare `class C` without `extern`.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_import_extern_decl_copy.carbon:[[@LINE-7]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
import library "extern_decl_copy";
// --- fail_todo_extern_decl_after_import_extern_decl.carbon
// --- extern_decl_after_import_extern_decl.carbon
library "extern_decl_after_import_extern_decl" api;
import library "extern_decl";
// CHECK:STDERR: fail_todo_extern_decl_after_import_extern_decl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_extern_decl_after_import_extern_decl.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import library "extern_decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: extern_decl.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR:
extern class C;
// --- fail_todo_decl_after_import_extern_decl.carbon
// --- decl_after_import_extern_decl.carbon
library "decl_after_import_extern_decl" api;
import library "decl";
// CHECK:STDERR: fail_todo_decl_after_import_extern_decl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_decl_after_import_extern_decl.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import library "decl";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: decl.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: class C;
// CHECK:STDERR: ^~~~~~~~
// CHECK:STDERR:
extern class C;
// --- fail_todo_def_after_import_extern_decl.carbon
// --- def_after_import_extern_decl.carbon
library "def_after_import_extern_decl" api;
import library "def";
// CHECK:STDERR: fail_todo_def_after_import_extern_decl.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_def_after_import_extern_decl.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import library "def";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: def.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
extern class C;
// --- fail_todo_extern_decl_after_import_def.carbon
// --- extern_decl_after_import_def.carbon
library "extern_decl_after_import_def" api;
import library "def";
// CHECK:STDERR: fail_todo_extern_decl_after_import_def.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: extern class C;
// CHECK:STDERR: ^~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_extern_decl_after_import_def.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import library "def";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: def.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: class C {}
// CHECK:STDERR: ^~~~~~~~~
extern class C;
// CHECK:STDOUT: --- decl.carbon
@@ -327,15 +229,17 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .C = %.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
@@ -344,15 +248,17 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .C = %.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
@@ -382,15 +288,17 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl
// CHECK:STDOUT: .C = %.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl [template = constants.%.1]
// CHECK:STDOUT: %.loc12: <function> = fn_decl @.1 [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -423,16 +331,19 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc4
// CHECK:STDOUT: .C = %.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl.loc4: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl.loc4 [template = constants.%.1]
// CHECK:STDOUT: %C.decl.loc12: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc12: type = extern_decl %C.decl.loc12 [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
@@ -441,15 +352,17 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc4
// CHECK:STDOUT: .C = %C.decl.loc12
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl.loc4: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl.loc4 [template = constants.%.1]
// CHECK:STDOUT: %C.decl.loc12: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -482,21 +395,23 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @D;
// CHECK:STDOUT:
// CHECK:STDOUT: --- todo_fail_def_after_extern_decl.carbon
// CHECK:STDOUT: --- fail_def_after_extern_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc4
// CHECK:STDOUT: .C = %C.decl.loc12
// CHECK:STDOUT: }
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl.loc4: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc5: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc4: type = extern_decl %C.decl.loc4 [template = constants.%.1]
// CHECK:STDOUT: %C.decl.loc12: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
@@ -508,6 +423,7 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -518,23 +434,25 @@ extern class C;
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %C.decl.loc4: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc12: type = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %.loc12: type = extern_decl %C.decl.loc12 [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_import_extern_decl_then_decl.carbon
// CHECK:STDOUT: --- import_extern_decl_then_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .C = %import_ref.2
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+3, loaded [template = constants.%.1]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+2, loaded [template = constants.%C.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
@@ -545,10 +463,11 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.2;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_import_decl_then_extern_decl.carbon
// CHECK:STDOUT: --- import_decl_then_extern_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -558,7 +477,7 @@ extern class C;
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+2, loaded [template = constants.%C.1]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+3, loaded [template = constants.%.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
@@ -568,20 +487,21 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.2;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_import_extern_decl_then_def.carbon
// CHECK:STDOUT: --- import_extern_decl_then_def.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: %.2: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .C = %import_ref.2
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+3, loaded [template = constants.%.2]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+2, loaded [template = constants.%C.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %import_ref.3 = import_ref ir3, inst+3, unloaded
@@ -604,16 +524,17 @@ extern class C;
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: %C.3: type = class_type @C.3 [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .C = %import_ref.2
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+3, loaded [template = constants.%.1]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+2, loaded [template = constants.%C.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
@@ -623,23 +544,25 @@ extern class C;
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.1;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.2 {
// CHECK:STDOUT: class @C.1 {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = file.%import_ref.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.2;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.3 {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = file.%import_ref.4
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_import_extern_decl_copy.carbon
// CHECK:STDOUT: --- import_extern_decl_copy.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C.1: type = class_type @C.1 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: %C.2: type = class_type @C.2 [template]
// CHECK:STDOUT: %.2: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -647,8 +570,8 @@ extern class C;
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C.2]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+2, loaded [template = constants.%C.1]
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+3, loaded [template = constants.%.2]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir3, inst+3, loaded [template = constants.%.1]
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C.1 [template = constants.%C.1] {}
// CHECK:STDOUT: %C.decl.2: invalid = class_decl @C.2 [template = constants.%C.2] {}
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
@@ -658,71 +581,70 @@ extern class C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @C.2;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_extern_decl_after_import_extern_decl.carbon
// CHECK:STDOUT: --- extern_decl_after_import_extern_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = class_type @.1 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref: type = import_ref ir2, inst+2, loaded [template = constants.%C]
// CHECK:STDOUT: %import_ref: type = import_ref ir2, inst+3, loaded [template = constants.%.1]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] {
// CHECK:STDOUT: %C.decl: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc6: type = class_decl @C [template = constants.%C] {
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc6: type = extern_decl %C.decl.loc6 [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_decl_after_import_extern_decl.carbon
// CHECK:STDOUT: --- decl_after_import_extern_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = class_type @.1 [template]
// CHECK:STDOUT: %.1: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref: type = import_ref ir2, inst+2, loaded [template = constants.%C]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] {
// CHECK:STDOUT: %C.decl: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc6: type = class_decl @C [template = constants.%C] {
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc6: type = extern_decl %C.decl.loc6 [template = constants.%.1]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C;
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_def_after_import_extern_decl.carbon
// CHECK:STDOUT: --- def_after_import_extern_decl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.2: type = class_type @.1 [template]
// CHECK:STDOUT: %.2: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+3, unloaded
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.2] {
// CHECK:STDOUT: %C.decl: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc6: type = class_decl @C [template = constants.%C] {
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc6: type = extern_decl %C.decl.loc6 [template = constants.%.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
@@ -730,27 +652,26 @@ extern class C;
// CHECK:STDOUT: .Self = file.%import_ref.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_todo_extern_decl_after_import_def.carbon
// CHECK:STDOUT: --- extern_decl_after_import_def.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %C: type = class_type @C [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.2: type = class_type @.1 [template]
// CHECK:STDOUT: %.2: type = extern_type C [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .C = %import_ref.1
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .C = %C.decl.loc6
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%C]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %import_ref.2 = import_ref ir2, inst+3, unloaded
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.2] {
// CHECK:STDOUT: %C.decl: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: %C.decl.loc6: type = class_decl @C [template = constants.%C] {
// CHECK:STDOUT: %C.decl.1: invalid = class_decl @C [template = constants.%C] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %.loc6: type = extern_decl %C.decl.loc6 [template = constants.%.2]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @C {
@@ -758,5 +679,3 @@ extern class C;
// CHECK:STDOUT: .Self = file.%import_ref.2
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1;
// CHECK:STDOUT:
+6 -12
View File
@@ -19,13 +19,13 @@ library "b" api;
import library "a";
// CHECK:STDERR: fail_b.carbon:[[@LINE+10]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: fail_b.carbon:[[@LINE+10]]:1: ERROR: Only one library can declare `class Empty` without `extern`.
// CHECK:STDERR: class Empty {
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR: fail_b.carbon:[[@LINE-5]]:1: In import.
// CHECK:STDERR: import library "a";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: a.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: a.carbon:4:1: Previously declared here.
// CHECK:STDERR: class Empty {
// CHECK:STDERR: ^~~~~~~~~~~~~
// CHECK:STDERR:
@@ -74,23 +74,22 @@ var a: Incomplete;
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Empty: type = class_type @Empty [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: %.2: type = class_type @.1 [template]
// CHECK:STDOUT: %Incomplete: type = class_type @Incomplete [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .Empty = %import_ref.1
// CHECK:STDOUT: .Incomplete = %import_ref.2
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .Empty = %Empty.decl.loc16
// CHECK:STDOUT: .a = %a
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref.1: type = import_ref ir2, inst+2, loaded [template = constants.%Empty]
// CHECK:STDOUT: %import_ref.2: type = import_ref ir2, inst+5, loc_15 [template = constants.%Incomplete]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %import_ref.3 = import_ref ir2, inst+3, unloaded
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.2] {
// CHECK:STDOUT: %Empty.decl: invalid = class_decl @Empty [template = constants.%Empty] {}
// CHECK:STDOUT: %Empty.decl.loc16: type = class_decl @Empty [template = constants.%Empty] {
// CHECK:STDOUT: %Empty.decl.1: invalid = class_decl @Empty [template = constants.%Empty] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: %Incomplete.decl: invalid = class_decl @Incomplete [template = constants.%Incomplete] {}
// CHECK:STDOUT: %Incomplete.ref: type = name_ref Incomplete, %import_ref.2 [template = constants.%Incomplete]
@@ -100,12 +99,7 @@ var a: Incomplete;
// CHECK:STDOUT:
// CHECK:STDOUT: class @Empty {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = file.%import_ref.3
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1 {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%.2
// CHECK:STDOUT: .Self = constants.%Empty
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @Incomplete;
@@ -10,22 +10,10 @@ library "a" api;
class ForwardDecl;
// --- fail_b.carbon
// --- a.impl.carbon
library "b" api;
library "a" impl;
import library "a";
// TODO: This should probably have a valid form.
// CHECK:STDERR: fail_b.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope.
// CHECK:STDERR: class ForwardDecl {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_b.carbon:[[@LINE-6]]:1: In import.
// CHECK:STDERR: import library "a";
// CHECK:STDERR: ^~~~~~
// CHECK:STDERR: a.carbon:4:1: Name is previously declared here.
// CHECK:STDERR: class ForwardDecl;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~
class ForwardDecl {
}
@@ -46,30 +34,27 @@ class ForwardDecl {
// CHECK:STDOUT:
// CHECK:STDOUT: class @ForwardDecl;
// CHECK:STDOUT:
// CHECK:STDOUT: --- fail_b.carbon
// CHECK:STDOUT: --- a.impl.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %ForwardDecl: type = class_type @ForwardDecl [template]
// CHECK:STDOUT: %.1: type = class_type @.1 [template]
// CHECK:STDOUT: %.2: type = struct_type {} [template]
// CHECK:STDOUT: %.1: type = struct_type {} [template]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = namespace [template] {
// CHECK:STDOUT: .ForwardDecl = %import_ref
// CHECK:STDOUT: .Core = %Core
// CHECK:STDOUT: .ForwardDecl = %ForwardDecl.decl.loc4
// CHECK:STDOUT: }
// CHECK:STDOUT: %import_ref: type = import_ref ir2, inst+2, loaded [template = constants.%ForwardDecl]
// CHECK:STDOUT: %import_ref: type = import_ref ir1, inst+2, loaded [template = constants.%ForwardDecl]
// CHECK:STDOUT: %Core: <namespace> = namespace [template] {}
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] {
// CHECK:STDOUT: %ForwardDecl.decl: invalid = class_decl @ForwardDecl [template = constants.%ForwardDecl] {}
// CHECK:STDOUT: %ForwardDecl.decl.loc4: type = class_decl @ForwardDecl [template = constants.%ForwardDecl] {
// CHECK:STDOUT: %ForwardDecl.decl.1: invalid = class_decl @ForwardDecl [template = constants.%ForwardDecl] {}
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: class @ForwardDecl;
// CHECK:STDOUT:
// CHECK:STDOUT: class @.1 {
// CHECK:STDOUT: class @ForwardDecl {
// CHECK:STDOUT: !members:
// CHECK:STDOUT: .Self = constants.%.1
// CHECK:STDOUT: .Self = constants.%ForwardDecl
// CHECK:STDOUT: }
// CHECK:STDOUT:
+5
View File
@@ -12,6 +12,11 @@
namespace Carbon::Lower {
auto HandleExternDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
SemIR::ExternDecl /*inst*/) -> void {
// No action to perform.
}
auto HandleClassDecl(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
SemIR::ClassDecl /*inst*/) -> void {
// No action to perform.
+5
View File
@@ -27,6 +27,11 @@ auto HandleConstType(FunctionContext& context, SemIR::InstId inst_id,
context.SetLocal(inst_id, context.GetTypeAsValue());
}
auto HandleExternType(FunctionContext& context, SemIR::InstId inst_id,
SemIR::ExternType /*inst*/) -> void {
context.SetLocal(inst_id, context.GetTypeAsValue());
}
auto HandleFacetTypeAccess(FunctionContext& context, SemIR::InstId inst_id,
SemIR::FacetTypeAccess /*inst*/) -> void {
context.SetLocal(inst_id, context.GetTypeAsValue());
+10
View File
@@ -206,6 +206,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case BindSymbolicName::Kind:
case Builtin::Kind:
case ClassType::Kind:
case ExternType::Kind:
case FacetTypeAccess::Kind:
case FloatType::Kind:
case ImportRefLoaded::Kind:
@@ -246,6 +247,7 @@ static auto GetTypePrecedence(InstKind kind) -> int {
case ClassInit::Kind:
case Converted::Kind:
case Deref::Kind:
case ExternDecl::Kind:
case FieldDecl::Kind:
case FloatLiteral::Kind:
case FunctionDecl::Kind:
@@ -379,6 +381,11 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
}
break;
}
case CARBON_KIND(ExternType inst): {
out << "extern ";
push_inst_id(sem_ir.types().GetInstId(inst.non_extern_type_id));
break;
}
case CARBON_KIND(FacetTypeAccess inst): {
// Print `T as type` as simply `T`.
push_inst_id(inst.facet_id);
@@ -521,6 +528,7 @@ static auto StringifyTypeExprImpl(const SemIR::File& outer_sem_ir,
case ClassInit::Kind:
case Converted::Kind:
case Deref::Kind:
case ExternDecl::Kind:
case FieldDecl::Kind:
case FloatLiteral::Kind:
case FunctionDecl::Kind:
@@ -640,6 +648,8 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
case ClassDecl::Kind:
case ClassType::Kind:
case ConstType::Kind:
case ExternDecl::Kind:
case ExternType::Kind:
case FacetTypeAccess::Kind:
case FloatLiteral::Kind:
case FloatType::Kind:
+2
View File
@@ -48,6 +48,8 @@ CARBON_SEM_IR_INST_KIND(ClassType)
CARBON_SEM_IR_INST_KIND(ConstType)
CARBON_SEM_IR_INST_KIND(Converted)
CARBON_SEM_IR_INST_KIND(Deref)
CARBON_SEM_IR_INST_KIND(ExternDecl)
CARBON_SEM_IR_INST_KIND(ExternType)
CARBON_SEM_IR_INST_KIND(FacetTypeAccess)
CARBON_SEM_IR_INST_KIND(FloatLiteral)
CARBON_SEM_IR_INST_KIND(FloatType)
+16
View File
@@ -434,6 +434,22 @@ struct Deref {
InstId pointer_id;
};
struct ExternDecl {
static constexpr auto Kind =
InstKind::ExternDecl.Define<Parse::NodeId>("extern_decl");
TypeId type_id;
InstId decl_id;
};
struct ExternType {
static constexpr auto Kind =
InstKind::ExternType.Define<Parse::NodeId>("extern_type");
TypeId type_id;
TypeId non_extern_type_id;
};
// Represents accessing the `type` field in a facet value, which is notionally a
// pair of a type and a witness.
struct FacetTypeAccess {