From fb50ae9e71003bf4a7445267fdc92036d1016637 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Tue, 31 Aug 2021 10:30:36 -0700 Subject: [PATCH] translate-c: emit compileError for undefined identifiers in macros --- src/translate_c.zig | 20 ++++++++++++++++++++ test/translate_c.zig | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/translate_c.zig b/src/translate_c.zig index 6b7165176b68..0f13d4176fa3 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -5248,6 +5248,23 @@ const MacroCtx = struct { fn makeSlicer(self: *const MacroCtx) MacroSlicer { return MacroSlicer{ .source = self.source, .tokens = self.list }; } + + fn containsUndefinedIdentifier(self: *MacroCtx, scope: *Scope) ?[]const u8 { + const slicer = self.makeSlicer(); + var i: usize = 1; // index 0 is the macro name + while (i < self.list.len) : (i += 1) { + const token = self.list[i]; + switch (token.id) { + .Period => i += 1, // skip next token since field identifiers can be unknown + .Identifier => { + const identifier = slicer.slice(token); + if (!scope.contains(identifier)) return identifier; + }, + else => {}, + } + } + return null; + } }; fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void { @@ -5344,6 +5361,9 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { const scope = &c.global_scope.base; + if (m.containsUndefinedIdentifier(scope)) |ident| + return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}); + const init_node = try parseCExpr(c, m, scope); const last = m.next().?; if (last != .Eof and last != .Nl) diff --git a/test/translate_c.zig b/test/translate_c.zig index 70ff464c8aa4..8286843d8730 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -228,6 +228,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add("macro expressions respect C operator precedence", + \\int *foo = 0; \\#define FOO *((foo) + 2) \\#define VALUE (1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9) \\#define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \ @@ -459,6 +460,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add("macro line continuation", + \\int BAR = 0; \\#define FOO -\ \\BAR , &[_][]const u8{ @@ -1833,6 +1835,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add("macro pointer cast", + \\#define NRF_GPIO_BASE 0 \\typedef struct { int dummy; } NRF_GPIO_Type; \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) , &[_][]const u8{ @@ -1873,6 +1876,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add("macro add", + \\#define D3_AHB1PERIPH_BASE 0 \\#define PERIPH_BASE (0x40000000UL) /*!< Base address of : AHB/APB Peripherals */ \\#define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000UL) \\#define RCC_BASE (D3_AHB1PERIPH_BASE + 0x4400UL) @@ -3138,6 +3142,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define FOO(bar) baz((void *)(baz)) \\#define BAR (void*) a \\#define BAZ (uint32_t)(2) + \\#define a 2 , &[_][]const u8{ \\pub inline fn FOO(bar: anytype) @TypeOf(baz(@import("std").zig.c_translation.cast(?*c_void, baz))) { \\ _ = bar; @@ -3160,6 +3165,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); cases.add("macro conditional operator", + \\ int a, b, c; \\#define FOO a ? b : c , &[_][]const u8{ \\pub const FOO = if (a) b else c; @@ -3649,4 +3655,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\_ = p[@intCast(c_uint, @as(c_int, 1))]; }); + + cases.add("Undefined macro identifier", + \\#define FOO BAR + , &[_][]const u8{ + \\pub const FOO = @compileError("unable to translate macro: undefined identifier `BAR`"); + }); }