| ... | ... | @@ -5524,22 +5524,38 @@ const MacroCtx = struct { |
| 5524 | 5524 | return MacroSlicer{ .source = self.source, .tokens = self.list }; |
| 5525 | 5525 | } |
| 5526 | 5526 | |
| 5527 | | fn containsUndefinedIdentifier(self: *MacroCtx, scope: *Scope, params: []const ast.Payload.Param) ?[]const u8 { |
| 5527 | const MacroTranslateError = union(enum) { |
| 5528 | undefined_identifier: []const u8, |
| 5529 | invalid_arg_usage: []const u8, |
| 5530 | }; |
| 5531 | |
| 5532 | fn checkTranslatableMacro(self: *MacroCtx, scope: *Scope, params: []const ast.Payload.Param) ?MacroTranslateError { |
| 5528 | 5533 | const slicer = self.makeSlicer(); |
| 5534 | var last_is_type_kw = false; |
| 5529 | 5535 | var i: usize = 1; // index 0 is the macro name |
| 5530 | 5536 | while (i < self.list.len) : (i += 1) { |
| 5531 | 5537 | const token = self.list[i]; |
| 5532 | 5538 | switch (token.id) { |
| 5533 | 5539 | .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown |
| 5540 | .Keyword_struct, .Keyword_union, .Keyword_enum => if (!last_is_type_kw) { |
| 5541 | last_is_type_kw = true; |
| 5542 | continue; |
| 5543 | }, |
| 5534 | 5544 | .Identifier => { |
| 5535 | 5545 | const identifier = slicer.slice(token); |
| 5536 | 5546 | const is_param = for (params) |param| { |
| 5537 | 5547 | if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true; |
| 5538 | 5548 | } else false; |
| 5539 | | if (!scope.contains(identifier) and !isBuiltinDefined(identifier) and !is_param) return identifier; |
| 5549 | if (is_param and last_is_type_kw) { |
| 5550 | return .{ .invalid_arg_usage = identifier }; |
| 5551 | } |
| 5552 | if (!scope.contains(identifier) and !isBuiltinDefined(identifier) and !is_param) { |
| 5553 | return .{ .undefined_identifier = identifier }; |
| 5554 | } |
| 5540 | 5555 | }, |
| 5541 | 5556 | else => {}, |
| 5542 | 5557 | } |
| 5558 | last_is_type_kw = false; |
| 5543 | 5559 | } |
| 5544 | 5560 | return null; |
| 5545 | 5561 | } |
| ... | ... | @@ -5649,8 +5665,10 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5649 | 5665 | fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5650 | 5666 | const scope = &c.global_scope.base; |
| 5651 | 5667 | |
| 5652 | | if (m.containsUndefinedIdentifier(scope, &.{})) |ident| |
| 5653 | | return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}); |
| 5668 | if (m.checkTranslatableMacro(scope, &.{})) |err| switch (err) { |
| 5669 | .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}), |
| 5670 | .invalid_arg_usage => unreachable, // no args |
| 5671 | }; |
| 5654 | 5672 | |
| 5655 | 5673 | const init_node = try parseCExpr(c, m, scope); |
| 5656 | 5674 | const last = m.next().?; |
| ... | ... | @@ -5698,8 +5716,10 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5698 | 5716 | |
| 5699 | 5717 | try m.skip(c, .RParen); |
| 5700 | 5718 | |
| 5701 | | if (m.containsUndefinedIdentifier(scope, fn_params.items)) |ident| |
| 5702 | | return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}); |
| 5719 | if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) { |
| 5720 | .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}), |
| 5721 | .invalid_arg_usage => |ident| return m.fail(c, "unable to translate macro: untranslatable usage of arg `{s}`", .{ident}), |
| 5722 | }; |
| 5703 | 5723 | |
| 5704 | 5724 | const expr = try parseCExpr(c, m, scope); |
| 5705 | 5725 | const last = m.next().?; |