mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:10:13 +01:00
Replace ResolvePrevInstForMerge with decl logic. (#3936)
This addresses the const reliance of ResolvePrevInstForMerge by checking the imported instruction, testing with `alias` name conflicts. Given the need to examine structure, the helper function feels like it now gets in the way, so I'm just removing it. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
d5c0c9cfe3
commit
292a9d3cb4
@@ -12,7 +12,7 @@ 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 {
|
||||
SemIR::ImportIRId prev_import_ir_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;
|
||||
@@ -30,7 +30,7 @@ auto MergeClassRedecl(Context& context, SemIRLoc new_loc,
|
||||
{.loc = prev_loc,
|
||||
.is_definition = prev_class.is_defined(),
|
||||
.is_extern = prev_is_extern},
|
||||
prev_import_ir_inst_id);
|
||||
prev_import_ir_id);
|
||||
|
||||
// The introducer kind must match the previous declaration.
|
||||
// TODO: The rule here is not yet decided. See #3384.
|
||||
@@ -56,7 +56,7 @@ 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) ||
|
||||
if ((prev_import_ir_id.is_valid() && !new_is_import) ||
|
||||
(prev_is_extern && !new_is_extern)) {
|
||||
prev_class.decl_id = new_class.decl_id;
|
||||
ReplacePrevInstForMerge(
|
||||
|
||||
@@ -21,7 +21,7 @@ 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;
|
||||
SemIR::ImportIRId prev_import_ir_id) -> bool;
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
|
||||
SemIR::Function& new_function, bool new_is_import,
|
||||
bool new_is_definition,
|
||||
SemIR::FunctionId prev_function_id,
|
||||
SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool {
|
||||
SemIR::ImportIRId prev_import_ir_id) -> bool {
|
||||
auto& prev_function = context.functions().Get(prev_function_id);
|
||||
|
||||
if (!CheckRedecl(context, new_function, prev_function, {})) {
|
||||
@@ -111,7 +111,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
|
||||
: prev_function.decl_id,
|
||||
.is_definition = prev_function.definition_id.is_valid(),
|
||||
.is_extern = prev_function.is_extern},
|
||||
prev_import_ir_inst_id);
|
||||
prev_import_ir_id);
|
||||
|
||||
if (new_is_definition) {
|
||||
// Track the signature from the definition, so that IDs in the body
|
||||
@@ -125,7 +125,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
|
||||
// The new function might have return slot information if it was imported.
|
||||
prev_function.return_slot =
|
||||
MergeReturnSlot(prev_function.return_slot, new_function.return_slot);
|
||||
if ((prev_import_ir_inst_id.is_valid() && !new_is_import) ||
|
||||
if ((prev_import_ir_id.is_valid() && !new_is_import) ||
|
||||
(prev_function.is_extern && !new_function.is_extern)) {
|
||||
prev_function.is_extern = new_function.is_extern;
|
||||
prev_function.decl_id = new_function.decl_id;
|
||||
|
||||
@@ -46,7 +46,7 @@ auto MergeFunctionRedecl(Context& context, SemIRLoc new_loc,
|
||||
SemIR::Function& new_function, bool new_is_import,
|
||||
bool new_is_definition,
|
||||
SemIR::FunctionId prev_function_id,
|
||||
SemIR::ImportIRInstId prev_import_ir_inst_id) -> bool;
|
||||
SemIR::ImportIRId prev_import_ir_id) -> bool;
|
||||
|
||||
// Checks that the return type of the specified function is complete, issuing an
|
||||
// error if not. This computes the return slot usage for the function if
|
||||
|
||||
@@ -48,38 +48,53 @@ static auto MergeOrAddName(Context& context, Parse::AnyClassDeclId node_id,
|
||||
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, prev_id);
|
||||
if (!prev_id.is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
auto prev_class_id = SemIR::ClassId::Invalid;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::Invalid;
|
||||
CARBON_KIND_SWITCH(context.insts().Get(prev_id)) {
|
||||
case CARBON_KIND(SemIR::ClassDecl class_decl): {
|
||||
prev_class_id = class_decl.class_id;
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImportRefLoaded import_ref): {
|
||||
auto import_ir_inst =
|
||||
context.import_ir_insts().Get(import_ref.import_ir_inst_id);
|
||||
|
||||
if (prev_class_id.is_valid()) {
|
||||
// TODO: Fix prev_is_extern logic.
|
||||
if (MergeClassRedecl(context, node_id, class_info,
|
||||
/*new_is_import=*/false, is_definition, is_extern,
|
||||
prev_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_id;
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::ClassDecl>(import_ir_inst.inst_id)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// This is a redeclaration of something other than a class.
|
||||
context.DiagnoseDuplicateName(class_decl_id, prev_id);
|
||||
|
||||
// Use the type to get the ID.
|
||||
if (auto class_type = context.insts().TryGetAs<SemIR::ClassType>(
|
||||
context.constant_values().Get(prev_id).inst_id())) {
|
||||
prev_class_id = class_type->class_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev_class_id.is_valid()) {
|
||||
// This is a redeclaration of something other than a class.
|
||||
context.DiagnoseDuplicateName(class_decl_id, prev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Fix prev_is_extern logic.
|
||||
if (MergeClassRedecl(context, node_id, class_info,
|
||||
/*new_is_import=*/false, is_definition, is_extern,
|
||||
prev_class_id, /*prev_is_extern=*/false,
|
||||
prev_import_ir_id)) {
|
||||
// When merging, use the existing entity rather than adding a new one.
|
||||
class_decl.class_id = prev_class_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,28 +61,6 @@ static auto DiagnoseModifiers(Context& context, bool is_definition,
|
||||
return context.decl_state_stack().innermost().modifier_set;
|
||||
}
|
||||
|
||||
// Returns the function ID for the instruction, or invalid.
|
||||
static auto GetRedeclFunctionId(Context& context, SemIR::Inst prev_inst)
|
||||
-> SemIR::FunctionId {
|
||||
CARBON_KIND_SWITCH(prev_inst) {
|
||||
case CARBON_KIND(SemIR::StructValue struct_value): {
|
||||
if (auto fn_type = context.types().TryGetAs<SemIR::FunctionType>(
|
||||
struct_value.type_id)) {
|
||||
return fn_type->function_id;
|
||||
}
|
||||
return SemIR::FunctionId::Invalid;
|
||||
}
|
||||
case CARBON_KIND(SemIR::FunctionDecl fn_decl): {
|
||||
return fn_decl.function_id;
|
||||
}
|
||||
default:
|
||||
// This is a redeclaration of something other than a function. This
|
||||
// includes the case where an associated function redeclares another
|
||||
// associated function.
|
||||
return SemIR::FunctionId::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether this is a redeclaration, merging if needed.
|
||||
static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
|
||||
SemIR::InstId prev_id,
|
||||
@@ -93,9 +71,39 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
|
||||
return;
|
||||
}
|
||||
|
||||
auto prev_inst_for_merge = ResolvePrevInstForMerge(context, prev_id);
|
||||
auto prev_function_id =
|
||||
GetRedeclFunctionId(context, prev_inst_for_merge.inst);
|
||||
auto prev_function_id = SemIR::FunctionId::Invalid;
|
||||
auto prev_import_ir_id = SemIR::ImportIRId::Invalid;
|
||||
CARBON_KIND_SWITCH(context.insts().Get(prev_id)) {
|
||||
case CARBON_KIND(SemIR::FunctionDecl function_decl): {
|
||||
prev_function_id = function_decl.function_id;
|
||||
break;
|
||||
}
|
||||
case CARBON_KIND(SemIR::ImportRefLoaded import_ref): {
|
||||
auto import_ir_inst =
|
||||
context.import_ir_insts().Get(import_ref.import_ir_inst_id);
|
||||
|
||||
// Verify the decl so that things like aliases are name conflicts.
|
||||
const auto* import_ir =
|
||||
context.import_irs().Get(import_ir_inst.ir_id).sem_ir;
|
||||
if (!import_ir->insts().Is<SemIR::FunctionDecl>(import_ir_inst.inst_id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Use the type to get the ID.
|
||||
if (auto struct_value = context.insts().TryGetAs<SemIR::StructValue>(
|
||||
context.constant_values().Get(prev_id).inst_id())) {
|
||||
if (auto function_type = context.types().TryGetAs<SemIR::FunctionType>(
|
||||
struct_value->type_id)) {
|
||||
prev_function_id = function_type->function_id;
|
||||
prev_import_ir_id = import_ir_inst.ir_id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev_function_id.is_valid()) {
|
||||
context.DiagnoseDuplicateName(function_info.decl_id, prev_id);
|
||||
return;
|
||||
@@ -103,8 +111,7 @@ static auto TryMergeRedecl(Context& context, Parse::AnyFunctionDeclId node_id,
|
||||
|
||||
if (MergeFunctionRedecl(context, node_id, function_info,
|
||||
/*new_is_import=*/false, is_definition,
|
||||
prev_function_id,
|
||||
prev_inst_for_merge.import_ir_inst_id)) {
|
||||
prev_function_id, prev_import_ir_id)) {
|
||||
// When merging, use the existing function rather than adding a new one.
|
||||
function_decl.function_id = prev_function_id;
|
||||
}
|
||||
|
||||
@@ -72,10 +72,9 @@ static auto DiagnoseNonExtern(Context& context, Lex::TokenKind decl_kind,
|
||||
// These all still merge.
|
||||
auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind,
|
||||
SemIR::NameId name_id, RedeclInfo new_decl,
|
||||
RedeclInfo prev_decl,
|
||||
SemIR::ImportIRInstId prev_import_ir_inst_id)
|
||||
RedeclInfo prev_decl, SemIR::ImportIRId import_ir_id)
|
||||
-> void {
|
||||
if (!prev_import_ir_inst_id.is_valid()) {
|
||||
if (!import_ir_id.is_valid()) {
|
||||
// Check for disallowed redeclarations in the same file.
|
||||
if (!new_decl.is_definition) {
|
||||
DiagnoseRedundant(context, decl_kind, name_id, new_decl.loc,
|
||||
@@ -96,8 +95,6 @@ auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind,
|
||||
return;
|
||||
}
|
||||
|
||||
auto import_ir_id =
|
||||
context.import_ir_insts().Get(prev_import_ir_inst_id).ir_id;
|
||||
if (import_ir_id == SemIR::ImportIRId::ApiForImpl) {
|
||||
// Check for disallowed redeclarations in the same library. Note that a
|
||||
// forward declaration in the impl is allowed.
|
||||
@@ -125,19 +122,6 @@ auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind,
|
||||
}
|
||||
}
|
||||
|
||||
auto ResolvePrevInstForMerge(Context& context, SemIR::InstId prev_inst_id)
|
||||
-> InstForMerge {
|
||||
InstForMerge result = {.inst = context.insts().Get(prev_inst_id),
|
||||
.import_ir_inst_id = SemIR::ImportIRInstId::Invalid};
|
||||
if (auto import_ref = result.inst.TryAs<SemIR::ImportRefLoaded>()) {
|
||||
// Follow the import ref.
|
||||
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());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto ReplacePrevInstForMerge(Context& context, SemIR::NameScopeId scope_id,
|
||||
SemIR::NameId name_id, SemIR::InstId new_inst_id)
|
||||
-> void {
|
||||
|
||||
+1
-16
@@ -32,22 +32,7 @@ struct RedeclInfo {
|
||||
auto CheckIsAllowedRedecl(Context& context, Lex::TokenKind decl_kind,
|
||||
SemIR::NameId name_id, RedeclInfo new_decl,
|
||||
RedeclInfo prev_decl,
|
||||
SemIR::ImportIRInstId prev_import_ir_inst_id) -> void;
|
||||
|
||||
struct InstForMerge {
|
||||
// The resolved instruction.
|
||||
SemIR::Inst inst;
|
||||
// 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;
|
||||
};
|
||||
|
||||
// Resolves prev_inst_id for merging (or name conflicts). This handles imports
|
||||
// to return the instruction relevant for a merge. If an import is found and was
|
||||
// previously used, it notes it, although an invalid redeclaration may diagnose
|
||||
// for other reasons too.
|
||||
auto ResolvePrevInstForMerge(Context& context, SemIR::InstId prev_inst_id)
|
||||
-> InstForMerge;
|
||||
SemIR::ImportIRId prev_import_ir_id) -> void;
|
||||
|
||||
// When the prior name lookup result is an import and we are successfully
|
||||
// merging, replace the name lookup result with the reference in the current
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
// 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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
|
||||
// --- basic.carbon
|
||||
|
||||
library "basic" api;
|
||||
|
||||
class C;
|
||||
|
||||
// --- basic.impl.carbon
|
||||
|
||||
library "basic" impl;
|
||||
|
||||
class C {}
|
||||
|
||||
// --- redecl_after_def.carbon
|
||||
|
||||
library "redecl_after_def" api;
|
||||
|
||||
class C {}
|
||||
|
||||
// --- fail_redecl_after_def.impl.carbon
|
||||
|
||||
library "redecl_after_def" impl;
|
||||
|
||||
// CHECK:STDERR: fail_redecl_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redeclaration of `class C` is redundant.
|
||||
// CHECK:STDERR: class C;
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: fail_redecl_after_def.impl.carbon:[[@LINE-5]]:1: In import.
|
||||
// CHECK:STDERR: library "redecl_after_def" impl;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: redecl_after_def.carbon:4:1: Previously declared here.
|
||||
// CHECK:STDERR: class C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
class C;
|
||||
|
||||
// --- redef_after_def.carbon
|
||||
|
||||
library "redef_after_def" api;
|
||||
|
||||
class C {}
|
||||
|
||||
// --- fail_redef_after_def.impl.carbon
|
||||
|
||||
library "redef_after_def" impl;
|
||||
|
||||
// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redefinition of `class C`.
|
||||
// CHECK:STDERR: class C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE-5]]:1: In import.
|
||||
// CHECK:STDERR: library "redef_after_def" impl;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: redef_after_def.carbon:4:1: Previously defined here.
|
||||
// CHECK:STDERR: class C {}
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
class C {}
|
||||
|
||||
// --- def_alias.carbon
|
||||
|
||||
library "def_alias" api;
|
||||
|
||||
class C;
|
||||
alias B = C;
|
||||
|
||||
// --- fail_def_alias.impl.carbon
|
||||
|
||||
library "def_alias" impl;
|
||||
|
||||
// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope.
|
||||
// CHECK:STDERR: class B {}
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE-5]]:1: In import.
|
||||
// CHECK:STDERR: library "def_alias" impl;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: def_alias.carbon:5:7: Name is previously declared here.
|
||||
// CHECK:STDERR: alias B = C;
|
||||
// CHECK:STDERR: ^
|
||||
class B {}
|
||||
|
||||
// CHECK:STDOUT: --- basic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- basic.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref: type = import_ref ir0, inst+1, loaded [template = constants.%C]
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- redecl_after_def.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_redecl_after_def.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref.1: type = import_ref ir0, inst+1, loaded [template = constants.%C]
|
||||
// CHECK:STDOUT: %import_ref.2 = import_ref ir0, inst+2, unloaded
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = file.%import_ref.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- redef_after_def.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_redef_after_def.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = struct_type {} [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref.1: type = import_ref ir0, inst+1, loaded [template = constants.%C]
|
||||
// CHECK:STDOUT: %import_ref.2 = import_ref ir0, inst+2, unloaded
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%C
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- def_alias.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: .B = %B
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [template = constants.%C] {}
|
||||
// CHECK:STDOUT: %C.ref: type = name_ref C, %C.decl [template = constants.%C]
|
||||
// CHECK:STDOUT: %B: type = bind_alias B, %C.decl [template = constants.%C]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_def_alias.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [template]
|
||||
// CHECK:STDOUT: %.1: type = class_type @.1 [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: .B = %import_ref.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref.1 = import_ref ir0, inst+1, unloaded
|
||||
// CHECK:STDOUT: %import_ref.2: type = import_ref ir0, inst+4, loaded [template = constants.%C]
|
||||
// CHECK:STDOUT: %.decl: type = class_decl @.1 [template = constants.%.1] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @C;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @.1 {
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%.1
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+71
-1
@@ -86,7 +86,7 @@ fn A() {}
|
||||
|
||||
library "redef_after_def" impl;
|
||||
|
||||
// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+9]]:1: ERROR: Redefinition of `fn A`.
|
||||
// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE+10]]:1: ERROR: Redefinition of `fn A`.
|
||||
// CHECK:STDERR: fn A() {}
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: fail_redef_after_def.impl.carbon:[[@LINE-5]]:1: In import.
|
||||
@@ -95,8 +95,31 @@ library "redef_after_def" impl;
|
||||
// CHECK:STDERR: redef_after_def.carbon:4:1: Previously defined here.
|
||||
// CHECK:STDERR: fn A() {}
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn A() {}
|
||||
|
||||
// --- def_alias.carbon
|
||||
|
||||
library "def_alias" api;
|
||||
|
||||
fn A();
|
||||
alias B = A;
|
||||
|
||||
// --- fail_def_alias.impl.carbon
|
||||
|
||||
library "def_alias" impl;
|
||||
|
||||
// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE+9]]:1: ERROR: Duplicate name being declared in the same scope.
|
||||
// CHECK:STDERR: fn B() {}
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: fail_def_alias.impl.carbon:[[@LINE-5]]:1: In import.
|
||||
// CHECK:STDERR: library "def_alias" impl;
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: def_alias.carbon:5:7: Name is previously declared here.
|
||||
// CHECK:STDERR: alias B = A;
|
||||
// CHECK:STDERR: ^
|
||||
fn B() {}
|
||||
|
||||
// CHECK:STDOUT: --- basic.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
@@ -290,3 +313,50 @@ fn A() {}
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- def_alias.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A: type = fn_type @A [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct: A = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .A = %A.decl
|
||||
// CHECK:STDOUT: .B = %B
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %A.decl: A = fn_decl @A [template = constants.%struct] {}
|
||||
// CHECK:STDOUT: %A.ref: A = name_ref A, %A.decl [template = constants.%struct]
|
||||
// CHECK:STDOUT: %B: A = bind_alias B, %A.decl [template = constants.%struct]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_def_alias.impl.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %A: type = fn_type @A [template]
|
||||
// CHECK:STDOUT: %.1: type = tuple_type () [template]
|
||||
// CHECK:STDOUT: %struct.1: A = struct_value () [template]
|
||||
// CHECK:STDOUT: %.2: type = fn_type @.1 [template]
|
||||
// CHECK:STDOUT: %struct.2: <invalid> = struct_value () [template]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: package: <namespace> = namespace [template] {
|
||||
// CHECK:STDOUT: .A = %import_ref.1
|
||||
// CHECK:STDOUT: .B = %import_ref.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %import_ref.1 = import_ref ir0, inst+1, unloaded
|
||||
// CHECK:STDOUT: %import_ref.2: A = import_ref ir0, inst+6, loaded [template = constants.%struct.1]
|
||||
// CHECK:STDOUT: %.decl: <invalid> = fn_decl @.1 [template = constants.%struct.2] {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @.1() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
Reference in New Issue
Block a user