mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Make translate-c more robust in handling macro functions.
Translate-c didn't properly account for C macro functions having parameter names that are C keywords. So something like `#define FOO(float) ((float) + 10)` would've been interpreted as casting `+10` to a `float` type, instead of adding `10` to the parameter `float`. An example of a real-world macro function like this is SDL3's `SDL_DEFINE_AUDIO_FORMAT` from `SDL_audio.h`, which uses `signed` as a parameter.
This commit is contained in:
parent
f2f36c49c8
commit
fb1d4990cb
@ -5226,6 +5226,7 @@ const MacroCtx = struct {
|
||||
loc: clang.SourceLocation,
|
||||
name: []const u8,
|
||||
refs_var_decl: bool = false,
|
||||
fn_params: ?[]const ast.Payload.Param = null,
|
||||
|
||||
fn peek(self: *MacroCtx) ?CToken.Id {
|
||||
if (self.i >= self.list.len) return null;
|
||||
@ -5298,6 +5299,15 @@ const MacroCtx = struct {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn checkFnParam(self: *MacroCtx, str: []const u8) bool {
|
||||
if (self.fn_params == null) return false;
|
||||
|
||||
for (self.fn_params.?) |param| {
|
||||
if (mem.eql(u8, param.name.?, str)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 {
|
||||
@ -5474,10 +5484,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
defer fn_params.deinit();
|
||||
|
||||
while (true) {
|
||||
switch (m.peek().?) {
|
||||
.identifier, .extended_identifier => _ = m.next(),
|
||||
else => break,
|
||||
}
|
||||
if (!m.peek().?.isMacroIdentifier()) break;
|
||||
|
||||
_ = m.next();
|
||||
|
||||
const mangled_name = try block_scope.makeMangledName(c, m.slice());
|
||||
try fn_params.append(.{
|
||||
@ -5490,6 +5499,8 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
_ = m.next();
|
||||
}
|
||||
|
||||
m.fn_params = fn_params.items;
|
||||
|
||||
try m.skip(c, .r_paren);
|
||||
|
||||
if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {
|
||||
@ -5905,7 +5916,18 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
.pp_num => {
|
||||
return parseCNumLit(c, m);
|
||||
},
|
||||
.identifier, .extended_identifier => {
|
||||
.l_paren => {
|
||||
const inner_node = try parseCExpr(c, m, scope);
|
||||
|
||||
try m.skip(c, .r_paren);
|
||||
return inner_node;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
// The C preprocessor has no knowledge of C, so C keywords aren't special in macros.
|
||||
// Thus the current token should be treated like an identifier if its name matches a parameter.
|
||||
if (tok == .identifier or tok == .extended_identifier or m.checkFnParam(slice)) {
|
||||
if (c.global_scope.blank_macros.contains(slice)) {
|
||||
return parseCPrimaryExpr(c, m, scope);
|
||||
}
|
||||
@ -5919,14 +5941,8 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
if (!var_decl_node.data.is_const) m.refs_var_decl = true;
|
||||
}
|
||||
return identifier;
|
||||
},
|
||||
.l_paren => {
|
||||
const inner_node = try parseCExpr(c, m, scope);
|
||||
}
|
||||
|
||||
try m.skip(c, .r_paren);
|
||||
return inner_node;
|
||||
},
|
||||
else => {
|
||||
// for handling type macros (EVIL)
|
||||
// TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
|
||||
m.i -= 1;
|
||||
@ -5935,8 +5951,6 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
}
|
||||
try m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{tok.symbol()});
|
||||
return error.ParseError;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn macroIntFromBool(c: *Context, node: Node) !Node {
|
||||
@ -6199,12 +6213,14 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
|
||||
|
||||
fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
|
||||
const tok = m.next().?;
|
||||
const slice = m.slice();
|
||||
const mangled_name = scope.getAlias(slice);
|
||||
if (!m.checkFnParam(mangled_name)) {
|
||||
switch (tok) {
|
||||
.identifier, .extended_identifier => {
|
||||
if (c.global_scope.blank_macros.contains(m.slice())) {
|
||||
return try parseCSpecifierQualifierList(c, m, scope, allow_fail);
|
||||
}
|
||||
const mangled_name = scope.getAlias(m.slice());
|
||||
if (!allow_fail or c.typedefs.contains(mangled_name)) {
|
||||
if (builtin_typedef_map.get(mangled_name)) |ty| return try Tag.type.create(c.arena, ty);
|
||||
return try Tag.identifier.create(c.arena, mangled_name);
|
||||
@ -6227,7 +6243,6 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
|
||||
},
|
||||
.keyword_enum, .keyword_struct, .keyword_union => {
|
||||
// struct Foo will be declared as struct_Foo by transRecordDecl
|
||||
const slice = m.slice();
|
||||
try m.skip(c, .identifier);
|
||||
|
||||
const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
|
||||
@ -6235,6 +6250,14 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
} else {
|
||||
if (allow_fail) {
|
||||
m.i -= 1;
|
||||
return null;
|
||||
} else {
|
||||
return try Tag.identifier.create(c.arena, mangled_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (allow_fail) {
|
||||
m.i -= 1;
|
||||
@ -6511,7 +6534,7 @@ fn parseCPostfixExprInner(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?
|
||||
}
|
||||
|
||||
fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
switch (m.next().?) {
|
||||
sw: switch (m.next().?) {
|
||||
.bang => {
|
||||
const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
|
||||
return Tag.not.create(c.arena, operand);
|
||||
@ -6534,6 +6557,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
return Tag.address_of.create(c.arena, operand);
|
||||
},
|
||||
.keyword_sizeof => {
|
||||
// 'sizeof' could be used as a parameter to a macro function.
|
||||
if (m.checkFnParam(m.slice())) break :sw;
|
||||
|
||||
const operand = if (m.peek().? == .l_paren) blk: {
|
||||
_ = m.next();
|
||||
const inner = (try parseCTypeName(c, m, scope, false)).?;
|
||||
@ -6544,6 +6570,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
return Tag.helpers_sizeof.create(c.arena, operand);
|
||||
},
|
||||
.keyword_alignof => {
|
||||
// 'alignof' could be used as a parameter to a macro function.
|
||||
if (m.checkFnParam(m.slice())) break :sw;
|
||||
|
||||
// TODO this won't work if using <stdalign.h>'s
|
||||
// #define alignof _Alignof
|
||||
try m.skip(c, .l_paren);
|
||||
@ -6556,11 +6585,11 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
|
||||
try m.fail(c, "TODO unary inc/dec expr", .{});
|
||||
return error.ParseError;
|
||||
},
|
||||
else => {
|
||||
else => {},
|
||||
}
|
||||
|
||||
m.i -= 1;
|
||||
return try parseCPostfixExpr(c, m, scope, null);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn getContainer(c: *Context, node: Node) ?Node {
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
#define GUARDED_INT_ADDITION(int) ((int) + 1)
|
||||
|
||||
#define UNGUARDED_INT_SUBTRACTION(int) (int - 2)
|
||||
|
||||
#define GUARDED_INT_MULTIPLY(int) ((int) * 3)
|
||||
|
||||
#define UNGUARDED_INT_DIVIDE(int) (int / 4)
|
||||
|
||||
#define WRAPPED_RETURN(return) ((return) % 2)
|
||||
|
||||
#define UNWRAPPED_RETURN(return) (return ^ 0x7F)
|
||||
|
||||
#define WITH_TWO_PARAMETERS(signed, x) ((signed) + (x) + 9)
|
||||
|
||||
#define GUARDED_ALIGNOF(_Alignof) ((_Alignof) & 0x55)
|
||||
|
||||
#define UNGUARDED_ALIGNOF(_Alignof) (_Alignof | 0x80)
|
||||
|
||||
#define GUARDED_SIZEOF(sizeof) ((sizeof) == 64)
|
||||
|
||||
#define UNGUARDED_SIZEOF(sizeof) (sizeof < 64)
|
||||
|
||||
#define SIZEOF(x) ((int)sizeof(x))
|
||||
|
||||
#define SIZEOF2(x) ((int)sizeof x)
|
||||
|
||||
// translate-c
|
||||
// c_frontend=clang
|
||||
//
|
||||
// pub inline fn GUARDED_INT_ADDITION(int: anytype) @TypeOf(int + @as(c_int, 1)) {
|
||||
// _ = ∫
|
||||
// return int + @as(c_int, 1);
|
||||
// }
|
||||
// pub inline fn UNGUARDED_INT_SUBTRACTION(int: anytype) @TypeOf(int - @as(c_int, 2)) {
|
||||
// _ = ∫
|
||||
// return int - @as(c_int, 2);
|
||||
// }
|
||||
// pub inline fn GUARDED_INT_MULTIPLY(int: anytype) @TypeOf(int * @as(c_int, 3)) {
|
||||
// _ = ∫
|
||||
// return int * @as(c_int, 3);
|
||||
// }
|
||||
// pub inline fn UNGUARDED_INT_DIVIDE(int: anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4))) {
|
||||
// _ = ∫
|
||||
// return @import("std").zig.c_translation.MacroArithmetic.div(int, @as(c_int, 4));
|
||||
// }
|
||||
// pub inline fn WRAPPED_RETURN(@"return": anytype) @TypeOf(@import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2))) {
|
||||
// _ = &@"return";
|
||||
// return @import("std").zig.c_translation.MacroArithmetic.rem(@"return", @as(c_int, 2));
|
||||
// }
|
||||
// pub inline fn UNWRAPPED_RETURN(@"return": anytype) @TypeOf(@"return" ^ @as(c_int, 0x7F)) {
|
||||
// _ = &@"return";
|
||||
// return @"return" ^ @as(c_int, 0x7F);
|
||||
// }
|
||||
// pub inline fn WITH_TWO_PARAMETERS(signed: anytype, x: anytype) @TypeOf((signed + x) + @as(c_int, 9)) {
|
||||
// _ = &signed;
|
||||
// _ = &x;
|
||||
// return (signed + x) + @as(c_int, 9);
|
||||
// }
|
||||
// pub inline fn GUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof & @as(c_int, 0x55)) {
|
||||
// _ = &_Alignof;
|
||||
// return _Alignof & @as(c_int, 0x55);
|
||||
// }
|
||||
// pub inline fn UNGUARDED_ALIGNOF(_Alignof: anytype) @TypeOf(_Alignof | @as(c_int, 0x80)) {
|
||||
// _ = &_Alignof;
|
||||
// return _Alignof | @as(c_int, 0x80);
|
||||
// }
|
||||
// pub inline fn GUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof == @as(c_int, 64)) {
|
||||
// _ = &sizeof;
|
||||
// return sizeof == @as(c_int, 64);
|
||||
// }
|
||||
// pub inline fn UNGUARDED_SIZEOF(sizeof: anytype) @TypeOf(sizeof < @as(c_int, 64)) {
|
||||
// _ = &sizeof;
|
||||
// return sizeof < @as(c_int, 64);
|
||||
// }
|
||||
// pub inline fn SIZEOF(x: anytype) c_int {
|
||||
// _ = &x;
|
||||
// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x));
|
||||
// }
|
||||
// pub inline fn SIZEOF2(x: anytype) c_int {
|
||||
// _ = &x;
|
||||
// return @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(x));
|
||||
// }
|
||||
Loading…
x
Reference in New Issue
Block a user