Commit 707154da36
Changed files (4)
src/all_types.hpp
@@ -788,6 +788,8 @@ struct TypeTableEntryStruct {
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
bool reported_infinite_err;
+ // whether we've finished resolving it
+ bool complete;
};
struct TypeTableEntryMaybe {
@@ -812,6 +814,8 @@ struct TypeTableEntryEnum {
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
bool reported_infinite_err;
+ // whether we've finished resolving it
+ bool complete;
};
struct TypeTableEntryFn {
src/analyze.cpp
@@ -25,6 +25,7 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
BlockContext *context, AstNode *node, Buf *err_name);
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
+static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
@@ -152,17 +153,34 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
return *parent_pointer;
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
- entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
- entry->size_in_bits = g->pointer_size_bytes * 8;
- entry->align_in_bits = g->pointer_size_bytes * 8;
- assert(child_type->di_type);
- entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
- entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
+ bool zero_bits;
+ if (child_type->size_in_bits == 0) {
+ if (child_type->id == TypeTableEntryIdStruct) {
+ zero_bits = child_type->data.structure.complete;
+ } else if (child_type->id == TypeTableEntryIdEnum) {
+ zero_bits = child_type->data.enumeration.complete;
+ } else {
+ zero_bits = true;
+ }
+ } else {
+ zero_bits = false;
+ }
+
+ if (!zero_bits) {
+ entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
+
+ entry->size_in_bits = g->pointer_size_bytes * 8;
+ entry->align_in_bits = g->pointer_size_bytes * 8;
+ assert(child_type->di_type);
+ entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
+ entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
+ }
+
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
@@ -511,6 +529,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
// after the gen_param_index += 1 because 0 is the return type
param_di_types[gen_param_index] = gen_type->di_type;
gen_return_type = g->builtin_types.entry_void;
+ } else if (return_type->size_in_bits == 0) {
+ gen_return_type = g->builtin_types.entry_void;
} else {
gen_return_type = return_type;
}
@@ -584,7 +604,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage);
- if (gen_return_type->id == TypeTableEntryIdUnreachable) {
+ if (return_type->id == TypeTableEntryIdUnreachable) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
}
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
@@ -707,6 +727,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
// unset temporary flag
enum_type->data.enumeration.embedded_in_current = false;
+ enum_type->data.enumeration.complete = true;
if (!enum_type->data.enumeration.is_invalid) {
enum_type->data.enumeration.gen_field_count = gen_field_index;
@@ -872,6 +893,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
struct_type->data.structure.embedded_in_current = false;
struct_type->data.structure.gen_field_count = gen_field_index;
+ struct_type->data.structure.complete = true;
if (!struct_type->data.structure.is_invalid) {
@@ -1186,7 +1208,9 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
static void add_global_const_expr(CodeGen *g, Expr *expr) {
if (expr->const_val.ok &&
- type_has_codegen_value(expr->type_entry->id) && !expr->has_global_const)
+ type_has_codegen_value(expr->type_entry->id) &&
+ !expr->has_global_const &&
+ expr->type_entry->size_in_bits > 0)
{
g->global_const_list.append(expr);
expr->has_global_const = true;
@@ -1776,7 +1800,7 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
return g->builtin_types.entry_invalid;
} else {
- return container_type;
+ return resolve_expr_const_val_as_void(g, node);
}
} else if (container_type->id == TypeTableEntryIdUnreachable) {
if (container_init_expr->entries.length != 0) {
@@ -1925,6 +1949,12 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
return return_type;
}
+static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
+ Expr *expr = get_resolved_expr(node);
+ expr->const_val.ok = true;
+ return g->builtin_types.entry_void;
+}
+
static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
src/codegen.cpp
@@ -510,7 +510,6 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
}
TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type;
- TypeTableEntry *gen_return_type = fn_type->data.fn.gen_return_type;
int fn_call_param_count = node->data.fn_call_expr.params.length;
bool first_arg_ret = handle_is_ptr(src_return_type);
@@ -544,7 +543,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
- if (gen_return_type->id == TypeTableEntryIdUnreachable) {
+ if (src_return_type->id == TypeTableEntryIdUnreachable) {
return LLVMBuildUnreachable(g->builder);
} else if (first_arg_ret) {
return node->data.fn_call_expr.tmp_ptr;
@@ -821,8 +820,6 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
VariableTableEntry *var = find_variable(expr_node->block_context,
&node->data.symbol_expr.symbol);
assert(var);
- // semantic checking ensures no variables are constant
- assert(!var->is_const);
*out_type_entry = var->type;
target_ref = var->value_ref;
@@ -895,8 +892,13 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
case PrefixOpDereference:
{
LLVMValueRef expr = gen_expr(g, expr_node);
- add_debug_source_node(g, node);
- return LLVMBuildLoad(g->builder, expr, "");
+ TypeTableEntry *type_entry = get_expr_type(expr_node);
+ if (type_entry->size_in_bits == 0) {
+ return nullptr;
+ } else {
+ add_debug_source_node(g, node);
+ return LLVMBuildLoad(g->builder, expr, "");
+ }
}
case PrefixOpMaybe:
{
@@ -2182,8 +2184,12 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node);
if (expr->const_val.ok) {
- assert(expr->const_llvm_val);
- return expr->const_llvm_val;
+ if (expr->type_entry->size_in_bits == 0) {
+ return nullptr;
+ } else {
+ assert(expr->const_llvm_val);
+ return expr->const_llvm_val;
+ }
}
switch (node->type) {
case NodeTypeBinOpExpr:
@@ -2291,119 +2297,144 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
return LLVMGetUndef(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 == TypeTableEntryIdPureError) {
- assert(const_val->data.x_err.err);
- return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false);
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- if (const_val->data.x_bignum.kind == BigNumKindFloat) {
- return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
- } else {
- int64_t x = const_val->data.x_bignum.data.x_uint;
- if (const_val->data.x_bignum.is_negative) {
- x = -x;
+ switch (type_entry->id) {
+ case TypeTableEntryIdInt:
+ return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
+ case TypeTableEntryIdPureError:
+ assert(const_val->data.x_err.err);
+ return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
+ const_val->data.x_err.err->value, false);
+ case TypeTableEntryIdFloat:
+ if (const_val->data.x_bignum.kind == BigNumKindFloat) {
+ return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
+ } else {
+ int64_t x = const_val->data.x_bignum.data.x_uint;
+ if (const_val->data.x_bignum.is_negative) {
+ x = -x;
+ }
+ return LLVMConstReal(type_entry->type_ref, x);
}
- return LLVMConstReal(type_entry->type_ref, x);
- }
- } else if (type_entry->id == TypeTableEntryIdBool) {
- if (const_val->data.x_bool) {
- return LLVMConstAllOnes(LLVMInt1Type());
- } else {
- return LLVMConstNull(LLVMInt1Type());
- }
- } else if (type_entry->id == TypeTableEntryIdMaybe) {
- TypeTableEntry *child_type = type_entry->data.maybe.child_type;
- LLVMValueRef child_val;
- LLVMValueRef maybe_val;
- if (const_val->data.x_maybe) {
- child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
- maybe_val = LLVMConstAllOnes(LLVMInt1Type());
- } else {
- child_val = LLVMConstNull(child_type->type_ref);
- maybe_val = LLVMConstNull(LLVMInt1Type());
- }
- LLVMValueRef fields[] = {
- child_val,
- maybe_val,
- };
- return LLVMConstStruct(fields, 2, false);
- } else if (type_entry->id == TypeTableEntryIdStruct) {
- LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
- for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
- TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
- fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
- const_val->data.x_struct.fields[i]);
- }
- return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
- } else if (type_entry->id == TypeTableEntryIdArray) {
- TypeTableEntry *child_type = type_entry->data.array.child_type;
- uint64_t len = type_entry->data.array.len;
- LLVMValueRef *values = allocate<LLVMValueRef>(len);
- for (int i = 0; i < len; i += 1) {
- ConstExprValue *field_value = const_val->data.x_array.fields[i];
- values[i] = gen_const_val(g, child_type, field_value);
- }
- return LLVMConstArray(child_type->type_ref, values, len);
- } else if (type_entry->id == TypeTableEntryIdEnum) {
- LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
- LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
- if (type_entry->data.enumeration.gen_field_count == 0) {
- return tag_value;
- } else {
- zig_panic("TODO");
- }
- } else if (type_entry->id == TypeTableEntryIdFn) {
- return const_val->data.x_fn->fn_value;
- } else if (type_entry->id == TypeTableEntryIdPointer) {
- TypeTableEntry *child_type = type_entry->data.pointer.child_type;
- int len = const_val->data.x_ptr.len;
- LLVMValueRef target_val;
- if (len == 1) {
- target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]);
- } else if (len > 1) {
- LLVMValueRef *values = allocate<LLVMValueRef>(len);
- for (int i = 0; i < len; i += 1) {
- values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]);
+ case TypeTableEntryIdBool:
+ if (const_val->data.x_bool) {
+ return LLVMConstAllOnes(LLVMInt1Type());
+ } else {
+ return LLVMConstNull(LLVMInt1Type());
}
- target_val = LLVMConstArray(child_type->type_ref, values, len);
- } else {
+ case TypeTableEntryIdMaybe:
+ {
+ TypeTableEntry *child_type = type_entry->data.maybe.child_type;
+ LLVMValueRef child_val;
+ LLVMValueRef maybe_val;
+ if (const_val->data.x_maybe) {
+ child_val = gen_const_val(g, child_type, const_val->data.x_maybe);
+ maybe_val = LLVMConstAllOnes(LLVMInt1Type());
+ } else {
+ child_val = LLVMConstNull(child_type->type_ref);
+ maybe_val = LLVMConstNull(LLVMInt1Type());
+ }
+ LLVMValueRef fields[] = {
+ child_val,
+ maybe_val,
+ };
+ return LLVMConstStruct(fields, 2, false);
+ }
+ case TypeTableEntryIdStruct:
+ {
+ LLVMValueRef *fields = allocate<LLVMValueRef>(type_entry->data.structure.gen_field_count);
+ for (int i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
+ TypeStructField *type_struct_field = &type_entry->data.structure.fields[i];
+ if (type_struct_field->gen_index == -1) {
+ continue;
+ }
+ fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry,
+ const_val->data.x_struct.fields[i]);
+ }
+ return LLVMConstNamedStruct(type_entry->type_ref, fields,
+ type_entry->data.structure.gen_field_count);
+ }
+ case TypeTableEntryIdArray:
+ {
+ TypeTableEntry *child_type = type_entry->data.array.child_type;
+ uint64_t len = type_entry->data.array.len;
+ LLVMValueRef *values = allocate<LLVMValueRef>(len);
+ for (int i = 0; i < len; i += 1) {
+ ConstExprValue *field_value = const_val->data.x_array.fields[i];
+ values[i] = gen_const_val(g, child_type, field_value);
+ }
+ return LLVMConstArray(child_type->type_ref, values, len);
+ }
+ case TypeTableEntryIdEnum:
+ {
+ LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
+ LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
+ if (type_entry->data.enumeration.gen_field_count == 0) {
+ return tag_value;
+ } else {
+ zig_panic("TODO");
+ }
+ }
+ case TypeTableEntryIdFn:
+ return const_val->data.x_fn->fn_value;
+ case TypeTableEntryIdPointer:
+ {
+ TypeTableEntry *child_type = type_entry->data.pointer.child_type;
+ int len = const_val->data.x_ptr.len;
+ LLVMValueRef target_val;
+ if (len == 1) {
+ target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]);
+ } else if (len > 1) {
+ LLVMValueRef *values = allocate<LLVMValueRef>(len);
+ for (int i = 0; i < len; i += 1) {
+ values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]);
+ }
+ target_val = LLVMConstArray(child_type->type_ref, values, len);
+ } else {
+ zig_unreachable();
+ }
+ LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), "");
+ LLVMSetInitializer(global_value, target_val);
+ LLVMSetLinkage(global_value, LLVMPrivateLinkage);
+ LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const);
+ LLVMSetUnnamedAddr(global_value, true);
+
+ if (len > 1) {
+ return LLVMConstBitCast(global_value, type_entry->type_ref);
+ } else {
+ return global_value;
+ }
+ }
+ case TypeTableEntryIdErrorUnion:
+ {
+ TypeTableEntry *child_type = type_entry->data.error.child_type;
+ if (child_type->size_in_bits == 0) {
+ uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
+ return LLVMConstInt(g->err_tag_type->type_ref, value, false);
+ } else {
+ LLVMValueRef err_tag_value;
+ LLVMValueRef err_payload_value;
+ if (const_val->data.x_err.err) {
+ err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false);
+ err_payload_value = LLVMConstNull(child_type->type_ref);
+ } else {
+ err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
+ err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload);
+ }
+ LLVMValueRef fields[] = {
+ err_tag_value,
+ err_payload_value,
+ };
+ return LLVMConstStruct(fields, 2, false);
+ }
+ }
+ case TypeTableEntryIdInvalid:
+ case TypeTableEntryIdMetaType:
+ case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdVoid:
zig_unreachable();
- }
- LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), "");
- LLVMSetInitializer(global_value, target_val);
- LLVMSetLinkage(global_value, LLVMPrivateLinkage);
- LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const);
- LLVMSetUnnamedAddr(global_value, true);
- if (len > 1) {
- return LLVMConstBitCast(global_value, type_entry->type_ref);
- } else {
- return global_value;
- }
- } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
- TypeTableEntry *child_type = type_entry->data.error.child_type;
- if (child_type->size_in_bits == 0) {
- uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
- return LLVMConstInt(g->err_tag_type->type_ref, value, false);
- } else {
- LLVMValueRef err_tag_value;
- LLVMValueRef err_payload_value;
- if (const_val->data.x_err.err) {
- err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false);
- err_payload_value = LLVMConstNull(child_type->type_ref);
- } else {
- err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
- err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload);
- }
- LLVMValueRef fields[] = {
- err_tag_value,
- err_payload_value,
- };
- return LLVMConstStruct(fields, 2, false);
- }
- } else {
- zig_unreachable();
}
}
@@ -2438,7 +2469,8 @@ static void do_code_gen(CodeGen *g) {
VariableTableEntry *var = g->global_vars.at(i);
if (var->type->id == TypeTableEntryIdNumLitFloat ||
- var->type->id == TypeTableEntryIdNumLitInt)
+ var->type->id == TypeTableEntryIdNumLitInt ||
+ var->type->size_in_bits == 0)
{
continue;
}
test/run_tests.cpp
@@ -1316,6 +1316,19 @@ pub fn main(args: [][]u8) -> %void {
%%stdout.printf("BAD\n");
}
%%stdout.printf("OK\n");
+}
+ )SOURCE", "OK\n");
+
+ add_simple_case("pointer to void return type", R"SOURCE(
+import "std.zig";
+const x = void{};
+fn f() -> &void {
+ %%stdout.printf("OK\n");
+ return &x;
+}
+pub fn main(args: [][]u8) -> %void {
+ const a = f();
+ return *a;
}
)SOURCE", "OK\n");
}