authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-13 12:34:42-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-13 12:34:42-04:00
log5354d1f5fc496beb8313488ea1690e02e9c630fa
tree4b46b803efbc09944d2a0cb47904b452ea666fbd
parentac096c294976b7cb6433a7939adcd664af770201

allow == for comparing optional pointers

closes #658

3 files changed, 35 insertions(+), 20 deletions(-)

src/codegen.cpp+1-3
...@@ -2249,10 +2249,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2249,10 +2249,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2249 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2249 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2250 } else if (type_entry->id == TypeTableEntryIdEnum ||2250 } else if (type_entry->id == TypeTableEntryIdEnum ||
2251 type_entry->id == TypeTableEntryIdErrorSet ||2251 type_entry->id == TypeTableEntryIdErrorSet ||
2252 type_entry->id == TypeTableEntryIdPointer ||
2253 type_entry->id == TypeTableEntryIdBool ||2252 type_entry->id == TypeTableEntryIdBool ||
2254 type_entry->id == TypeTableEntryIdPromise ||2253 get_codegen_ptr_type(type_entry) != nullptr)
2255 type_entry->id == TypeTableEntryIdFn)
2256 {2254 {
2257 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);2255 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2258 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2256 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
src/ir.cpp+13-17
...@@ -11147,7 +11147,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11147,7 +11147,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11147 if (type_is_invalid(resolved_type))11147 if (type_is_invalid(resolved_type))
11148 return resolved_type;11148 return resolved_type;
1114911149
1115011150 bool operator_allowed;
11151 switch (resolved_type->id) {11151 switch (resolved_type->id) {
11152 case TypeTableEntryIdInvalid:11152 case TypeTableEntryIdInvalid:
11153 zig_unreachable(); // handled above11153 zig_unreachable(); // handled above
...@@ -11156,6 +11156,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11156,6 +11156,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11156 case TypeTableEntryIdComptimeInt:11156 case TypeTableEntryIdComptimeInt:
11157 case TypeTableEntryIdInt:11157 case TypeTableEntryIdInt:
11158 case TypeTableEntryIdFloat:11158 case TypeTableEntryIdFloat:
11159 operator_allowed = true;
11159 break;11160 break;
1116011161
11161 case TypeTableEntryIdBool:11162 case TypeTableEntryIdBool:
...@@ -11170,19 +11171,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11170,19 +11171,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11170 case TypeTableEntryIdBoundFn:11171 case TypeTableEntryIdBoundFn:
11171 case TypeTableEntryIdArgTuple:11172 case TypeTableEntryIdArgTuple:
11172 case TypeTableEntryIdPromise:11173 case TypeTableEntryIdPromise:
11173 if (!is_equality_cmp) {
11174 ir_add_error_node(ira, source_node,
11175 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
11176 return ira->codegen->builtin_types.entry_invalid;
11177 }
11178 break;
11179
11180 case TypeTableEntryIdEnum:11174 case TypeTableEntryIdEnum:
11181 if (!is_equality_cmp) {11175 operator_allowed = is_equality_cmp;
11182 ir_add_error_node(ira, source_node,
11183 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
11184 return ira->codegen->builtin_types.entry_invalid;
11185 }
11186 break;11176 break;
1118711177
11188 case TypeTableEntryIdUnreachable:11178 case TypeTableEntryIdUnreachable:
...@@ -11190,12 +11180,18 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11190,12 +11180,18 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11190 case TypeTableEntryIdStruct:11180 case TypeTableEntryIdStruct:
11191 case TypeTableEntryIdUndefined:11181 case TypeTableEntryIdUndefined:
11192 case TypeTableEntryIdNull:11182 case TypeTableEntryIdNull:
11193 case TypeTableEntryIdOptional:
11194 case TypeTableEntryIdErrorUnion:11183 case TypeTableEntryIdErrorUnion:
11195 case TypeTableEntryIdUnion:11184 case TypeTableEntryIdUnion:
11196 ir_add_error_node(ira, source_node,11185 operator_allowed = false;
11197 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));11186 break;
11198 return ira->codegen->builtin_types.entry_invalid;11187 case TypeTableEntryIdOptional:
11188 operator_allowed = is_equality_cmp && get_codegen_ptr_type(resolved_type) != nullptr;
11189 break;
11190 }
11191 if (!operator_allowed) {
11192 ir_add_error_node(ira, source_node,
11193 buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
11194 return ira->codegen->builtin_types.entry_invalid;
11199 }11195 }
1120011196
11201 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, resolved_type);11197 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, resolved_type);
test/cases/optional.zig+21
...@@ -7,3 +7,24 @@ test "optional pointer to size zero struct" {...@@ -7,3 +7,24 @@ test "optional pointer to size zero struct" {
7 var o: ?*EmptyStruct = &e;7 var o: ?*EmptyStruct = &e;
8 assert(o != null);8 assert(o != null);
9}9}
10
11test "equality compare nullable pointers" {
12 testNullPtrsEql();
13 comptime testNullPtrsEql();
14}
15
16fn testNullPtrsEql() void {
17 var number: i32 = 1234;
18
19 var x: ?*i32 = null;
20 var y: ?*i32 = null;
21 assert(x == y);
22 y = &number;
23 assert(x != y);
24 assert(x != &number);
25 assert(&number != x);
26 x = &number;
27 assert(x == y);
28 assert(x == &number);
29 assert(&number == x);
30}