fix struct inside function referencing local const
closes #672 the crash and compile errors are fixed but structs inside functions still get named after the functions they're in. this will be fixed later.
This commit is contained in:
parent
ad438cfd40
commit
bb39e503c0
@ -37,13 +37,7 @@ struct ScopeDecls;
|
|||||||
struct ZigWindowsSDK;
|
struct ZigWindowsSDK;
|
||||||
struct Tld;
|
struct Tld;
|
||||||
struct TldExport;
|
struct TldExport;
|
||||||
|
struct IrAnalyze;
|
||||||
struct IrGotoItem {
|
|
||||||
AstNode *source_node;
|
|
||||||
IrBasicBlock *bb;
|
|
||||||
size_t instruction_index;
|
|
||||||
Scope *scope;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IrExecutable {
|
struct IrExecutable {
|
||||||
ZigList<IrBasicBlock *> basic_block_list;
|
ZigList<IrBasicBlock *> basic_block_list;
|
||||||
@ -53,13 +47,13 @@ struct IrExecutable {
|
|||||||
size_t *backward_branch_count;
|
size_t *backward_branch_count;
|
||||||
size_t backward_branch_quota;
|
size_t backward_branch_quota;
|
||||||
bool invalid;
|
bool invalid;
|
||||||
ZigList<IrGotoItem> goto_list;
|
|
||||||
bool is_inline;
|
bool is_inline;
|
||||||
FnTableEntry *fn_entry;
|
FnTableEntry *fn_entry;
|
||||||
Buf *c_import_buf;
|
Buf *c_import_buf;
|
||||||
AstNode *source_node;
|
AstNode *source_node;
|
||||||
IrExecutable *parent_exec;
|
IrExecutable *parent_exec;
|
||||||
IrExecutable *source_exec;
|
IrExecutable *source_exec;
|
||||||
|
IrAnalyze *analysis;
|
||||||
Scope *begin_scope;
|
Scope *begin_scope;
|
||||||
ZigList<Tld *> tld_list;
|
ZigList<Tld *> tld_list;
|
||||||
};
|
};
|
||||||
@ -1626,6 +1620,7 @@ struct VariableTableEntry {
|
|||||||
LLVMValueRef param_value_ref;
|
LLVMValueRef param_value_ref;
|
||||||
bool shadowable;
|
bool shadowable;
|
||||||
size_t mem_slot_index;
|
size_t mem_slot_index;
|
||||||
|
IrExecutable *owner_exec;
|
||||||
size_t ref_count;
|
size_t ref_count;
|
||||||
VarLinkage linkage;
|
VarLinkage linkage;
|
||||||
IrInstruction *decl_instruction;
|
IrInstruction *decl_instruction;
|
||||||
|
82
src/ir.cpp
82
src/ir.cpp
@ -2530,8 +2530,10 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
|
|||||||
bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
|
bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
|
||||||
{
|
{
|
||||||
VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_comptime);
|
VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_comptime);
|
||||||
if (is_comptime != nullptr || gen_is_const)
|
if (is_comptime != nullptr || gen_is_const) {
|
||||||
var->mem_slot_index = exec_next_mem_slot(irb->exec);
|
var->mem_slot_index = exec_next_mem_slot(irb->exec);
|
||||||
|
var->owner_exec = irb->exec;
|
||||||
|
}
|
||||||
assert(var->child_scope);
|
assert(var->child_scope);
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
@ -7037,48 +7039,48 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
|
|||||||
if (expected_type != nullptr && type_is_invalid(expected_type))
|
if (expected_type != nullptr && type_is_invalid(expected_type))
|
||||||
return codegen->invalid_instruction;
|
return codegen->invalid_instruction;
|
||||||
|
|
||||||
IrExecutable ir_executable = {0};
|
IrExecutable *ir_executable = allocate<IrExecutable>(1);
|
||||||
ir_executable.source_node = source_node;
|
ir_executable->source_node = source_node;
|
||||||
ir_executable.parent_exec = parent_exec;
|
ir_executable->parent_exec = parent_exec;
|
||||||
ir_executable.name = exec_name;
|
ir_executable->name = exec_name;
|
||||||
ir_executable.is_inline = true;
|
ir_executable->is_inline = true;
|
||||||
ir_executable.fn_entry = fn_entry;
|
ir_executable->fn_entry = fn_entry;
|
||||||
ir_executable.c_import_buf = c_import_buf;
|
ir_executable->c_import_buf = c_import_buf;
|
||||||
ir_executable.begin_scope = scope;
|
ir_executable->begin_scope = scope;
|
||||||
ir_gen(codegen, node, scope, &ir_executable);
|
ir_gen(codegen, node, scope, ir_executable);
|
||||||
|
|
||||||
if (ir_executable.invalid)
|
if (ir_executable->invalid)
|
||||||
return codegen->invalid_instruction;
|
return codegen->invalid_instruction;
|
||||||
|
|
||||||
if (codegen->verbose_ir) {
|
if (codegen->verbose_ir) {
|
||||||
fprintf(stderr, "\nSource: ");
|
fprintf(stderr, "\nSource: ");
|
||||||
ast_render(codegen, stderr, node, 4);
|
ast_render(codegen, stderr, node, 4);
|
||||||
fprintf(stderr, "\n{ // (IR)\n");
|
fprintf(stderr, "\n{ // (IR)\n");
|
||||||
ir_print(codegen, stderr, &ir_executable, 4);
|
ir_print(codegen, stderr, ir_executable, 4);
|
||||||
fprintf(stderr, "}\n");
|
fprintf(stderr, "}\n");
|
||||||
}
|
}
|
||||||
IrExecutable analyzed_executable = {0};
|
IrExecutable *analyzed_executable = allocate<IrExecutable>(1);
|
||||||
analyzed_executable.source_node = source_node;
|
analyzed_executable->source_node = source_node;
|
||||||
analyzed_executable.parent_exec = parent_exec;
|
analyzed_executable->parent_exec = parent_exec;
|
||||||
analyzed_executable.source_exec = &ir_executable;
|
analyzed_executable->source_exec = ir_executable;
|
||||||
analyzed_executable.name = exec_name;
|
analyzed_executable->name = exec_name;
|
||||||
analyzed_executable.is_inline = true;
|
analyzed_executable->is_inline = true;
|
||||||
analyzed_executable.fn_entry = fn_entry;
|
analyzed_executable->fn_entry = fn_entry;
|
||||||
analyzed_executable.c_import_buf = c_import_buf;
|
analyzed_executable->c_import_buf = c_import_buf;
|
||||||
analyzed_executable.backward_branch_count = backward_branch_count;
|
analyzed_executable->backward_branch_count = backward_branch_count;
|
||||||
analyzed_executable.backward_branch_quota = backward_branch_quota;
|
analyzed_executable->backward_branch_quota = backward_branch_quota;
|
||||||
analyzed_executable.begin_scope = scope;
|
analyzed_executable->begin_scope = scope;
|
||||||
TypeTableEntry *result_type = ir_analyze(codegen, &ir_executable, &analyzed_executable, expected_type, node);
|
TypeTableEntry *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
|
||||||
if (type_is_invalid(result_type))
|
if (type_is_invalid(result_type))
|
||||||
return codegen->invalid_instruction;
|
return codegen->invalid_instruction;
|
||||||
|
|
||||||
if (codegen->verbose_ir) {
|
if (codegen->verbose_ir) {
|
||||||
fprintf(stderr, "{ // (analyzed)\n");
|
fprintf(stderr, "{ // (analyzed)\n");
|
||||||
ir_print(codegen, stderr, &analyzed_executable, 4);
|
ir_print(codegen, stderr, analyzed_executable, 4);
|
||||||
fprintf(stderr, "}\n");
|
fprintf(stderr, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ir_exec_const_result(codegen, &analyzed_executable);
|
return ir_exec_const_result(codegen, analyzed_executable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
|
static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
|
||||||
@ -9334,6 +9336,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
|||||||
IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
|
IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
|
||||||
bool is_comptime_var = ir_get_var_is_comptime(var);
|
bool is_comptime_var = ir_get_var_is_comptime(var);
|
||||||
|
|
||||||
|
bool var_class_requires_const = false;
|
||||||
|
|
||||||
TypeTableEntry *result_type = casted_init_value->value.type;
|
TypeTableEntry *result_type = casted_init_value->value.type;
|
||||||
if (type_is_invalid(result_type)) {
|
if (type_is_invalid(result_type)) {
|
||||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||||
@ -9345,6 +9349,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
|||||||
result_type = ira->codegen->builtin_types.entry_invalid;
|
result_type = ira->codegen->builtin_types.entry_invalid;
|
||||||
break;
|
break;
|
||||||
case VarClassRequiredConst:
|
case VarClassRequiredConst:
|
||||||
|
var_class_requires_const = true;
|
||||||
if (!var->src_is_const && !is_comptime_var) {
|
if (!var->src_is_const && !is_comptime_var) {
|
||||||
ir_add_error_node(ira, source_node,
|
ir_add_error_node(ira, source_node,
|
||||||
buf_sprintf("variable of type '%s' must be const or comptime",
|
buf_sprintf("variable of type '%s' must be const or comptime",
|
||||||
@ -9366,8 +9371,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
|||||||
return ira->codegen->builtin_types.entry_void;
|
return ira->codegen->builtin_types.entry_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_comptime = ir_get_var_is_comptime(var);
|
|
||||||
|
|
||||||
if (decl_var_instruction->align_value == nullptr) {
|
if (decl_var_instruction->align_value == nullptr) {
|
||||||
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
|
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
|
||||||
} else {
|
} else {
|
||||||
@ -9382,12 +9385,12 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
|||||||
ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
||||||
*mem_slot = casted_init_value->value;
|
*mem_slot = casted_init_value->value;
|
||||||
|
|
||||||
if (is_comptime) {
|
if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
|
||||||
ir_build_const_from(ira, &decl_var_instruction->base);
|
ir_build_const_from(ira, &decl_var_instruction->base);
|
||||||
return ira->codegen->builtin_types.entry_void;
|
return ira->codegen->builtin_types.entry_void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (is_comptime) {
|
} else if (is_comptime_var) {
|
||||||
ir_add_error(ira, &decl_var_instruction->base,
|
ir_add_error(ira, &decl_var_instruction->base,
|
||||||
buf_sprintf("cannot store runtime value in compile time variable"));
|
buf_sprintf("cannot store runtime value in compile time variable"));
|
||||||
var->value->type = ira->codegen->builtin_types.entry_invalid;
|
var->value->type = ira->codegen->builtin_types.entry_invalid;
|
||||||
@ -9690,6 +9693,10 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in
|
|||||||
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||||
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
|
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
|
||||||
{
|
{
|
||||||
|
if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {
|
||||||
|
assert(ira->codegen->errors.length != 0);
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
}
|
||||||
assert(var->value->type);
|
assert(var->value->type);
|
||||||
if (type_is_invalid(var->value->type))
|
if (type_is_invalid(var->value->type))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
@ -9700,9 +9707,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
|||||||
if (var->value->special == ConstValSpecialStatic) {
|
if (var->value->special == ConstValSpecialStatic) {
|
||||||
mem_slot = var->value;
|
mem_slot = var->value;
|
||||||
} else {
|
} else {
|
||||||
// TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.
|
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
|
||||||
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))
|
// find the relevant exec_context
|
||||||
mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
assert(var->owner_exec != nullptr);
|
||||||
|
assert(var->owner_exec->analysis != nullptr);
|
||||||
|
IrExecContext *exec_context = &var->owner_exec->analysis->exec_context;
|
||||||
|
assert(var->mem_slot_index < exec_context->mem_slot_count);
|
||||||
|
mem_slot = &exec_context->mem_slot_list[var->mem_slot_index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
|
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
|
||||||
@ -15328,8 +15340,8 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
|
|||||||
assert(!old_exec->invalid);
|
assert(!old_exec->invalid);
|
||||||
assert(expected_type == nullptr || !type_is_invalid(expected_type));
|
assert(expected_type == nullptr || !type_is_invalid(expected_type));
|
||||||
|
|
||||||
IrAnalyze ir_analyze_data = {};
|
IrAnalyze *ira = allocate<IrAnalyze>(1);
|
||||||
IrAnalyze *ira = &ir_analyze_data;
|
old_exec->analysis = ira;
|
||||||
ira->codegen = codegen;
|
ira->codegen = codegen;
|
||||||
ira->explicit_return_type = expected_type;
|
ira->explicit_return_type = expected_type;
|
||||||
|
|
||||||
|
@ -577,3 +577,22 @@ test "implicit comptime while" {
|
|||||||
@compileError("bad");
|
@compileError("bad");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "struct inside function" {
|
||||||
|
testStructInFn();
|
||||||
|
comptime testStructInFn();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testStructInFn() {
|
||||||
|
const BlockKind = u32;
|
||||||
|
|
||||||
|
const Block = struct {
|
||||||
|
kind: BlockKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
var block = Block { .kind = 1234 };
|
||||||
|
|
||||||
|
block.kind += 1;
|
||||||
|
|
||||||
|
assert(block.kind == 1235);
|
||||||
|
}
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
const tests = @import("tests.zig");
|
const tests = @import("tests.zig");
|
||||||
|
|
||||||
pub fn addCases(cases: &tests.CompileErrorContext) {
|
pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||||
|
cases.add("bad identifier in function with struct defined inside function which references local const",
|
||||||
|
\\export fn entry() {
|
||||||
|
\\ const BlockKind = u32;
|
||||||
|
\\
|
||||||
|
\\ const Block = struct {
|
||||||
|
\\ kind: BlockKind,
|
||||||
|
\\ };
|
||||||
|
\\
|
||||||
|
\\ bogus;
|
||||||
|
\\}
|
||||||
|
, ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'");
|
||||||
|
|
||||||
cases.add("labeled break not found",
|
cases.add("labeled break not found",
|
||||||
\\export fn entry() {
|
\\export fn entry() {
|
||||||
\\ blah: while (true) {
|
\\ blah: while (true) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user