fix inability to write to global in some cases

before, when we initialized a variable by copying the
initialization value, it made the internal const value
references point to a duplicate value, resulting in
a phony duplicate global value being updated instead of
the real on. now the behavior is as expected.

thanks to hoppetosse for pointing out this bug on IRC.
This commit is contained in:
Andrew Kelley 2017-02-27 00:05:08 -05:00
parent 25761570f1
commit 1195994880
7 changed files with 89 additions and 89 deletions

View File

@ -1430,7 +1430,7 @@ enum VarLinkage {
struct VariableTableEntry {
Buf name;
ConstExprValue value;
ConstExprValue *value;
LLVMValueRef value_ref;
bool src_is_const;
bool gen_is_const;

View File

@ -2085,7 +2085,7 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
assert(value);
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
variable_entry->value = *value;
variable_entry->value = value;
variable_entry->parent_scope = parent_scope;
variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
@ -2101,21 +2101,21 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
variable_entry->value.type = g->builtin_types.entry_invalid;
variable_entry->value->type = g->builtin_types.entry_invalid;
} else {
auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
if (primitive_table_entry) {
TypeTableEntry *type = primitive_table_entry->value;
add_node_error(g, source_node,
buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
variable_entry->value.type = g->builtin_types.entry_invalid;
variable_entry->value->type = g->builtin_types.entry_invalid;
} else {
Tld *tld = find_decl(g, parent_scope, name);
if (tld && tld->id != TldIdVar) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
variable_entry->value.type = g->builtin_types.entry_invalid;
variable_entry->value->type = g->builtin_types.entry_invalid;
}
}
}
@ -3181,7 +3181,7 @@ uint32_t fn_eval_hash(Scope* scope) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
result += hash_const_val(&var_scope->var->value);
result += hash_const_val(var_scope->var->value);
} else if (scope->id == ScopeIdFnDef) {
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
result += hash_ptr(fn_scope->fn_entry);
@ -3203,9 +3203,9 @@ bool fn_eval_eql(Scope *a, Scope *b) {
if (a->id == ScopeIdVarDecl) {
ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
if (a_var_scope->var->value.type != b_var_scope->var->value.type)
if (a_var_scope->var->value->type != b_var_scope->var->value->type)
return false;
if (!const_values_equal(&a_var_scope->var->value, &b_var_scope->var->value))
if (!const_values_equal(a_var_scope->var->value, b_var_scope->var->value))
return false;
} else if (a->id == ScopeIdFnDef) {
ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;

View File

@ -964,26 +964,26 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) {
const char *extern_str = extern_string(var->linkage == VarLinkageExternal);
fprintf(ar->f, "%s%s%s %s", visib_mod_str, extern_str, const_or_var, buf_ptr(name));
if (var->value.type->id == TypeTableEntryIdNumLitFloat ||
var->value.type->id == TypeTableEntryIdNumLitInt ||
var->value.type->id == TypeTableEntryIdMetaType)
if (var->value->type->id == TypeTableEntryIdNumLitFloat ||
var->value->type->id == TypeTableEntryIdNumLitInt ||
var->value->type->id == TypeTableEntryIdMetaType)
{
// skip type
} else {
fprintf(ar->f, ": %s", buf_ptr(&var->value.type->name));
fprintf(ar->f, ": %s", buf_ptr(&var->value->type->name));
}
if (var->value.special == ConstValSpecialRuntime) {
if (var->value->special == ConstValSpecialRuntime) {
fprintf(ar->f, ";\n");
return;
}
fprintf(ar->f, " = ");
if (var->value.special == ConstValSpecialStatic &&
var->value.type->id == TypeTableEntryIdMetaType)
if (var->value->special == ConstValSpecialStatic &&
var->value->type->id == TypeTableEntryIdMetaType)
{
TypeTableEntry *type_entry = var->value.data.x_type;
TypeTableEntry *type_entry = var->value->data.x_type;
if (type_entry->id == TypeTableEntryIdStruct) {
const char *layout_str = layout_string(type_entry->data.structure.layout);
fprintf(ar->f, "%sstruct {\n", layout_str);
@ -1022,7 +1022,7 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) {
} else {
Buf buf = BUF_INIT;
buf_resize(&buf, 0);
render_const_value(&buf, &var->value);
render_const_value(&buf, var->value);
fprintf(ar->f, "%s", buf_ptr(&buf));
}

View File

@ -1316,7 +1316,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
{
VariableTableEntry *var = decl_var_instruction->var;
if (!type_has_bits(var->value.type))
if (!type_has_bits(var->value->type))
return nullptr;
if (var->ref_count == 0 && g->is_release_build)
@ -1331,16 +1331,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
have_init_expr = true;
if (have_init_expr) {
assert(var->value.type == init_value->value.type);
gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->value.type);
assert(var->value->type == init_value->value.type);
gen_assign_raw(g, var->value_ref, ir_llvm_value(g, init_value), var->value->type);
} else {
bool ignore_uninit = false;
// handle runtime stack allocation
bool want_safe = ir_want_debug_safety(g, &decl_var_instruction->base);
if (!ignore_uninit && want_safe) {
TypeTableEntry *usize = g->builtin_types.entry_usize;
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value.type->type_ref);
uint64_t align_bytes = get_type_alignment(g, var->value.type);
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
uint64_t align_bytes = get_type_alignment(g, var->value->type);
// memset uninitialized memory to 0xa
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
@ -1437,7 +1437,7 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
VariableTableEntry *var = instruction->var;
if (type_has_bits(var->value.type)) {
if (type_has_bits(var->value->type)) {
assert(var->value_ref);
return var->value_ref;
} else {
@ -3203,9 +3203,9 @@ static void do_code_gen(CodeGen *g) {
TldVar *tld_var = g->global_vars.at(i);
VariableTableEntry *var = tld_var->var;
if (var->value.type->id == TypeTableEntryIdNumLitFloat) {
if (var->value->type->id == TypeTableEntryIdNumLitFloat) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = g->builtin_types.entry_f64;
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
@ -3213,9 +3213,9 @@ static void do_code_gen(CodeGen *g) {
continue;
}
if (var->value.type->id == TypeTableEntryIdNumLitInt) {
if (var->value->type->id == TypeTableEntryIdNumLitInt) {
// Generate debug info for it but that's it.
ConstExprValue *const_val = &var->value;
ConstExprValue *const_val = var->value;
assert(const_val->special != ConstValSpecialRuntime);
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
@ -3225,22 +3225,22 @@ static void do_code_gen(CodeGen *g) {
continue;
}
if (!type_has_bits(var->value.type))
if (!type_has_bits(var->value->type))
continue;
assert(var->decl_node);
LLVMValueRef global_value;
if (var->linkage == VarLinkageExternal) {
global_value = LLVMAddGlobal(g->module, var->value.type->type_ref, buf_ptr(&var->name));
global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage);
} else {
render_const_val(g, &var->value);
render_const_val_global(g, &var->value, buf_ptr(&var->name));
global_value = var->value.llvm_global;
render_const_val(g, var->value);
render_const_val_global(g, var->value, buf_ptr(&var->name));
global_value = var->value->llvm_global;
if (var->linkage == VarLinkageExport) {
LLVMSetLinkage(global_value, LLVMExternalLinkage);
@ -3249,11 +3249,11 @@ static void do_code_gen(CodeGen *g) {
LLVMSetSection(global_value, buf_ptr(tld_var->section_name));
}
LLVMSetAlignment(global_value, tld_var->alignment ?
tld_var->alignment : get_type_alignment(g, var->value.type));
tld_var->alignment : get_type_alignment(g, var->value->type));
// TODO debug info for function pointers
if (var->gen_is_const && var->value.type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, var->value.llvm_value, var->value.type);
if (var->gen_is_const && var->value->type->id != TypeTableEntryIdFn) {
gen_global_var(g, var, var->value->llvm_value, var->value->type);
}
}
@ -3432,30 +3432,30 @@ static void do_code_gen(CodeGen *g) {
for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
VariableTableEntry *var = fn_table_entry->variable_list.at(var_i);
if (!type_has_bits(var->value.type)) {
if (!type_has_bits(var->value->type)) {
continue;
}
if (ir_get_var_is_comptime(var))
continue;
if (type_requires_comptime(var->value.type))
if (type_requires_comptime(var->value->type))
continue;
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = build_alloca(g, var->value.type, buf_ptr(&var->name));
var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name));
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
var->value.type->di_type, !g->strip_debug_symbols, 0);
var->value->type->di_type, !g->strip_debug_symbols, 0);
} else {
assert(var->gen_arg_index != SIZE_MAX);
TypeTableEntry *gen_type;
if (handle_is_ptr(var->value.type)) {
if (handle_is_ptr(var->value->type)) {
gen_type = fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index].type;
var->value_ref = LLVMGetParam(fn, var->gen_arg_index);
} else {
gen_type = var->value.type;
var->value_ref = build_alloca(g, var->value.type, buf_ptr(&var->name));
gen_type = var->value->type;
var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name));
}
if (var->decl_node) {
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@ -3483,7 +3483,7 @@ static void do_code_gen(CodeGen *g) {
assert(variable);
assert(variable->value_ref);
if (!handle_is_ptr(variable->value.type)) {
if (!handle_is_ptr(variable->value->type)) {
clear_debug_source_node(g);
LLVMBuildStore(g->builder, LLVMGetParam(fn, variable->gen_arg_index), variable->value_ref);
}

View File

@ -3164,6 +3164,7 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->is_comptime = is_comptime;
variable_entry->src_arg_index = SIZE_MAX;
variable_entry->value = allocate<ConstExprValue>(1);
if (name) {
buf_init_from_buf(&variable_entry->name, name);
@ -3173,21 +3174,21 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
variable_entry->value.type = codegen->builtin_types.entry_invalid;
variable_entry->value->type = codegen->builtin_types.entry_invalid;
} else {
auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name);
if (primitive_table_entry) {
TypeTableEntry *type = primitive_table_entry->value;
add_node_error(codegen, node,
buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
variable_entry->value.type = codegen->builtin_types.entry_invalid;
variable_entry->value->type = codegen->builtin_types.entry_invalid;
} else {
Tld *tld = find_decl(codegen, parent_scope, name);
if (tld && tld->id != TldIdVar) {
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
variable_entry->value.type = codegen->builtin_types.entry_invalid;
variable_entry->value->type = codegen->builtin_types.entry_invalid;
}
}
}
@ -4516,7 +4517,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
// is inside var->child_scope
if (!is_extern && !variable_declaration->expr) {
var->value.type = irb->codegen->builtin_types.entry_invalid;
var->value->type = irb->codegen->builtin_types.entry_invalid;
add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized"));
return irb->codegen->invalid_instruction;
}
@ -5387,7 +5388,7 @@ static bool render_instance_name_recursive(Buf *name, Scope *outer_scope, Scope
ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope;
if (need_comma)
buf_append_char(name, ',');
render_const_value(name, &var_scope->var->value);
render_const_value(name, var_scope->var->value);
return true;
}
@ -7827,8 +7828,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
IrInstruction *init_value = decl_var_instruction->init_value->other;
if (type_is_invalid(init_value->value.type)) {
var->value.type = ira->codegen->builtin_types.entry_invalid;
return var->value.type;
var->value->type = ira->codegen->builtin_types.entry_invalid;
return var->value->type;
}
AstNodeVariableDeclaration *variable_declaration = &var->decl_node->data.variable_declaration;
@ -7844,8 +7845,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
TypeTableEntry *proposed_type = ir_resolve_type(ira, var_type);
explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
if (type_is_invalid(explicit_type)) {
var->value.type = ira->codegen->builtin_types.entry_invalid;
return var->value.type;
var->value->type = ira->codegen->builtin_types.entry_invalid;
return var->value->type;
}
}
@ -7906,8 +7907,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
break;
}
var->value.type = result_type;
assert(var->value.type);
var->value->type = result_type;
assert(var->value->type);
if (type_is_invalid(result_type)) {
decl_var_instruction->base.other = &decl_var_instruction->base;
@ -7930,7 +7931,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
} else if (is_comptime) {
ir_add_error(ira, &decl_var_instruction->base,
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;
return ira->codegen->builtin_types.entry_invalid;
}
@ -8766,24 +8767,24 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
{
assert(var->value.type);
if (type_is_invalid(var->value.type))
return var->value.type;
assert(var->value->type);
if (type_is_invalid(var->value->type))
return var->value->type;
bool comptime_var_mem = ir_get_var_is_comptime(var);
ConstExprValue *mem_slot = nullptr;
FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope);
if (var->value.special == ConstValSpecialStatic) {
mem_slot = &var->value;
if (var->value->special == ConstValSpecialStatic) {
mem_slot = var->value;
} else if (fn_entry) {
// 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))
mem_slot = &ira->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_volatile = (var->value.type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
ConstPtrMut ptr_mut;
if (comptime_var_mem) {
@ -8794,11 +8795,11 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc
assert(!comptime_var_mem);
ptr_mut = ConstPtrMutRuntimeVar;
}
return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type, ptr_mut, is_const, is_volatile);
return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value->type, ptr_mut, is_const, is_volatile);
} else {
ir_build_var_ptr_from(&ira->new_irb, instruction, var, is_const, is_volatile);
type_ensure_zero_bits_known(ira->codegen, var->value.type);
return get_pointer_to_type(ira->codegen, var->value.type, var->src_is_const);
type_ensure_zero_bits_known(ira->codegen, var->value->type);
return get_pointer_to_type(ira->codegen, var->value->type, var->src_is_const);
}
}
@ -12520,8 +12521,8 @@ FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableE
fn_entry->fndef_scope = create_fndef_scope(nullptr, parent_scope, fn_entry);
fn_entry->child_scope = &fn_entry->fndef_scope->base;
assert(var->value.type->id == TypeTableEntryIdMaybe);
TypeTableEntry *src_fn_type = var->value.type->data.maybe.child_type;
assert(var->value->type->id == TypeTableEntryIdMaybe);
TypeTableEntry *src_fn_type = var->value->type->data.maybe.child_type;
assert(src_fn_type->id == TypeTableEntryIdFn);
FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id;

View File

@ -1235,7 +1235,7 @@ static void process_symbol_macros(Context *c) {
// variable is non-null and calls it.
if (existing_tld->id == TldIdVar) {
TldVar *tld_var = (TldVar *)existing_tld;
TypeTableEntry *var_type = tld_var->var->value.type;
TypeTableEntry *var_type = tld_var->var->value->type;
if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) {
TypeTableEntry *child_type = var_type->data.maybe.child_type;
if (child_type->id == TypeTableEntryIdFn) {

View File

@ -72,24 +72,23 @@ fn nestedArrays() {
}
// TODO
//var s_array: [8]Sub = undefined;
//const Sub = struct {
// b: u8,
//};
//const Str = struct {
// a: []Sub,
//};
//fn setGlobalVarArrayViaSliceEmbeddedInStruct() {
// @setFnTest(this);
//
// var s = Str { .a = s_array[0...]};
//
// s.a[0].b = 1;
// s.a[1].b = 2;
// s.a[2].b = 3;
//
// assert(s_array[0].b == 1);
// assert(s_array[1].b == 2);
// assert(s_array[2].b == 3);
//}
var s_array: [8]Sub = undefined;
const Sub = struct {
b: u8,
};
const Str = struct {
a: []Sub,
};
fn setGlobalVarArrayViaSliceEmbeddedInStruct() {
@setFnTest(this);
var s = Str { .a = s_array[0...]};
s.a[0].b = 1;
s.a[1].b = 2;
s.a[2].b = 3;
assert(s_array[0].b == 1);
assert(s_array[1].b == 2);
assert(s_array[2].b == 3);
}