Commit 8696e52a3d

Robin Voetter <robin@voetter.nl>
2020-06-21 20:55:44
Make unary minus for unsigned types a compile error (#5654)
* Make unary minus for unsigned types a compile error * Add unreachable when generating unsigned negate
1 parent 126f570
Changed files (3)
src/codegen.cpp
@@ -3540,7 +3540,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutableGen *executabl
 
         for (size_t field_i = 0; field_i < field_count; field_i += 1) {
             TypeEnumField *type_enum_field = &wanted_type->data.enumeration.fields[field_i];
-            
+
             Buf *name = type_enum_field->name;
             auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
             if (entry != nullptr) {
@@ -3654,7 +3654,7 @@ static LLVMValueRef ir_gen_negation(CodeGen *g, IrInstGen *inst, IrInstGen *oper
         } else if (scalar_type->data.integral.is_signed) {
             return LLVMBuildNSWNeg(g->builder, llvm_operand, "");
         } else {
-            return LLVMBuildNUWNeg(g->builder, llvm_operand, "");
+            zig_unreachable();
         }
     } else {
         zig_unreachable();
@@ -3984,7 +3984,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutableGen *executable,
             assert(array_type->data.pointer.child_type->id == ZigTypeIdArray);
             array_type = array_type->data.pointer.child_type;
         }
-        
+
         assert(array_type->data.array.len != 0 || array_type->data.array.sentinel != nullptr);
 
         if (safety_check_on) {
@@ -5258,7 +5258,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
 
     for (size_t field_i = 0; field_i < field_count; field_i += 1) {
         TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
-        
+
         Buf *name = type_enum_field->name;
         auto entry = occupied_tag_values.put_unique(type_enum_field->value, name);
         if (entry != nullptr) {
@@ -5471,7 +5471,7 @@ static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
         }
         auto bit_count = operand_type->data.integral.bit_count;
         bool is_signed = operand_type->data.integral.is_signed;
-        
+
         ir_assert(bit_count != 0, instruction);
         if (bit_count == 1 || !is_power_of_2(bit_count)) {
             return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8));
@@ -9265,7 +9265,7 @@ static void init(CodeGen *g) {
             abi_name = (g->zig_target->arch == ZigLLVM_riscv32) ? "ilp32" : "lp64";
         }
     }
-    
+
     g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str),
             target_specific_cpu_args, target_specific_features, opt_level, reloc_mode,
             to_llvm_code_model(g), g->function_sections, float_abi, abi_name);
src/ir.cpp
@@ -12602,28 +12602,28 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
         if (prev_type->id == ZigTypeIdPointer &&
             prev_type->data.pointer.ptr_len == PtrLenSingle &&
             prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
-            ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown))) 
+            ((cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenUnknown)))
         {
-            prev_inst = cur_inst;   
+            prev_inst = cur_inst;
 
             if (prev_type->data.pointer.is_const && !cur_type->data.pointer.is_const) {
                 // const array pointer and non-const unknown pointer
                 make_the_pointer_const = true;
             }
-            continue; 
+            continue;
         }
 
         // *[N]T to [*]T
         if (cur_type->id == ZigTypeIdPointer &&
             cur_type->data.pointer.ptr_len == PtrLenSingle &&
             cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
-            ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown))) 
+            ((prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenUnknown)))
         {
             if (cur_type->data.pointer.is_const && !prev_type->data.pointer.is_const) {
                 // const array pointer and non-const unknown pointer
                 make_the_pointer_const = true;
             }
-            continue;   
+            continue;
         }
 
         // *[N]T to []T
@@ -20987,17 +20987,24 @@ static IrInstGen *ir_analyze_negation(IrAnalyze *ira, IrInstSrcUnOp *instruction
     if (type_is_invalid(expr_type))
         return ira->codegen->invalid_inst_gen;
 
-    if (!(expr_type->id == ZigTypeIdInt || expr_type->id == ZigTypeIdComptimeInt ||
-        expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat ||
-        expr_type->id == ZigTypeIdVector))
-    {
-        ir_add_error(ira, &instruction->base.base,
-            buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name)));
-        return ira->codegen->invalid_inst_gen;
-    }
-
     bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap);
 
+    switch (expr_type->id) {
+        case ZigTypeIdComptimeInt:
+        case ZigTypeIdFloat:
+        case ZigTypeIdComptimeFloat:
+        case ZigTypeIdVector:
+            break;
+        case ZigTypeIdInt:
+            if (is_wrap_op || expr_type->data.integral.is_signed)
+                break;
+            ZIG_FALLTHROUGH;
+        default:
+            ir_add_error(ira, &instruction->base.base,
+                buf_sprintf("negation of type '%s'", buf_ptr(&expr_type->name)));
+            return ira->codegen->invalid_inst_gen;
+    }
+
     ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
 
     if (instr_is_comptime(value)) {
@@ -30380,7 +30387,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, IrInst* source_instr, BuiltinF
         case BuiltinFnIdTrunc:
             f128M_trunc(in, out);
             break;
-        case BuiltinFnIdRound: 
+        case BuiltinFnIdRound:
             f128M_roundToInt(in, softfloat_round_near_maxMag, false, out);
             break;
         case BuiltinFnIdNearbyInt:
test/compile_errors.zig
@@ -7530,4 +7530,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
     , &[_][]const u8{
         "tmp.zig:2:9: error: @wasmMemoryGrow is a wasm32 feature only",
     });
+
+    cases.add("Issue #5586: Make unary minus for unsigned types a compile error",
+        \\export fn f(x: u32) u32 {
+        \\    const y = -%x;
+        \\    return -y;
+        \\}
+    , &[_][]const u8{
+        "tmp.zig:3:12: error: negation of type 'u32'"
+    });
 }