Skip to content

Commit bc97a56

Browse files
committed
Sema: display cimport errors from clang
1 parent 886fa45 commit bc97a56

7 files changed

Lines changed: 109 additions & 25 deletions

File tree

src/Compilation.zig

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const clangMain = @import("main.zig").clangMain;
3131
const Module = @import("Module.zig");
3232
const Cache = @import("Cache.zig");
3333
const translate_c = @import("translate_c.zig");
34+
const clang = @import("clang.zig");
3435
const c_codegen = @import("codegen/c.zig");
3536
const ThreadPool = @import("ThreadPool.zig");
3637
const WaitGroup = @import("WaitGroup.zig");
@@ -2749,6 +2750,9 @@ pub fn totalErrorCount(self: *Compilation) usize {
27492750
const decl = module.declPtr(key);
27502751
if (decl.getFileScope().okToReportErrors()) {
27512752
total += 1;
2753+
if (module.cimport_errors.get(key)) |errors| {
2754+
total += errors.len;
2755+
}
27522756
}
27532757
}
27542758
if (module.emit_h) |emit_h| {
@@ -2858,6 +2862,23 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
28582862
// We'll try again once parsing succeeds.
28592863
if (decl.getFileScope().okToReportErrors()) {
28602864
try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
2865+
if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
2866+
if (c_error.path) |some|
2867+
try errors.append(.{
2868+
.src = .{
2869+
.src_path = try arena_allocator.dupe(u8, std.mem.span(some)),
2870+
.span = .{ .start = c_error.offset, .end = c_error.offset + 1, .main = c_error.offset },
2871+
.msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)),
2872+
.line = c_error.line,
2873+
.column = c_error.column,
2874+
.source_line = if (c_error.source_line) |line| try arena_allocator.dupe(u8, std.mem.span(line)) else null,
2875+
},
2876+
})
2877+
else
2878+
try errors.append(.{
2879+
.plain = .{ .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)) },
2880+
});
2881+
};
28612882
}
28622883
}
28632884
}
@@ -3524,7 +3545,7 @@ test "cImport" {
35243545

35253546
const CImportResult = struct {
35263547
out_zig_path: []u8,
3527-
errors: []translate_c.ClangErrMsg,
3548+
errors: []clang.ErrorMsg,
35283549
};
35293550

35303551
/// Caller owns returned memory.
@@ -3599,7 +3620,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
35993620

36003621
const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
36013622
const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
3602-
var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
3623+
var clang_errors: []clang.ErrorMsg = &[0]clang.ErrorMsg{};
36033624
var tree = translate_c.translate(
36043625
comp.gpa,
36053626
new_argv.ptr,
@@ -3665,7 +3686,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
36653686
}
36663687
return CImportResult{
36673688
.out_zig_path = out_zig_path,
3668-
.errors = &[0]translate_c.ClangErrMsg{},
3689+
.errors = &[0]clang.ErrorMsg{},
36693690
};
36703691
}
36713692

src/Module.zig

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const target_util = @import("target.zig");
3131
const build_options = @import("build_options");
3232
const Liveness = @import("Liveness.zig");
3333
const isUpDir = @import("introspect.zig").isUpDir;
34+
const clang = @import("clang.zig");
3435

3536
/// General-purpose allocator. Used for both temporary and long-term storage.
3637
gpa: Allocator,
@@ -111,6 +112,9 @@ failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
111112
/// Using a map here for consistency with the other fields here.
112113
/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
113114
failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
115+
/// If a decl failed due to a cimport error, the corresponding Clang errors
116+
/// are stored here.
117+
cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{},
114118

115119
/// Candidates for deletion. After a semantic analysis update completes, this list
116120
/// contains Decls that need to be deleted if they end up having no references to them.
@@ -172,6 +176,21 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
172176
src: LazySrcLoc,
173177
}) = .{},
174178

179+
pub const CImportError = struct {
180+
offset: u32,
181+
line: u32,
182+
column: u32,
183+
path: ?[*:0]u8,
184+
source_line: ?[*:0]u8,
185+
msg: [*:0]u8,
186+
187+
pub fn deinit(err: CImportError, gpa: Allocator) void {
188+
if (err.path) |some| gpa.free(std.mem.span(some));
189+
if (err.source_line) |some| gpa.free(std.mem.span(some));
190+
gpa.free(std.mem.span(err.msg));
191+
}
192+
};
193+
175194
pub const StringLiteralContext = struct {
176195
bytes: *ArrayListUnmanaged(u8),
177196

@@ -3449,6 +3468,11 @@ pub fn deinit(mod: *Module) void {
34493468
}
34503469
mod.failed_exports.deinit(gpa);
34513470

3471+
for (mod.cimport_errors.values()) |errs| {
3472+
for (errs) |err| err.deinit(gpa);
3473+
}
3474+
mod.cimport_errors.deinit(gpa);
3475+
34523476
mod.compile_log_decls.deinit(gpa);
34533477

34543478
for (mod.decl_exports.values()) |*export_list| {
@@ -5381,6 +5405,9 @@ pub fn clearDecl(
53815405
if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| {
53825406
kv.value.destroy(gpa);
53835407
}
5408+
if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| {
5409+
for (kv.value) |err| err.deinit(gpa);
5410+
}
53845411
if (mod.emit_h) |emit_h| {
53855412
if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| {
53865413
kv.value.destroy(gpa);
@@ -5768,6 +5795,9 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void {
57685795
if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| {
57695796
kv.value.destroy(mod.gpa);
57705797
}
5798+
if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| {
5799+
for (kv.value) |err| err.deinit(mod.gpa);
5800+
}
57715801
if (decl.has_tv and decl.owns_tv) {
57725802
if (decl.val.castTag(.function)) |payload| {
57735803
const func = payload.data;

src/Sema.zig

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5130,20 +5130,58 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
51305130

51315131
if (c_import_res.errors.len != 0) {
51325132
const msg = msg: {
5133+
defer @import("clang.zig").ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len);
5134+
51335135
const msg = try sema.errMsg(&child_block, src, "C import failed", .{});
51345136
errdefer msg.destroy(sema.gpa);
51355137

51365138
if (!mod.comp.bin_file.options.link_libc)
51375139
try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{});
51385140

5139-
for (c_import_res.errors) |_| {
5140-
// TODO integrate with LazySrcLoc
5141-
// try mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]});
5142-
// if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)",
5143-
// clang_err.line + 1,
5144-
// clang_err.column + 1,
5141+
const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index);
5142+
if (!gop.found_existing) {
5143+
var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len);
5144+
errdefer {
5145+
for (errs.items) |err| err.deinit(sema.gpa);
5146+
errs.deinit(sema.gpa);
5147+
}
5148+
5149+
for (c_import_res.errors) |c_error| {
5150+
const path = if (c_error.filename_ptr) |some|
5151+
try sema.gpa.dupeZ(u8, some[0..c_error.filename_len])
5152+
else
5153+
null;
5154+
errdefer if (path) |some| sema.gpa.free(some);
5155+
5156+
const c_msg = try sema.gpa.dupeZ(u8, c_error.msg_ptr[0..c_error.msg_len]);
5157+
errdefer sema.gpa.free(c_msg);
5158+
5159+
const line = line: {
5160+
const source = c_error.source orelse break :line null;
5161+
var start = c_error.offset;
5162+
while (start > 0) : (start -= 1) {
5163+
if (source[start - 1] == '\n') break;
5164+
}
5165+
var end = c_error.offset;
5166+
while (true) : (end += 1) {
5167+
if (source[end] == 0) break;
5168+
if (source[end] == '\n') break;
5169+
}
5170+
break :line try sema.gpa.dupeZ(u8, source[start..end]);
5171+
};
5172+
errdefer if (line) |some| sema.gpa.free(some);
5173+
5174+
errs.appendAssumeCapacity(.{
5175+
.path = path orelse null,
5176+
.source_line = line orelse null,
5177+
.line = c_error.line,
5178+
.column = c_error.column,
5179+
.offset = c_error.offset,
5180+
.msg = c_msg,
5181+
});
5182+
}
5183+
gop.value_ptr.* = errs.items;
51455184
}
5146-
@import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len);
51475185
break :msg msg;
51485186
};
51495187
return sema.failWithOwnedErrorMsg(msg);

src/clang.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,13 +1897,13 @@ pub const OffsetOfNode_Kind = enum(c_int) {
18971897
Base,
18981898
};
18991899

1900-
pub const Stage2ErrorMsg = extern struct {
1900+
pub const ErrorMsg = extern struct {
19011901
filename_ptr: ?[*]const u8,
19021902
filename_len: usize,
19031903
msg_ptr: [*]const u8,
19041904
msg_len: usize,
19051905
// valid until the ASTUnit is freed
1906-
source: ?[*]const u8,
1906+
source: ?[*:0]const u8,
19071907
// 0 based
19081908
line: c_uint,
19091909
// 0 based
@@ -1912,14 +1912,14 @@ pub const Stage2ErrorMsg = extern struct {
19121912
offset: c_uint,
19131913

19141914
pub const delete = ZigClangErrorMsg_delete;
1915-
extern fn ZigClangErrorMsg_delete(ptr: [*]Stage2ErrorMsg, len: usize) void;
1915+
extern fn ZigClangErrorMsg_delete(ptr: [*]ErrorMsg, len: usize) void;
19161916
};
19171917

19181918
pub const LoadFromCommandLine = ZigClangLoadFromCommandLine;
19191919
extern fn ZigClangLoadFromCommandLine(
19201920
args_begin: [*]?[*]const u8,
19211921
args_end: [*]?[*]const u8,
1922-
errors_ptr: *[*]Stage2ErrorMsg,
1922+
errors_ptr: *[*]ErrorMsg,
19231923
errors_len: *usize,
19241924
resources_path: [*:0]const u8,
19251925
) ?*ASTUnit;

src/main.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const introspect = @import("introspect.zig");
1919
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2020
const wasi_libc = @import("wasi_libc.zig");
2121
const translate_c = @import("translate_c.zig");
22+
const clang = @import("clang.zig");
2223
const Cache = @import("Cache.zig");
2324
const target_util = @import("target.zig");
2425
const ThreadPool = @import("ThreadPool.zig");
@@ -3552,7 +3553,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
35523553

35533554
const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
35543555
const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
3555-
var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
3556+
var clang_errors: []clang.ErrorMsg = &[0]clang.ErrorMsg{};
35563557
var tree = translate_c.translate(
35573558
comp.gpa,
35583559
new_argv.ptr,

src/translate_c.zig

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ const Tag = Node.Tag;
1313

1414
const CallingConvention = std.builtin.CallingConvention;
1515

16-
pub const ClangErrMsg = clang.Stage2ErrorMsg;
17-
1816
pub const Error = std.mem.Allocator.Error;
1917
const MacroProcessingError = Error || error{UnexpectedMacroToken};
2018
const TypeError = Error || error{UnsupportedType};
@@ -350,7 +348,7 @@ pub fn translate(
350348
gpa: mem.Allocator,
351349
args_begin: [*]?[*]const u8,
352350
args_end: [*]?[*]const u8,
353-
errors: *[]ClangErrMsg,
351+
errors: *[]clang.ErrorMsg,
354352
resources_path: [*:0]const u8,
355353
) !std.zig.Ast {
356354
// TODO stage2 bug
@@ -5115,10 +5113,6 @@ pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, compti
51155113
try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment));
51165114
}
51175115

5118-
pub fn freeErrors(errors: []ClangErrMsg) void {
5119-
errors.ptr.delete(errors.len);
5120-
}
5121-
51225116
const PatternList = struct {
51235117
patterns: []Pattern,
51245118

test/cases/compile_errors/stage1/obj/cImport_with_bogus_include.zig renamed to test/cases/compile_errors/cImport_with_bogus_include.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ const c = @cImport(@cInclude("bogus.h"));
22
export fn entry() usize { return @sizeOf(@TypeOf(c.bogo)); }
33

44
// error
5-
// backend=stage1
5+
// backend=llvm
66
// target=native
77
//
8-
// tmp.zig:1:11: error: C import failed
9-
// .h:1:10: note: 'bogus.h' file not found
8+
// :1:11: error: C import failed
9+
// :1:10: error: 'bogus.h' file not found

0 commit comments

Comments
 (0)