Commit 1912ec0323

Andrew Kelley <andrew@ziglang.org>
2021-12-02 00:24:44
AstGen: use null string to communicate non-string-literal asm
dd62a6d2e8de522187fd096354e7156cca1821c5 short-circuited the logic of `asmExpr` by emitting ZIR for `@compileError("...")`. This caused false positive "unreachable code" errors for stage1 when there was an expression in the asm template. This commit makes such cases instead go through logic of `asmExpr` like normal, however the asm template is set to 0. This is then picked up in Sema (part of stage2, not stage1) and reported as "assembly code must use string literal syntax".
1 parent 0714832
Changed files (2)
src/AstGen.zig
@@ -6422,52 +6422,17 @@ fn asmExpr(
     const asm_source = switch (node_tags[full.ast.template]) {
         .string_literal => try astgen.strLitAsString(main_tokens[full.ast.template]),
         .multiline_string_literal => try astgen.strLitNodeAsString(full.ast.template),
-        else => {
+        else => blk: {
             // stage1 allows this, and until we do another design iteration on inline assembly
             // in stage2 to improve support for the various needed use cases, we allow inline
             // assembly templates to be an expression. Once stage2 addresses the real world needs
             // of people using inline assembly (primarily OS developers) then we can re-institute
             // the rule into AstGen that assembly code must use string literal syntax.
             //return astgen.failNode(full.ast.template, "assembly code must use string literal syntax", .{}),
-
-            // This code emits ZIR for
-            // `@compileError("assembly code must use string literal syntax")`
-            // which allows it to make it to stage1 but gives the error for stage2.
-            const string_bytes = &astgen.string_bytes;
-            const str_index = @intCast(u32, string_bytes.items.len);
-            try string_bytes.appendSlice(astgen.gpa, "assembly code must use string literal syntax");
-            const key = string_bytes.items[str_index..];
-            const gop = try astgen.string_table.getOrPutContextAdapted(astgen.gpa, @as([]const u8, key), StringIndexAdapter{
-                .bytes = string_bytes,
-            }, StringIndexContext{
-                .bytes = string_bytes,
-            });
-            const str = if (gop.found_existing) str: {
-                string_bytes.shrinkRetainingCapacity(str_index);
-                break :str IndexSlice{
-                    .index = gop.key_ptr.*,
-                    .len = @intCast(u32, key.len),
-                };
-            } else str: {
-                gop.key_ptr.* = str_index;
-                // Still need a null byte because we are using the same table
-                // to lookup null terminated strings, so if we get a match, it has to
-                // be null terminated for that to work.
-                try string_bytes.append(astgen.gpa, 0);
-                break :str IndexSlice{
-                    .index = str_index,
-                    .len = @intCast(u32, key.len),
-                };
-            };
-            const msg = try gz.add(.{
-                .tag = .str,
-                .data = .{ .str = .{
-                    .start = str.index,
-                    .len = str.len,
-                } },
-            });
-            const result = try gz.addUnNode(.compile_error, msg, node);
-            return rvalue(gz, rl, result, node);
+            // We still need to trigger all the expr() calls here to avoid errors for unused things.
+            // So we pass 0 as the asm source and stage2 Sema will notice this and
+            // report the error.
+            break :blk IndexSlice{ .index = 0, .len = 0 };
         },
     };
 
src/Sema.zig
@@ -8226,6 +8226,12 @@ fn zirAsm(
     const inputs_len = @truncate(u5, extended.small >> 5);
     const clobbers_len = @truncate(u5, extended.small >> 10);
 
+    if (extra.data.asm_source == 0) {
+        // This can move to become an AstGen error after inline assembly improvements land
+        // and stage1 code matches stage2 code.
+        return sema.fail(block, src, "assembly code must use string literal syntax", .{});
+    }
+
     if (outputs_len > 1) {
         return sema.fail(block, src, "TODO implement Sema for asm with more than 1 output", .{});
     }