@@ -5226,6 +5226,7 @@ const MacroCtx = struct {
5226
5226
loc : clang.SourceLocation ,
5227
5227
name : []const u8 ,
5228
5228
refs_var_decl : bool = false ,
5229
+ fn_params : ? []const ast.Payload.Param = null ,
5229
5230
5230
5231
fn peek (self : * MacroCtx ) ? CToken.Id {
5231
5232
if (self .i >= self .list .len ) return null ;
@@ -5298,6 +5299,15 @@ const MacroCtx = struct {
5298
5299
}
5299
5300
return null ;
5300
5301
}
5302
+
5303
+ fn checkFnParam (self : * MacroCtx , str : []const u8 ) bool {
5304
+ if (self .fn_params == null ) return false ;
5305
+
5306
+ for (self .fn_params .? ) | param | {
5307
+ if (mem .eql (u8 , param .name .? , str )) return true ;
5308
+ }
5309
+ return false ;
5310
+ }
5301
5311
};
5302
5312
5303
5313
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 {
5474
5484
defer fn_params .deinit ();
5475
5485
5476
5486
while (true ) {
5477
- switch (m .peek ().? ) {
5478
- .identifier , .extended_identifier = > _ = m .next (),
5479
- else = > break ,
5480
- }
5487
+ if (! m .peek ().? .isMacroIdentifier ()) break ;
5488
+
5489
+ _ = m .next ();
5481
5490
5482
5491
const mangled_name = try block_scope .makeMangledName (c , m .slice ());
5483
5492
try fn_params .append (.{
@@ -5490,6 +5499,8 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5490
5499
_ = m .next ();
5491
5500
}
5492
5501
5502
+ m .fn_params = fn_params .items ;
5503
+
5493
5504
try m .skip (c , .r_paren );
5494
5505
5495
5506
if (m .checkTranslatableMacro (scope , fn_params .items )) | err | switch (err ) {
@@ -5905,38 +5916,41 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5905
5916
.pp_num = > {
5906
5917
return parseCNumLit (c , m );
5907
5918
},
5908
- .identifier , .extended_identifier = > {
5909
- if (c .global_scope .blank_macros .contains (slice )) {
5910
- return parseCPrimaryExpr (c , m , scope );
5911
- }
5912
- const mangled_name = scope .getAlias (slice );
5913
- if (builtin_typedef_map .get (mangled_name )) | ty | return Tag .type .create (c .arena , ty );
5914
- const identifier = try Tag .identifier .create (c .arena , mangled_name );
5915
- scope .skipVariableDiscard (identifier .castTag (.identifier ).? .data );
5916
- refs_var : {
5917
- const ident_node = c .global_scope .sym_table .get (slice ) orelse break :refs_var ;
5918
- const var_decl_node = ident_node .castTag (.var_decl ) orelse break :refs_var ;
5919
- if (! var_decl_node .data .is_const ) m .refs_var_decl = true ;
5920
- }
5921
- return identifier ;
5922
- },
5923
5919
.l_paren = > {
5924
5920
const inner_node = try parseCExpr (c , m , scope );
5925
5921
5926
5922
try m .skip (c , .r_paren );
5927
5923
return inner_node ;
5928
5924
},
5929
- else = > {
5930
- // for handling type macros (EVIL)
5931
- // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
5932
- m .i -= 1 ;
5933
- if (try parseCTypeName (c , m , scope , true )) | type_name | {
5934
- return type_name ;
5935
- }
5936
- try m .fail (c , "unable to translate C expr: unexpected token '{s}'" , .{tok .symbol ()});
5937
- return error .ParseError ;
5938
- },
5925
+ else = > {},
5926
+ }
5927
+
5928
+ // The C preprocessor has no knowledge of C, so C keywords aren't special in macros.
5929
+ // Thus the current token should be treated like an identifier if its name matches a parameter.
5930
+ if (tok == .identifier or tok == .extended_identifier or m .checkFnParam (slice )) {
5931
+ if (c .global_scope .blank_macros .contains (slice )) {
5932
+ return parseCPrimaryExpr (c , m , scope );
5933
+ }
5934
+ const mangled_name = scope .getAlias (slice );
5935
+ if (builtin_typedef_map .get (mangled_name )) | ty | return Tag .type .create (c .arena , ty );
5936
+ const identifier = try Tag .identifier .create (c .arena , mangled_name );
5937
+ scope .skipVariableDiscard (identifier .castTag (.identifier ).? .data );
5938
+ refs_var : {
5939
+ const ident_node = c .global_scope .sym_table .get (slice ) orelse break :refs_var ;
5940
+ const var_decl_node = ident_node .castTag (.var_decl ) orelse break :refs_var ;
5941
+ if (! var_decl_node .data .is_const ) m .refs_var_decl = true ;
5942
+ }
5943
+ return identifier ;
5944
+ }
5945
+
5946
+ // for handling type macros (EVIL)
5947
+ // TODO maybe detect and treat type macros as typedefs in parseCSpecifierQualifierList?
5948
+ m .i -= 1 ;
5949
+ if (try parseCTypeName (c , m , scope , true )) | type_name | {
5950
+ return type_name ;
5939
5951
}
5952
+ try m .fail (c , "unable to translate C expr: unexpected token '{s}'" , .{tok .symbol ()});
5953
+ return error .ParseError ;
5940
5954
}
5941
5955
5942
5956
fn macroIntFromBool (c : * Context , node : Node ) ! Node {
@@ -6199,41 +6213,50 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
6199
6213
6200
6214
fn parseCSpecifierQualifierList (c : * Context , m : * MacroCtx , scope : * Scope , allow_fail : bool ) ParseError ! ? Node {
6201
6215
const tok = m .next ().? ;
6202
- switch (tok ) {
6203
- .identifier , .extended_identifier = > {
6204
- if (c .global_scope .blank_macros .contains (m .slice ())) {
6205
- return try parseCSpecifierQualifierList (c , m , scope , allow_fail );
6206
- }
6207
- const mangled_name = scope .getAlias (m .slice ());
6208
- if (! allow_fail or c .typedefs .contains (mangled_name )) {
6209
- if (builtin_typedef_map .get (mangled_name )) | ty | return try Tag .type .create (c .arena , ty );
6210
- return try Tag .identifier .create (c .arena , mangled_name );
6211
- }
6212
- },
6213
- .keyword_void = > return try Tag .type .create (c .arena , "anyopaque" ),
6214
- .keyword_bool = > return try Tag .type .create (c .arena , "bool" ),
6215
- .keyword_char ,
6216
- .keyword_int ,
6217
- .keyword_short ,
6218
- .keyword_long ,
6219
- .keyword_float ,
6220
- .keyword_double ,
6221
- .keyword_signed ,
6222
- .keyword_unsigned ,
6223
- .keyword_complex ,
6224
- = > {
6225
- m .i -= 1 ;
6226
- return try parseCNumericType (c , m );
6227
- },
6228
- .keyword_enum , .keyword_struct , .keyword_union = > {
6229
- // struct Foo will be declared as struct_Foo by transRecordDecl
6230
- const slice = m .slice ();
6231
- try m .skip (c , .identifier );
6216
+ const slice = m .slice ();
6217
+ const mangled_name = scope .getAlias (slice );
6218
+ if (! m .checkFnParam (mangled_name )) {
6219
+ switch (tok ) {
6220
+ .identifier , .extended_identifier = > {
6221
+ if (c .global_scope .blank_macros .contains (m .slice ())) {
6222
+ return try parseCSpecifierQualifierList (c , m , scope , allow_fail );
6223
+ }
6224
+ if (! allow_fail or c .typedefs .contains (mangled_name )) {
6225
+ if (builtin_typedef_map .get (mangled_name )) | ty | return try Tag .type .create (c .arena , ty );
6226
+ return try Tag .identifier .create (c .arena , mangled_name );
6227
+ }
6228
+ },
6229
+ .keyword_void = > return try Tag .type .create (c .arena , "anyopaque" ),
6230
+ .keyword_bool = > return try Tag .type .create (c .arena , "bool" ),
6231
+ .keyword_char ,
6232
+ .keyword_int ,
6233
+ .keyword_short ,
6234
+ .keyword_long ,
6235
+ .keyword_float ,
6236
+ .keyword_double ,
6237
+ .keyword_signed ,
6238
+ .keyword_unsigned ,
6239
+ .keyword_complex ,
6240
+ = > {
6241
+ m .i -= 1 ;
6242
+ return try parseCNumericType (c , m );
6243
+ },
6244
+ .keyword_enum , .keyword_struct , .keyword_union = > {
6245
+ // struct Foo will be declared as struct_Foo by transRecordDecl
6246
+ try m .skip (c , .identifier );
6232
6247
6233
- const name = try std .fmt .allocPrint (c .arena , "{s}_{s}" , .{ slice , m .slice () });
6234
- return try Tag .identifier .create (c .arena , name );
6235
- },
6236
- else = > {},
6248
+ const name = try std .fmt .allocPrint (c .arena , "{s}_{s}" , .{ slice , m .slice () });
6249
+ return try Tag .identifier .create (c .arena , name );
6250
+ },
6251
+ else = > {},
6252
+ }
6253
+ } else {
6254
+ if (allow_fail ) {
6255
+ m .i -= 1 ;
6256
+ return null ;
6257
+ } else {
6258
+ return try Tag .identifier .create (c .arena , mangled_name );
6259
+ }
6237
6260
}
6238
6261
6239
6262
if (allow_fail ) {
@@ -6511,7 +6534,7 @@ fn parseCPostfixExprInner(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?
6511
6534
}
6512
6535
6513
6536
fn parseCUnaryExpr (c : * Context , m : * MacroCtx , scope : * Scope ) ParseError ! Node {
6514
- switch (m .next ().? ) {
6537
+ sw : switch (m .next ().? ) {
6515
6538
.bang = > {
6516
6539
const operand = try macroIntToBool (c , try parseCCastExpr (c , m , scope ));
6517
6540
return Tag .not .create (c .arena , operand );
@@ -6534,6 +6557,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6534
6557
return Tag .address_of .create (c .arena , operand );
6535
6558
},
6536
6559
.keyword_sizeof = > {
6560
+ // 'sizeof' could be used as a parameter to a macro function.
6561
+ if (m .checkFnParam (m .slice ())) break :sw ;
6562
+
6537
6563
const operand = if (m .peek ().? == .l_paren ) blk : {
6538
6564
_ = m .next ();
6539
6565
const inner = (try parseCTypeName (c , m , scope , false )).? ;
@@ -6544,6 +6570,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6544
6570
return Tag .helpers_sizeof .create (c .arena , operand );
6545
6571
},
6546
6572
.keyword_alignof = > {
6573
+ // 'alignof' could be used as a parameter to a macro function.
6574
+ if (m .checkFnParam (m .slice ())) break :sw ;
6575
+
6547
6576
// TODO this won't work if using <stdalign.h>'s
6548
6577
// #define alignof _Alignof
6549
6578
try m .skip (c , .l_paren );
@@ -6556,11 +6585,11 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6556
6585
try m .fail (c , "TODO unary inc/dec expr" , .{});
6557
6586
return error .ParseError ;
6558
6587
},
6559
- else = > {
6560
- m .i -= 1 ;
6561
- return try parseCPostfixExpr (c , m , scope , null );
6562
- },
6588
+ else = > {},
6563
6589
}
6590
+
6591
+ m .i -= 1 ;
6592
+ return try parseCPostfixExpr (c , m , scope , null );
6564
6593
}
6565
6594
6566
6595
fn getContainer (c : * Context , node : Node ) ? Node {
0 commit comments