mirror of
https://github.com/ziglang/zig.git
synced 2024-11-23 12:50:13 +00:00
translate-c: improve handling of undefined identifiers
This commit is contained in:
parent
8d2acff197
commit
df589eecd6
@ -395,7 +395,15 @@ pub fn translate(
|
||||
context.pattern_list.deinit(gpa);
|
||||
}
|
||||
|
||||
try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init());
|
||||
inline for (meta.declarations(std.zig.c_builtins)) |decl| {
|
||||
if (decl.is_pub) {
|
||||
const builtin = try Tag.pub_var_simple.create(context.arena, .{
|
||||
.name = decl.name,
|
||||
.init = try Tag.import_builtin.create(context.arena, decl.name),
|
||||
});
|
||||
try context.global_scope.nodes.append(builtin);
|
||||
}
|
||||
}
|
||||
|
||||
try prepopulateGlobalNameTable(ast_unit, &context);
|
||||
|
||||
@ -5249,16 +5257,19 @@ const MacroCtx = struct {
|
||||
return MacroSlicer{ .source = self.source, .tokens = self.list };
|
||||
}
|
||||
|
||||
fn containsUndefinedIdentifier(self: *MacroCtx, scope: *Scope) ?[]const u8 {
|
||||
fn containsUndefinedIdentifier(self: *MacroCtx, scope: *Scope, params: []const ast.Payload.Param) ?[]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
|
||||
.Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown
|
||||
.Identifier => {
|
||||
const identifier = slicer.slice(token);
|
||||
if (!scope.contains(identifier)) return identifier;
|
||||
const is_param = for (params) |param| {
|
||||
if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;
|
||||
} else false;
|
||||
if (!scope.contains(identifier) and !isBuiltinDefined(identifier) and !is_param) return identifier;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -5361,7 +5372,7 @@ 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|
|
||||
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);
|
||||
@ -5414,6 +5425,9 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
return m.fail(c, "unable to translate C expr: expected ')'", .{});
|
||||
}
|
||||
|
||||
if (m.containsUndefinedIdentifier(scope, fn_params.items)) |ident|
|
||||
return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident});
|
||||
|
||||
const expr = try parseCExpr(c, m, scope);
|
||||
const last = m.next().?;
|
||||
if (last != .Eof and last != .Nl)
|
||||
@ -5755,10 +5769,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
|
||||
},
|
||||
.Identifier => {
|
||||
const mangled_name = scope.getAlias(slice);
|
||||
if (mem.startsWith(u8, mangled_name, "__builtin_") and !isBuiltinDefined(mangled_name)) {
|
||||
try m.fail(c, "TODO implement function '{s}' in std.zig.c_builtins", .{mangled_name});
|
||||
return error.ParseError;
|
||||
}
|
||||
if (builtin_typedef_map.get(mangled_name)) |ty| return Tag.type.create(c.arena, ty);
|
||||
const identifier = try Tag.identifier.create(c.arena, mangled_name);
|
||||
scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
|
||||
|
@ -31,8 +31,6 @@ pub const Node = extern union {
|
||||
@"anytype",
|
||||
@"continue",
|
||||
@"break",
|
||||
/// pub usingnamespace @import("std").zig.c_builtins
|
||||
usingnamespace_builtins,
|
||||
// After this, the tag requires a payload.
|
||||
|
||||
integer_literal,
|
||||
@ -119,6 +117,8 @@ pub const Node = extern union {
|
||||
ellipsis3,
|
||||
assign,
|
||||
|
||||
/// @import("std").zig.c_builtins.<name>
|
||||
import_builtin,
|
||||
log2_int_type,
|
||||
/// @import("std").math.Log2Int(operand)
|
||||
std_math_Log2Int,
|
||||
@ -224,7 +224,7 @@ pub const Node = extern union {
|
||||
/// [1]type{val} ** count
|
||||
array_filler,
|
||||
|
||||
pub const last_no_payload_tag = Tag.usingnamespace_builtins;
|
||||
pub const last_no_payload_tag = Tag.@"break";
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
|
||||
pub fn Type(comptime t: Tag) type {
|
||||
@ -236,7 +236,6 @@ pub const Node = extern union {
|
||||
.true_literal,
|
||||
.false_literal,
|
||||
.empty_block,
|
||||
.usingnamespace_builtins,
|
||||
.return_void,
|
||||
.zero_literal,
|
||||
.one_literal,
|
||||
@ -344,6 +343,7 @@ pub const Node = extern union {
|
||||
.warning,
|
||||
.type,
|
||||
.helpers_macro,
|
||||
.import_builtin,
|
||||
=> Payload.Value,
|
||||
.discard => Payload.Discard,
|
||||
.@"if" => Payload.If,
|
||||
@ -871,22 +871,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
try c.buf.append('\n');
|
||||
return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'
|
||||
},
|
||||
.usingnamespace_builtins => {
|
||||
// pub usingnamespace @import("std").c.builtins;
|
||||
_ = try c.addToken(.keyword_pub, "pub");
|
||||
const usingnamespace_token = try c.addToken(.keyword_usingnamespace, "usingnamespace");
|
||||
const import_node = try renderStdImport(c, &.{ "zig", "c_builtins" });
|
||||
_ = try c.addToken(.semicolon, ";");
|
||||
|
||||
return c.addNode(.{
|
||||
.tag = .@"usingnamespace",
|
||||
.main_token = usingnamespace_token,
|
||||
.data = .{
|
||||
.lhs = import_node,
|
||||
.rhs = undefined,
|
||||
},
|
||||
});
|
||||
},
|
||||
.std_math_Log2Int => {
|
||||
const payload = node.castTag(.std_math_Log2Int).?.data;
|
||||
const import_node = try renderStdImport(c, &.{ "math", "Log2Int" });
|
||||
@ -1143,6 +1127,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
};
|
||||
return renderStdImport(c, &chain);
|
||||
},
|
||||
.import_builtin => {
|
||||
const payload = node.castTag(.import_builtin).?.data;
|
||||
const chain = [_][]const u8{
|
||||
"zig",
|
||||
"c_builtins",
|
||||
payload,
|
||||
};
|
||||
return renderStdImport(c, &chain);
|
||||
},
|
||||
.string_slice => {
|
||||
const payload = node.castTag(.string_slice).?.data;
|
||||
|
||||
@ -2352,7 +2345,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.@"comptime",
|
||||
.@"defer",
|
||||
.asm_simple,
|
||||
.usingnamespace_builtins,
|
||||
.while_true,
|
||||
.if_not_break,
|
||||
.switch_else,
|
||||
@ -2371,6 +2363,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.bit_xor_assign,
|
||||
.assign,
|
||||
.helpers_macro,
|
||||
.import_builtin,
|
||||
=> {
|
||||
// these should never appear in places where grouping might be needed.
|
||||
unreachable;
|
||||
|
@ -195,6 +195,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
|
||||
cases.add("use cast param as macro fn return type",
|
||||
\\#include <stdint.h>
|
||||
\\#define SYS_BASE_CACHED 0
|
||||
\\#define MEM_PHYSICAL_TO_K0(x) (void*)((uint32_t)(x) + SYS_BASE_CACHED)
|
||||
, &[_][]const u8{
|
||||
\\pub inline fn MEM_PHYSICAL_TO_K0(x: anytype) ?*c_void {
|
||||
@ -364,6 +365,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
});
|
||||
|
||||
cases.add("correct semicolon after infixop",
|
||||
\\#define _IO_ERR_SEEN 0
|
||||
\\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
|
||||
, &[_][]const u8{
|
||||
\\pub inline fn __ferror_unlocked_body(_fp: anytype) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != @as(c_int, 0)) {
|
||||
@ -430,6 +432,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
|
||||
cases.add("macro comma operator",
|
||||
\\#define foo (foo, bar)
|
||||
\\int baz(int x, int y) { return 0; }
|
||||
\\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
|
||||
, &[_][]const u8{
|
||||
\\pub const foo = blk: {
|
||||
@ -2573,6 +2576,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
|
||||
cases.add("macro call",
|
||||
\\#define CALL(arg) bar(arg)
|
||||
\\int bar(int x) { return x; }
|
||||
, &[_][]const u8{
|
||||
\\pub inline fn CALL(arg: anytype) @TypeOf(bar(arg)) {
|
||||
\\ return bar(arg);
|
||||
@ -2581,6 +2585,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
|
||||
cases.add("macro call with no args",
|
||||
\\#define CALL(arg) bar()
|
||||
\\int bar(void) { return 0; }
|
||||
, &[_][]const u8{
|
||||
\\pub inline fn CALL(arg: anytype) @TypeOf(bar()) {
|
||||
\\ _ = arg;
|
||||
@ -3139,6 +3144,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
|
||||
cases.add("macro cast",
|
||||
\\#include <stdint.h>
|
||||
\\int baz(void *arg) { return 0; }
|
||||
\\#define FOO(bar) baz((void *)(baz))
|
||||
\\#define BAR (void*) a
|
||||
\\#define BAZ (uint32_t)(2)
|
||||
@ -3475,11 +3481,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
|
||||
});
|
||||
|
||||
// See __builtin_alloca_with_align comment in std.zig.c_builtins
|
||||
cases.add("demote un-implemented builtins",
|
||||
\\#define FOO(X) __builtin_alloca_with_align((X), 8)
|
||||
, &[_][]const u8{
|
||||
\\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.zig.c_builtins");
|
||||
\\pub const FOO = @compileError("unable to translate macro: undefined identifier `__builtin_alloca_with_align`");
|
||||
});
|
||||
|
||||
cases.add("null sentinel arrays when initialized from string literal. Issue #8256",
|
||||
@ -3661,4 +3666,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub const FOO = @compileError("unable to translate macro: undefined identifier `BAR`");
|
||||
});
|
||||
|
||||
cases.add("Macro redefines builtin",
|
||||
\\#define FOO __builtin_popcount
|
||||
, &[_][]const u8{
|
||||
\\pub const FOO = __builtin_popcount;
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user