implement undefined literal
parent
0e51c16ef5
commit
e269caae02
|
@ -62,6 +62,7 @@ struct ConstPtrValue {
|
|||
struct ConstExprValue {
|
||||
bool ok; // true if constant expression evalution worked
|
||||
bool depends_on_compile_var;
|
||||
bool undef;
|
||||
|
||||
union {
|
||||
BigNum x_bignum;
|
||||
|
@ -808,6 +809,7 @@ enum TypeTableEntryId {
|
|||
TypeTableEntryIdStruct,
|
||||
TypeTableEntryIdNumLitFloat,
|
||||
TypeTableEntryIdNumLitInt,
|
||||
TypeTableEntryIdUndefLit,
|
||||
TypeTableEntryIdMaybe,
|
||||
TypeTableEntryIdError,
|
||||
TypeTableEntryIdEnum,
|
||||
|
@ -949,6 +951,7 @@ struct CodeGen {
|
|||
TypeTableEntry *entry_invalid;
|
||||
TypeTableEntry *entry_num_lit_int;
|
||||
TypeTableEntry *entry_num_lit_float;
|
||||
TypeTableEntry *entry_undef;
|
||||
} builtin_types;
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
|
|
|
@ -111,6 +111,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
|||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdError:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
// nothing to init
|
||||
break;
|
||||
case TypeTableEntryIdStruct:
|
||||
|
@ -1063,6 +1064,7 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
|
|||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
return false;
|
||||
|
||||
case TypeTableEntryIdBool:
|
||||
|
@ -2481,10 +2483,9 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt
|
|||
ConstExprValue *const_val = &expr->const_val;
|
||||
|
||||
const_val->ok = true;
|
||||
const_val->undef = true;
|
||||
|
||||
zig_panic("TODO");
|
||||
|
||||
return expected_type;
|
||||
return expected_type ? expected_type : g->builtin_types.entry_undef;
|
||||
}
|
||||
|
||||
|
||||
|
|
150
src/codegen.cpp
150
src/codegen.cpp
|
@ -1725,84 +1725,91 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
|||
}
|
||||
if (variable->type->size_in_bits == 0) {
|
||||
return nullptr;
|
||||
} else {
|
||||
if (var_decl->expr) {
|
||||
TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
|
||||
LLVMValueRef value;
|
||||
if (unwrap_maybe) {
|
||||
assert(var_decl->expr);
|
||||
assert(expr_type->id == TypeTableEntryIdMaybe);
|
||||
value = gen_unwrap_maybe(g, source_node, *init_value);
|
||||
expr_type = expr_type->data.maybe.child_type;
|
||||
} else {
|
||||
value = *init_value;
|
||||
}
|
||||
gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
|
||||
value, variable->type, expr_type);
|
||||
}
|
||||
|
||||
bool have_init_expr = false;
|
||||
if (var_decl->expr) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
|
||||
if (!const_val->ok || !const_val->undef) {
|
||||
have_init_expr = true;
|
||||
}
|
||||
}
|
||||
if (have_init_expr) {
|
||||
TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
|
||||
LLVMValueRef value;
|
||||
if (unwrap_maybe) {
|
||||
assert(var_decl->expr);
|
||||
assert(expr_type->id == TypeTableEntryIdMaybe);
|
||||
value = gen_unwrap_maybe(g, source_node, *init_value);
|
||||
expr_type = expr_type->data.maybe.child_type;
|
||||
} else {
|
||||
bool ignore_uninit = false;
|
||||
TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
|
||||
if (var_type->id == TypeTableEntryIdStruct &&
|
||||
var_type->data.structure.is_unknown_size_array)
|
||||
{
|
||||
assert(var_decl->type->type == NodeTypeArrayType);
|
||||
AstNode *size_node = var_decl->type->data.array_type.size;
|
||||
if (size_node) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
|
||||
if (!const_val->ok) {
|
||||
TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
|
||||
value = *init_value;
|
||||
}
|
||||
gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
|
||||
value, variable->type, expr_type);
|
||||
} else {
|
||||
bool ignore_uninit = false;
|
||||
TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
|
||||
if (var_type->id == TypeTableEntryIdStruct &&
|
||||
var_type->data.structure.is_unknown_size_array)
|
||||
{
|
||||
assert(var_decl->type->type == NodeTypeArrayType);
|
||||
AstNode *size_node = var_decl->type->data.array_type.size;
|
||||
if (size_node) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
|
||||
if (!const_val->ok) {
|
||||
TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
|
||||
|
||||
LLVMValueRef size_val = gen_expr(g, size_node);
|
||||
LLVMValueRef size_val = gen_expr(g, size_node);
|
||||
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
|
||||
size_val, "");
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
|
||||
size_val, "");
|
||||
|
||||
// store the freshly allocated pointer in the unknown size array struct
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 0, "");
|
||||
LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
|
||||
// store the freshly allocated pointer in the unknown size array struct
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 0, "");
|
||||
LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
|
||||
|
||||
// store the size in the len field
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 1, "");
|
||||
LLVMBuildStore(g->builder, size_val, len_field_ptr);
|
||||
// store the size in the len field
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
|
||||
variable->value_ref, 1, "");
|
||||
LLVMBuildStore(g->builder, size_val, len_field_ptr);
|
||||
|
||||
// don't clobber what we just did with debug initialization
|
||||
ignore_uninit = true;
|
||||
}
|
||||
// don't clobber what we just did with debug initialization
|
||||
ignore_uninit = true;
|
||||
}
|
||||
}
|
||||
if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
|
||||
// memset uninitialized memory to 0xa
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
|
||||
LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
|
||||
variable->type->size_in_bits / 8, false);
|
||||
LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
|
||||
variable->type->align_in_bits / 8, false);
|
||||
LLVMValueRef params[] = {
|
||||
dest_ptr,
|
||||
fill_char,
|
||||
byte_count,
|
||||
align_in_bytes,
|
||||
LLVMConstNull(LLVMInt1Type()), // is volatile
|
||||
};
|
||||
|
||||
LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
|
||||
}
|
||||
}
|
||||
if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
|
||||
// memset uninitialized memory to 0xa
|
||||
add_debug_source_node(g, source_node);
|
||||
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
|
||||
LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
|
||||
variable->type->size_in_bits / 8, false);
|
||||
LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
|
||||
variable->type->align_in_bits / 8, false);
|
||||
LLVMValueRef params[] = {
|
||||
dest_ptr,
|
||||
fill_char,
|
||||
byte_count,
|
||||
align_in_bytes,
|
||||
LLVMConstNull(LLVMInt1Type()), // is volatile
|
||||
};
|
||||
|
||||
LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
|
||||
g->cur_block_context->di_scope);
|
||||
LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
|
||||
LLVMGetInsertBlock(g->builder));
|
||||
return nullptr;
|
||||
LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
|
||||
}
|
||||
}
|
||||
|
||||
LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
|
||||
g->cur_block_context->di_scope);
|
||||
LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
|
||||
LLVMGetInsertBlock(g->builder));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
||||
|
@ -2035,6 +2042,10 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
|
|||
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
|
||||
assert(const_val->ok);
|
||||
|
||||
if (const_val->undef) {
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
}
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
|
@ -2389,6 +2400,11 @@ static void define_builtin_types(CodeGen *g) {
|
|||
buf_init_from_str(&entry->name, "(integer literal)");
|
||||
g->builtin_types.entry_num_lit_int = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
|
||||
buf_init_from_str(&entry->name, "(undefined)");
|
||||
g->builtin_types.entry_undef = entry;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array_length(int_sizes_in_bits); i += 1) {
|
||||
int size_in_bits = int_sizes_in_bits[i];
|
||||
|
|
Loading…
Reference in New Issue