authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 22:55:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-12 22:55:29-07:00
logbd77bc749a1b38ef754fdd5b7e14a8228cb6f72c
tree1cc38a744572519ef574fcd21bb9a3a6d18772d7
parent0f02e29a2b7a975407c7f3b4ed742f886e0c1add

structs are working


5 files changed, 124 insertions(+), 90 deletions(-)

example/structs/structs.zig-2
...@@ -2,8 +2,6 @@ export executable "structs";...@@ -2,8 +2,6 @@ export executable "structs";
22
3use "std.zig";3use "std.zig";
44
5// Note: this example is not working because codegen is confused about
6// how byvalue structs which are in memory on the stack work
7export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {5export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
8 let mut foo : Foo;6 let mut foo : Foo;
97
src/analyze.cpp+43-39
...@@ -758,6 +758,47 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {...@@ -758,6 +758,47 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
758 zig_unreachable();758 zig_unreachable();
759}759}
760760
761static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
762 TypeTableEntry *expected_type, AstNode *node)
763{
764 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);
765 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
766
767 if (wanted_type->id == TypeTableEntryIdInvalid ||
768 actual_type->id == TypeTableEntryIdInvalid)
769 {
770 return g->builtin_types.entry_invalid;
771 }
772
773 CastNode *cast_node = &node->codegen_node->data.cast_node;
774
775 // special casing this for now, TODO think about casting and do a general solution
776 if (wanted_type == g->builtin_types.entry_isize &&
777 actual_type->id == TypeTableEntryIdPointer)
778 {
779 cast_node->op = CastOpPtrToInt;
780 return wanted_type;
781 } else if (wanted_type->id == TypeTableEntryIdInt &&
782 actual_type->id == TypeTableEntryIdInt)
783 {
784 cast_node->op = CastOpIntWidenOrShorten;
785 return wanted_type;
786 } else if (wanted_type == g->builtin_types.entry_string &&
787 actual_type->id == TypeTableEntryIdArray &&
788 actual_type->data.array.child_type == g->builtin_types.entry_u8)
789 {
790 cast_node->op = CastOpArrayToString;
791 context->cast_expr_alloca_list.append(node);
792 return wanted_type;
793 } else {
794 add_node_error(g, node,
795 buf_sprintf("invalid cast from type '%s' to '%s'",
796 buf_ptr(&actual_type->name),
797 buf_ptr(&wanted_type->name)));
798 return g->builtin_types.entry_invalid;
799 }
800}
801
761static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,802static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
762 TypeTableEntry *expected_type, AstNode *node)803 TypeTableEntry *expected_type, AstNode *node)
763{804{
...@@ -1100,45 +1141,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1100,45 +1141,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1100 break;1141 break;
1101 }1142 }
1102 case NodeTypeCastExpr:1143 case NodeTypeCastExpr:
1103 {1144 return_type = analyze_cast_expr(g, import, context, expected_type, node);
1104 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type);1145 break;
1105 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr,
1106 node->data.cast_expr.expr);
1107
1108 if (wanted_type->id == TypeTableEntryIdInvalid ||
1109 actual_type->id == TypeTableEntryIdInvalid)
1110 {
1111 return_type = g->builtin_types.entry_invalid;
1112 break;
1113 }
1114
1115 CastNode *cast_node = &node->codegen_node->data.cast_node;
1116
1117 // special casing this for now, TODO think about casting and do a general solution
1118 if (wanted_type == g->builtin_types.entry_isize &&
1119 actual_type->id == TypeTableEntryIdPointer)
1120 {
1121 cast_node->op = CastOpPtrToInt;
1122 return_type = wanted_type;
1123 } else if (wanted_type->id == TypeTableEntryIdInt &&
1124 actual_type->id == TypeTableEntryIdInt)
1125 {
1126 cast_node->op = CastOpIntWidenOrShorten;
1127 return_type = wanted_type;
1128 } else if (wanted_type == g->builtin_types.entry_string &&
1129 actual_type->id == TypeTableEntryIdArray &&
1130 actual_type->data.array.child_type == g->builtin_types.entry_u8)
1131 {
1132 cast_node->op = CastOpArrayToString;
1133 return_type = wanted_type;
1134 } else {
1135 add_node_error(g, node,
1136 buf_sprintf("TODO handle cast from '%s' to '%s'",
1137 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
1138 return_type = g->builtin_types.entry_invalid;
1139 }
1140 break;
1141 }
1142 case NodeTypePrefixOpExpr:1146 case NodeTypePrefixOpExpr:
1143 switch (node->data.prefix_op_expr.prefix_op) {1147 switch (node->data.prefix_op_expr.prefix_op) {
1144 case PrefixOpBoolNot:1148 case PrefixOpBoolNot:
src/analyze.hpp+4
...@@ -193,6 +193,7 @@ struct BlockContext {...@@ -193,6 +193,7 @@ struct BlockContext {
193 BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef193 BlockContext *root; // always points to the BlockContext with the NodeTypeFnDef
194 BlockContext *parent; // nullptr when this is the root194 BlockContext *parent; // nullptr when this is the root
195 HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;195 HashMap<Buf *, LocalVariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
196 ZigList<AstNode *> cast_expr_alloca_list;
196 LLVMZigDIScope *di_scope;197 LLVMZigDIScope *di_scope;
197};198};
198199
...@@ -244,6 +245,9 @@ enum CastOp {...@@ -244,6 +245,9 @@ enum CastOp {
244245
245struct CastNode {246struct CastNode {
246 CastOp op;247 CastOp op;
248 // if op is CastOpArrayToString, this will be a pointer to
249 // the string struct on the stack
250 LLVMValueRef ptr;
247};251};
248252
249struct CodeGenNode {253struct CodeGenNode {
src/codegen.cpp+56-49
...@@ -59,30 +59,31 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {...@@ -59,30 +59,31 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
59}59}
6060
61static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);61static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
62
6263
63static LLVMTypeRef to_llvm_type(AstNode *type_node) {64static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
64 assert(type_node->type == NodeTypeType);65 assert(type_node->type == NodeTypeType);
65 assert(type_node->codegen_node);66 assert(type_node->codegen_node);
66 assert(type_node->codegen_node->data.type_node.entry);67 assert(type_node->codegen_node->data.type_node.entry);
6768 return type_node->codegen_node->data.type_node.entry;
68 return type_node->codegen_node->data.type_node.entry->type_ref;
69}69}
7070
71static LLVMZigDIType *to_llvm_debug_type(AstNode *type_node) {71static LLVMTypeRef fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
72 assert(type_node->type == NodeTypeType);72 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
73 assert(type_node->codegen_node);
74 assert(type_node->codegen_node->data.type_node.entry);
7573
76 return type_node->codegen_node->data.type_node.entry->di_type;74 if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
75 return get_pointer_to_type(g, type_entry, true)->type_ref;
76 } else {
77 return type_entry->type_ref;
78 }
77}79}
7880
79static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {81static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) {
80 assert(type_node->type == NodeTypeType);82 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
81 assert(type_node->codegen_node);83 return type_entry->di_type;
82 assert(type_node->codegen_node->data.type_node.entry);
83 return type_node->codegen_node->data.type_node.entry;
84}84}
8585
86
86static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {87static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
87 return get_type_for_type_node(g, type_node) == g->builtin_types.entry_unreachable;88 return get_type_for_type_node(g, type_node) == g->builtin_types.entry_unreachable;
88}89}
...@@ -198,20 +199,6 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {...@@ -198,20 +199,6 @@ static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) {
198 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");199 return LLVMBuildInBoundsGEP(g->builder, array_ref_value, indices, 2, "");
199}200}
200201
201static LLVMValueRef gen_field_val(CodeGen *g, AstNode *node) {
202 assert(node->type == NodeTypeFieldAccessExpr);
203
204 LLVMValueRef struct_val = gen_expr(g, node->data.field_access_expr.struct_expr);
205 assert(struct_val);
206
207 FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
208 assert(codegen_field_access->field_index >= 0);
209
210 add_debug_source_node(g, node);
211 return LLVMBuildExtractValue(g->builder, struct_val, codegen_field_access->field_index, "");
212}
213
214/*
215static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {202static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
216 assert(node->type == NodeTypeFieldAccessExpr);203 assert(node->type == NodeTypeFieldAccessExpr);
217204
...@@ -223,9 +210,9 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {...@@ -223,9 +210,9 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node) {
223210
224 assert(codegen_field_access->field_index >= 0);211 assert(codegen_field_access->field_index >= 0);
225212
213 add_debug_source_node(g, node);
226 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");214 return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
227}215}
228*/
229216
230static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {217static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node) {
231 assert(node->type == NodeTypeArrayAccessExpr);218 assert(node->type == NodeTypeArrayAccessExpr);
...@@ -249,11 +236,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {...@@ -249,11 +236,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
249 zig_panic("gen_field_access_expr bad array field");236 zig_panic("gen_field_access_expr bad array field");
250 }237 }
251 } else if (struct_type->id == TypeTableEntryIdStruct) {238 } else if (struct_type->id == TypeTableEntryIdStruct) {
252 /*
253 LLVMValueRef ptr = gen_field_ptr(g, node);239 LLVMValueRef ptr = gen_field_ptr(g, node);
254 return LLVMBuildLoad(g->builder, ptr, "");240 return LLVMBuildLoad(g->builder, ptr, "");
255 */
256 return gen_field_val(g, node);
257 } else {241 } else {
258 zig_panic("gen_field_access_expr bad struct type");242 zig_panic("gen_field_access_expr bad struct type");
259 }243 }
...@@ -311,14 +295,19 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -311,14 +295,19 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
311 }295 }
312 case CastOpArrayToString:296 case CastOpArrayToString:
313 {297 {
314 LLVMValueRef struct_vals[] = {298 assert(cast_node->ptr);
315 expr_val,299
316 LLVMConstInt(g->builtin_types.entry_usize->type_ref, actual_type->data.array.len, false)300 add_debug_source_node(g, node);
317 };301
318 unsigned field_count = g->builtin_types.entry_string->data.structure.field_count;302 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
319 assert(field_count == 2);303 LLVMBuildStore(g->builder, expr_val, ptr_ptr);
320 return LLVMConstNamedStruct(g->builtin_types.entry_string->type_ref,304
321 struct_vals, field_count);305 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
306 LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
307 actual_type->data.array.len, false);
308 LLVMBuildStore(g->builder, len_val, len_ptr);
309
310 return cast_node->ptr;
322 }311 }
323 }312 }
324 zig_unreachable();313 zig_unreachable();
...@@ -580,6 +569,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -580,6 +569,8 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
580 assert(array_type->id == TypeTableEntryIdArray);569 assert(array_type->id == TypeTableEntryIdArray);
581 op1_type = array_type->data.array.child_type;570 op1_type = array_type->data.array.child_type;
582 target_ref = gen_array_ptr(g, lhs_node);571 target_ref = gen_array_ptr(g, lhs_node);
572 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
573 target_ref = gen_field_ptr(g, lhs_node);
583 } else {574 } else {
584 zig_panic("bad assign target");575 zig_panic("bad assign target");
585 }576 }
...@@ -717,6 +708,7 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {...@@ -717,6 +708,7 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
717static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {708static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
718 assert(block_node->type == NodeTypeBlock);709 assert(block_node->type == NodeTypeBlock);
719710
711 BlockContext *old_block_context = g->cur_block_context;
720 g->cur_block_context = block_node->codegen_node->data.block_node.block_context;712 g->cur_block_context = block_node->codegen_node->data.block_node.block_context;
721713
722 LLVMValueRef return_value;714 LLVMValueRef return_value;
...@@ -726,6 +718,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i...@@ -726,6 +718,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
726 }718 }
727719
728 if (implicit_return_type) {720 if (implicit_return_type) {
721 add_debug_source_node(g, block_node);
729 if (implicit_return_type == g->builtin_types.entry_void) {722 if (implicit_return_type == g->builtin_types.entry_void) {
730 LLVMBuildRetVoid(g->builder);723 LLVMBuildRetVoid(g->builder);
731 } else if (implicit_return_type != g->builtin_types.entry_unreachable) {724 } else if (implicit_return_type != g->builtin_types.entry_unreachable) {
...@@ -733,6 +726,8 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i...@@ -733,6 +726,8 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
733 }726 }
734 }727 }
735728
729 g->cur_block_context = old_block_context;
730
736 return return_value;731 return return_value;
737}732}
738733
...@@ -934,6 +929,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -934,6 +929,8 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
934 } else if (variable->is_ptr) {929 } else if (variable->is_ptr) {
935 if (variable->type->id == TypeTableEntryIdArray) {930 if (variable->type->id == TypeTableEntryIdArray) {
936 return variable->value_ref;931 return variable->value_ref;
932 } else if (variable->type->id == TypeTableEntryIdStruct) {
933 return variable->value_ref;
937 } else {934 } else {
938 add_debug_source_node(g, node);935 add_debug_source_node(g, node);
939 return LLVMBuildLoad(g->builder, variable->value_ref, "");936 return LLVMBuildLoad(g->builder, variable->value_ref, "");
...@@ -994,12 +991,12 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro...@@ -994,12 +991,12 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
994 LLVMZigDIFile *di_file)991 LLVMZigDIFile *di_file)
995{992{
996 LLVMZigDIType **types = allocate<LLVMZigDIType*>(1 + fn_proto->params.length);993 LLVMZigDIType **types = allocate<LLVMZigDIType*>(1 + fn_proto->params.length);
997 types[0] = to_llvm_debug_type(fn_proto->return_type);994 types[0] = to_llvm_debug_type(g, fn_proto->return_type);
998 int types_len = fn_proto->params.length + 1;995 int types_len = fn_proto->params.length + 1;
999 for (int i = 0; i < fn_proto->params.length; i += 1) {996 for (int i = 0; i < fn_proto->params.length; i += 1) {
1000 AstNode *param_node = fn_proto->params.at(i);997 AstNode *param_node = fn_proto->params.at(i);
1001 assert(param_node->type == NodeTypeParamDecl);998 assert(param_node->type == NodeTypeParamDecl);
1002 LLVMZigDIType *param_type = to_llvm_debug_type(param_node->data.param_decl.type);999 LLVMZigDIType *param_type = to_llvm_debug_type(g, param_node->data.param_decl.type);
1003 types[i + 1] = param_type;1000 types[i + 1] = param_type;
1004 }1001 }
1005 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);1002 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
...@@ -1026,7 +1023,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1026,7 +1023,7 @@ static void do_code_gen(CodeGen *g) {
1026 assert(proto_node->type == NodeTypeFnProto);1023 assert(proto_node->type == NodeTypeFnProto);
1027 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;1024 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
10281025
1029 LLVMTypeRef ret_type = to_llvm_type(fn_proto->return_type);1026 LLVMTypeRef ret_type = fn_proto_type_from_type_node(g, fn_proto->return_type);
1030 int param_count = count_non_void_params(g, &fn_proto->params);1027 int param_count = count_non_void_params(g, &fn_proto->params);
1031 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);1028 LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
1032 int gen_param_index = 0;1029 int gen_param_index = 0;
...@@ -1036,7 +1033,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1036,7 +1033,7 @@ static void do_code_gen(CodeGen *g) {
1036 if (is_param_decl_type_void(g, param_node))1033 if (is_param_decl_type_void(g, param_node))
1037 continue;1034 continue;
1038 AstNode *type_node = param_node->data.param_decl.type;1035 AstNode *type_node = param_node->data.param_decl.type;
1039 param_types[gen_param_index] = to_llvm_type(type_node);1036 param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node);
1040 gen_param_index += 1;1037 gen_param_index += 1;
1041 }1038 }
1042 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);1039 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
...@@ -1061,8 +1058,8 @@ static void do_code_gen(CodeGen *g) {...@@ -1061,8 +1058,8 @@ static void do_code_gen(CodeGen *g) {
1061 }1058 }
10621059
1063 // Generate function definitions.1060 // Generate function definitions.
1064 for (int i = 0; i < g->fn_defs.length; i += 1) {1061 for (int fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
1065 FnTableEntry *fn_table_entry = g->fn_defs.at(i);1062 FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
1066 ImportTableEntry *import = fn_table_entry->import_entry;1063 ImportTableEntry *import = fn_table_entry->import_entry;
1067 AstNode *fn_def_node = fn_table_entry->fn_def_node;1064 AstNode *fn_def_node = fn_table_entry->fn_def_node;
1068 LLVMValueRef fn = fn_table_entry->fn_value;1065 LLVMValueRef fn = fn_table_entry->fn_value;
...@@ -1101,8 +1098,8 @@ static void do_code_gen(CodeGen *g) {...@@ -1101,8 +1098,8 @@ static void do_code_gen(CodeGen *g) {
1101 LLVMGetParams(fn, params);1098 LLVMGetParams(fn, params);
11021099
1103 int non_void_index = 0;1100 int non_void_index = 0;
1104 for (int i = 0; i < fn_proto->params.length; i += 1) {1101 for (int param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
1105 AstNode *param_decl = fn_proto->params.at(i);1102 AstNode *param_decl = fn_proto->params.at(param_i);
1106 assert(param_decl->type == NodeTypeParamDecl);1103 assert(param_decl->type == NodeTypeParamDecl);
1107 if (is_param_decl_type_void(g, param_decl))1104 if (is_param_decl_type_void(g, param_decl))
1108 continue;1105 continue;
...@@ -1115,8 +1112,8 @@ static void do_code_gen(CodeGen *g) {...@@ -1115,8 +1112,8 @@ static void do_code_gen(CodeGen *g) {
11151112
1116 // Set up debug info for blocks and variables and1113 // Set up debug info for blocks and variables and
1117 // allocate all local variables1114 // allocate all local variables
1118 for (int i = 0; i < codegen_fn_def->all_block_contexts.length; i += 1) {1115 for (int bc_i = 0; bc_i < codegen_fn_def->all_block_contexts.length; bc_i += 1) {
1119 BlockContext *block_context = codegen_fn_def->all_block_contexts.at(i);1116 BlockContext *block_context = codegen_fn_def->all_block_contexts.at(bc_i);
11201117
1121 if (block_context->parent) {1118 if (block_context->parent) {
1122 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,1119 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder,
...@@ -1157,6 +1154,16 @@ static void do_code_gen(CodeGen *g) {...@@ -1157,6 +1154,16 @@ static void do_code_gen(CodeGen *g) {
1157 import->di_file, var->decl_node->line + 1,1154 import->di_file, var->decl_node->line + 1,
1158 var->type->di_type, !g->strip_debug_symbols, 0, arg_no);1155 var->type->di_type, !g->strip_debug_symbols, 0, arg_no);
1159 }1156 }
1157
1158 // allocate structs which are the result of casts
1159 for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
1160 AstNode *cast_expr_node = block_context->cast_expr_alloca_list.at(cea_i);
1161 assert(cast_expr_node->type == NodeTypeCastExpr);
1162 CastNode *cast_codegen = &cast_expr_node->codegen_node->data.cast_node;
1163 TypeTableEntry *type_entry = get_type_for_type_node(g, cast_expr_node->data.cast_expr.type);
1164 add_debug_source_node(g, cast_expr_node);
1165 cast_codegen->ptr = LLVMBuildAlloca(g->builder, type_entry->type_ref, "");
1166 }
1160 }1167 }
11611168
1162 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;1169 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
test/run_tests.cpp+21
...@@ -477,6 +477,27 @@ export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {...@@ -477,6 +477,27 @@ export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
477}477}
478 )SOURCE", "OK\n");478 )SOURCE", "OK\n");
479479
480 add_simple_case("structs", R"SOURCE(
481use "std.zig";
482
483export fn main(argc : isize, argv : *mut *mut u8, env : *mut *mut u8) -> i32 {
484 let mut foo : Foo;
485 foo.a = foo.a + 1;
486 foo.b = foo.a == 1;
487 test_foo(foo);
488 return 0;
489}
490struct Foo {
491 a : i32,
492 b : bool,
493 c : f32,
494}
495fn test_foo(foo : Foo) {
496 if foo.b {
497 print_str("OK\n" as string);
498 }
499}
500 )SOURCE", "OK\n");
480}501}
481502
482static void add_compile_failure_test_cases(void) {503static void add_compile_failure_test_cases(void) {