authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-26 16:44:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-26 16:44:13-04:00
logd6b01931ef8a04777ae198af323c2b6ba998f7b1
treeafa92361832d1b071fb029678524a4b7f01174f8
parentc42c91ee7c630d47e6adc0a940b5f10bbe04d13a

implicitly cast by value var args parameters to const references

See #336

4 files changed, 82 insertions(+), 7 deletions(-)

src/analyze.cpp+1-1
...@@ -299,7 +299,7 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {...@@ -299,7 +299,7 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
299 return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);299 return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);
300}300}
301301
302static bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry) {302bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry) {
303 type_ensure_zero_bits_known(g, type_entry);303 type_ensure_zero_bits_known(g, type_entry);
304 if (!type_has_bits(type_entry))304 if (!type_has_bits(type_entry))
305 return true;305 return true;
src/analyze.hpp+1
...@@ -165,5 +165,6 @@ TypeTableEntryId type_id_at_index(size_t index);...@@ -165,5 +165,6 @@ TypeTableEntryId type_id_at_index(size_t index);
165size_t type_id_len();165size_t type_id_len();
166size_t type_id_index(TypeTableEntryId id);166size_t type_id_index(TypeTableEntryId id);
167TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);167TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
168bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry);
168169
169#endif170#endif
src/ir.cpp+59-6
...@@ -49,6 +49,7 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);...@@ -49,6 +49,7 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
49static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);49static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
50static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);50static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
51static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);51static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type);
52static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
5253
53ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {54ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
54 assert(const_val->type->id == TypeTableEntryIdPointer);55 assert(const_val->type->id == TypeTableEntryIdPointer);
...@@ -6292,7 +6293,26 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6292,7 +6293,26 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6292 }6293 }
6293 }6294 }
62946295
6295 // implicit [N]T to &const []const N6296 // implicit &const [N]T to []const T
6297 if (expected_type->id == TypeTableEntryIdStruct &&
6298 expected_type->data.structure.is_slice &&
6299 actual_type->id == TypeTableEntryIdPointer &&
6300 actual_type->data.pointer.is_const &&
6301 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
6302 {
6303 TypeTableEntry *ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
6304 assert(ptr_type->id == TypeTableEntryIdPointer);
6305
6306 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
6307
6308 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
6309 types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))
6310 {
6311 return ImplicitCastMatchResultYes;
6312 }
6313 }
6314
6315 // implicit [N]T to &const []const T
6296 if (expected_type->id == TypeTableEntryIdPointer &&6316 if (expected_type->id == TypeTableEntryIdPointer &&
6297 expected_type->data.pointer.is_const &&6317 expected_type->data.pointer.is_const &&
6298 is_slice(expected_type->data.pointer.child_type) &&6318 is_slice(expected_type->data.pointer.child_type) &&
...@@ -6308,7 +6328,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -6308,7 +6328,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
6308 }6328 }
6309 }6329 }
63106330
6311 // implicit [N]T to ?[]const N6331 // implicit [N]T to ?[]const T
6312 if (expected_type->id == TypeTableEntryIdMaybe &&6332 if (expected_type->id == TypeTableEntryIdMaybe &&
6313 is_slice(expected_type->data.maybe.child_type) &&6333 is_slice(expected_type->data.maybe.child_type) &&
6314 actual_type->id == TypeTableEntryIdArray)6334 actual_type->id == TypeTableEntryIdArray)
...@@ -7069,12 +7089,20 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi...@@ -7069,12 +7089,20 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
7069}7089}
70707090
7071static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,7091static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
7072 IrInstruction *array, TypeTableEntry *wanted_type)7092 IrInstruction *array_arg, TypeTableEntry *wanted_type)
7073{7093{
7074 assert(is_slice(wanted_type));7094 assert(is_slice(wanted_type));
7075 // In this function we honor the const-ness of wanted_type, because7095 // In this function we honor the const-ness of wanted_type, because
7076 // we may be casting [0]T to []const T which is perfectly valid.7096 // we may be casting [0]T to []const T which is perfectly valid.
70777097
7098 IrInstruction *array_ptr = nullptr;
7099 IrInstruction *array;
7100 if (array_arg->value.type->id == TypeTableEntryIdPointer) {
7101 array = ir_get_deref(ira, source_instr, array_arg);
7102 array_ptr = array_arg;
7103 } else {
7104 array = array_arg;
7105 }
7078 TypeTableEntry *array_type = array->value.type;7106 TypeTableEntry *array_type = array->value.type;
7079 assert(array_type->id == TypeTableEntryIdArray);7107 assert(array_type->id == TypeTableEntryIdArray);
70807108
...@@ -7094,7 +7122,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s...@@ -7094,7 +7122,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
7094 source_instr->source_node, ira->codegen->builtin_types.entry_usize);7122 source_instr->source_node, ira->codegen->builtin_types.entry_usize);
7095 init_const_usize(ira->codegen, &end->value, array_type->data.array.len);7123 init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
70967124
7097 IrInstruction *array_ptr = ir_get_ref(ira, source_instr, array, true, false);7125 if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
70987126
7099 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,7127 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
7100 source_instr->source_node, array_ptr, start, end, false);7128 source_instr->source_node, array_ptr, start, end, false);
...@@ -7374,6 +7402,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -7374,6 +7402,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
7374 }7402 }
7375 }7403 }
73767404
7405 // expliict cast from &const [N]T to []const T
7406 if (is_slice(wanted_type) &&
7407 actual_type->id == TypeTableEntryIdPointer &&
7408 actual_type->data.pointer.is_const &&
7409 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
7410 {
7411 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
7412 assert(ptr_type->id == TypeTableEntryIdPointer);
7413
7414 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
7415
7416 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
7417 types_match_const_cast_only(ptr_type->data.pointer.child_type, array_type->data.array.child_type))
7418 {
7419 return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
7420 }
7421 }
7422
7377 // explicit cast from [N]T to &const []const N7423 // explicit cast from [N]T to &const []const N
7378 if (wanted_type->id == TypeTableEntryIdPointer &&7424 if (wanted_type->id == TypeTableEntryIdPointer &&
7379 wanted_type->data.pointer.is_const &&7425 wanted_type->data.pointer.is_const &&
...@@ -7674,6 +7720,13 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ...@@ -7674,6 +7720,13 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
7674 zig_unreachable();7720 zig_unreachable();
7675}7721}
76767722
7723static IrInstruction *ir_implicit_byval_const_ref_cast(IrAnalyze *ira, IrInstruction *inst) {
7724 if (type_is_copyable(ira->codegen, inst->value.type))
7725 return inst;
7726 TypeTableEntry *const_ref_type = get_pointer_to_type(ira->codegen, inst->value.type, true);
7727 return ir_implicit_cast(ira, inst, const_ref_type);
7728}
7729
7677static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {7730static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
7678 TypeTableEntry *type_entry = ptr->value.type;7731 TypeTableEntry *type_entry = ptr->value.type;
7679 if (type_is_invalid(type_entry)) {7732 if (type_is_invalid(type_entry)) {
...@@ -8816,7 +8869,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -8816,7 +8869,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
8816 IrInstruction *casted_arg;8869 IrInstruction *casted_arg;
8817 if (is_var_args) {8870 if (is_var_args) {
8818 arg_part_of_generic_id = true;8871 arg_part_of_generic_id = true;
8819 casted_arg = arg;8872 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
8820 } else {8873 } else {
8821 AstNode *param_type_node = param_decl_node->data.param_decl.type;8874 AstNode *param_type_node = param_decl_node->data.param_decl.type;
8822 TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);8875 TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);
...@@ -8826,7 +8879,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod...@@ -8826,7 +8879,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
8826 bool is_var_type = (param_type->id == TypeTableEntryIdVar);8879 bool is_var_type = (param_type->id == TypeTableEntryIdVar);
8827 if (is_var_type) {8880 if (is_var_type) {
8828 arg_part_of_generic_id = true;8881 arg_part_of_generic_id = true;
8829 casted_arg = arg;8882 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
8830 } else {8883 } else {
8831 casted_arg = ir_implicit_cast(ira, arg, param_type);8884 casted_arg = ir_implicit_cast(ira, arg, param_type);
8832 if (type_is_invalid(casted_arg->value.type))8885 if (type_is_invalid(casted_arg->value.type))
test/cases/cast.zig+21
...@@ -206,3 +206,24 @@ fn testResolveUndefWithInt(b: bool, x: i32) {...@@ -206,3 +206,24 @@ fn testResolveUndefWithInt(b: bool, x: i32) {
206 assert(value == x);206 assert(value == x);
207 }207 }
208}208}
209
210test "implicit cast from &const [N]T to []const T" {
211 testCastConstArrayRefToConstSlice();
212 comptime testCastConstArrayRefToConstSlice();
213}
214
215fn testCastConstArrayRefToConstSlice() {
216 const blah = "aoeu";
217 const const_array_ref = &blah;
218 assert(@typeOf(const_array_ref) == &const [4]u8);
219 const slice: []const u8 = const_array_ref;
220 assert(mem.eql(u8, slice, "aoeu"));
221}
222
223test "var args implicitly casts by value arg to const ref" {
224 foo("hello");
225}
226
227fn foo(args: ...) {
228 assert(@typeOf(args[0]) == &const [5]u8);
229}