From 6b5ac4fe191a277b3f6c129e75e62c25e70ed017 Mon Sep 17 00:00:00 2001
From: motiejus <foo@bar>
Date: Fri, 8 Nov 2024 19:12:33 +0200
Subject: [PATCH] 0.10.0-1638-g7199d7c777: re-add @qualCast

---
 src/AstGen.zig    |  2 ++
 src/BuiltinFn.zig |  8 ++++++++
 src/Sema.zig      | 44 ++++++++++++++++++++++++++++++++++++++++++++
 src/Zir.zig       |  6 ++++++
 src/print_zir.zig |  1 +
 5 files changed, 61 insertions(+)

diff --git a/src/AstGen.zig b/src/AstGen.zig
index 40eef32d4e..f04713fab5 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -2531,6 +2531,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
             .bit_size_of,
             .typeof_log2_int_type,
             .ptr_to_int,
+            .qual_cast,
             .align_of,
             .bool_to_int,
             .embed_file,
@@ -8038,6 +8039,7 @@ fn builtinCall(
         .float_cast   => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),
         .int_cast     => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),
         .ptr_cast     => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast),
+        .qual_cast    => return typeCast(gz, scope, ri, node, params[0], params[1], .qual_cast),
         .truncate     => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
         // zig fmt: on
 
diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig
index 20edbabe47..78d492a99b 100644
--- a/src/BuiltinFn.zig
+++ b/src/BuiltinFn.zig
@@ -76,6 +76,7 @@ pub const Tag = enum {
     prefetch,
     ptr_cast,
     ptr_to_int,
+    qual_cast,
     rem,
     return_address,
     select,
@@ -683,6 +684,13 @@ pub const list = list: {
                 .param_count = 1,
             },
         },
+        .{
+            "@qualCast",
+            .{
+                .tag = .qual_cast,
+                .param_count = 2,
+            },
+        },
         .{
             "@rem",
             .{
diff --git a/src/Sema.zig b/src/Sema.zig
index cf6350e35f..f76c5bd3c4 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1015,6 +1015,7 @@ fn analyzeBodyInner(
             .float_cast                   => try sema.zirFloatCast(block, inst),
             .int_cast                     => try sema.zirIntCast(block, inst),
             .ptr_cast                     => try sema.zirPtrCast(block, inst),
+            .qual_cast                    => try sema.zirQualCast(block, inst),
             .truncate                     => try sema.zirTruncate(block, inst),
             .align_cast                   => try sema.zirAlignCast(block, inst),
             .has_decl                     => try sema.zirHasDecl(block, inst),
@@ -19661,6 +19662,49 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
     return block.addBitCast(aligned_dest_ty, ptr);
 }
 
+fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+    const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+    const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+    const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
+    const operand = try sema.resolveInst(extra.rhs);
+    const operand_ty = sema.typeOf(operand);
+
+    try sema.checkPtrType(block, dest_ty_src, dest_ty);
+    try sema.checkPtrOperand(block, operand_src, operand_ty);
+
+    var operand_payload = operand_ty.ptrInfo();
+    var dest_info = dest_ty.ptrInfo();
+
+    operand_payload.data.mutable = dest_info.data.mutable;
+    operand_payload.data.@"volatile" = dest_info.data.@"volatile";
+
+    const altered_operand_ty = Type.initPayload(&operand_payload.base);
+    if (!altered_operand_ty.eql(dest_ty, sema.mod)) {
+        const msg = msg: {
+            const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{});
+            errdefer msg.destroy(sema.gpa);
+
+            dest_info.data.mutable = !operand_ty.isConstPtr();
+            dest_info.data.@"volatile" = operand_ty.isVolatilePtr();
+            const altered_dest_ty = Type.initPayload(&dest_info.base);
+            try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)});
+            try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)});
+            break :msg msg;
+        };
+        return sema.failWithOwnedErrorMsg(msg);
+    }
+
+    if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
+        return sema.addConstant(dest_ty, operand_val);
+    }
+
+    try sema.requireRuntimeBlock(block, src, null);
+    return block.addBitCast(dest_ty, operand);
+}
+
 fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
     const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
     const src = LazySrcLoc.nodeOffset(extra.node);
diff --git a/src/Zir.zig b/src/Zir.zig
index 58f9fdff14..338712c0b7 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -857,6 +857,9 @@ pub const Inst = struct {
         /// Implements the `@ptrCast` builtin.
         /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
         ptr_cast,
+        /// Implements the `@qualCast` builtin.
+        /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
+        qual_cast,
         /// Implements the `@truncate` builtin.
         /// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
         truncate,
@@ -1195,6 +1198,7 @@ pub const Inst = struct {
                 .float_cast,
                 .int_cast,
                 .ptr_cast,
+                .qual_cast,
                 .truncate,
                 .align_cast,
                 .has_field,
@@ -1484,6 +1488,7 @@ pub const Inst = struct {
                 .float_cast,
                 .int_cast,
                 .ptr_cast,
+                .qual_cast,
                 .truncate,
                 .align_cast,
                 .has_field,
@@ -1755,6 +1760,7 @@ pub const Inst = struct {
                 .float_cast = .pl_node,
                 .int_cast = .pl_node,
                 .ptr_cast = .pl_node,
+                .qual_cast = .pl_node,
                 .truncate = .pl_node,
                 .align_cast = .pl_node,
                 .typeof_builtin = .pl_node,
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 8d97000582..c2485a8cb4 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -332,6 +332,7 @@ const Writer = struct {
             .float_cast,
             .int_cast,
             .ptr_cast,
+            .qual_cast,
             .truncate,
             .align_cast,
             .div_exact,
-- 
2.44.1

