From bc97a5662da4dd0a82840de79dd5600cef0ef825 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 12 Dec 2022 13:16:09 +0200 Subject: Sema: display cimport errors from clang --- src/Compilation.zig | 27 ++++++++++++++++++++++++--- src/Module.zig | 30 ++++++++++++++++++++++++++++++ src/Sema.zig | 52 +++++++++++++++++++++++++++++++++++++++++++++------- src/clang.zig | 8 ++++---- src/main.zig | 3 ++- src/translate_c.zig | 8 +------- 6 files changed, 106 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/Compilation.zig b/src/Compilation.zig index 911089df02..1d0997d20c 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -31,6 +31,7 @@ const clangMain = @import("main.zig").clangMain; const Module = @import("Module.zig"); const Cache = @import("Cache.zig"); const translate_c = @import("translate_c.zig"); +const clang = @import("clang.zig"); const c_codegen = @import("codegen/c.zig"); const ThreadPool = @import("ThreadPool.zig"); const WaitGroup = @import("WaitGroup.zig"); @@ -2749,6 +2750,9 @@ pub fn totalErrorCount(self: *Compilation) usize { const decl = module.declPtr(key); if (decl.getFileScope().okToReportErrors()) { total += 1; + if (module.cimport_errors.get(key)) |errors| { + total += errors.len; + } } } if (module.emit_h) |emit_h| { @@ -2858,6 +2862,23 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { // We'll try again once parsing succeeds. if (decl.getFileScope().okToReportErrors()) { try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*); + if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| { + if (c_error.path) |some| + try errors.append(.{ + .src = .{ + .src_path = try arena_allocator.dupe(u8, std.mem.span(some)), + .span = .{ .start = c_error.offset, .end = c_error.offset + 1, .main = c_error.offset }, + .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)), + .line = c_error.line, + .column = c_error.column, + .source_line = if (c_error.source_line) |line| try arena_allocator.dupe(u8, std.mem.span(line)) else null, + }, + }) + else + try errors.append(.{ + .plain = .{ .msg = try arena_allocator.dupe(u8, std.mem.span(c_error.msg)) }, + }); + }; } } } @@ -3524,7 +3545,7 @@ test "cImport" { const CImportResult = struct { out_zig_path: []u8, - errors: []translate_c.ClangErrMsg, + errors: []clang.ErrorMsg, }; /// Caller owns returned memory. @@ -3599,7 +3620,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); - var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; + var clang_errors: []clang.ErrorMsg = &[0]clang.ErrorMsg{}; var tree = translate_c.translate( comp.gpa, new_argv.ptr, @@ -3665,7 +3686,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { } return CImportResult{ .out_zig_path = out_zig_path, - .errors = &[0]translate_c.ClangErrMsg{}, + .errors = &[0]clang.ErrorMsg{}, }; } diff --git a/src/Module.zig b/src/Module.zig index 57745a3276..83294f3068 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -31,6 +31,7 @@ const target_util = @import("target.zig"); const build_options = @import("build_options"); const Liveness = @import("Liveness.zig"); const isUpDir = @import("introspect.zig").isUpDir; +const clang = @import("clang.zig"); /// General-purpose allocator. Used for both temporary and long-term storage. gpa: Allocator, @@ -111,6 +112,9 @@ failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{}, /// Using a map here for consistency with the other fields here. /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, +/// If a decl failed due to a cimport error, the corresponding Clang errors +/// are stored here. +cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, /// Candidates for deletion. After a semantic analysis update completes, this list /// 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 { src: LazySrcLoc, }) = .{}, +pub const CImportError = struct { + offset: u32, + line: u32, + column: u32, + path: ?[*:0]u8, + source_line: ?[*:0]u8, + msg: [*:0]u8, + + pub fn deinit(err: CImportError, gpa: Allocator) void { + if (err.path) |some| gpa.free(std.mem.span(some)); + if (err.source_line) |some| gpa.free(std.mem.span(some)); + gpa.free(std.mem.span(err.msg)); + } +}; + pub const StringLiteralContext = struct { bytes: *ArrayListUnmanaged(u8), @@ -3449,6 +3468,11 @@ pub fn deinit(mod: *Module) void { } mod.failed_exports.deinit(gpa); + for (mod.cimport_errors.values()) |errs| { + for (errs) |err| err.deinit(gpa); + } + mod.cimport_errors.deinit(gpa); + mod.compile_log_decls.deinit(gpa); for (mod.decl_exports.values()) |*export_list| { @@ -5381,6 +5405,9 @@ pub fn clearDecl( if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { kv.value.destroy(gpa); } + if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { + for (kv.value) |err| err.deinit(gpa); + } if (mod.emit_h) |emit_h| { if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { kv.value.destroy(gpa); @@ -5768,6 +5795,9 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { kv.value.destroy(mod.gpa); } + if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { + for (kv.value) |err| err.deinit(mod.gpa); + } if (decl.has_tv and decl.owns_tv) { if (decl.val.castTag(.function)) |payload| { const func = payload.data; diff --git a/src/Sema.zig b/src/Sema.zig index 6fcff1fec8..8c7c8b0dd7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5130,20 +5130,58 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr if (c_import_res.errors.len != 0) { const msg = msg: { + defer @import("clang.zig").ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); + const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); errdefer msg.destroy(sema.gpa); if (!mod.comp.bin_file.options.link_libc) try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); - for (c_import_res.errors) |_| { - // TODO integrate with LazySrcLoc - // try mod.errNoteNonLazy(.{}, msg, "{s}", .{clang_err.msg_ptr[0..clang_err.msg_len]}); - // if (clang_err.filename_ptr) |p| p[0..clang_err.filename_len] else "(no file)", - // clang_err.line + 1, - // clang_err.column + 1, + const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index); + if (!gop.found_existing) { + var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len); + errdefer { + for (errs.items) |err| err.deinit(sema.gpa); + errs.deinit(sema.gpa); + } + + for (c_import_res.errors) |c_error| { + const path = if (c_error.filename_ptr) |some| + try sema.gpa.dupeZ(u8, some[0..c_error.filename_len]) + else + null; + errdefer if (path) |some| sema.gpa.free(some); + + const c_msg = try sema.gpa.dupeZ(u8, c_error.msg_ptr[0..c_error.msg_len]); + errdefer sema.gpa.free(c_msg); + + const line = line: { + const source = c_error.source orelse break :line null; + var start = c_error.offset; + while (start > 0) : (start -= 1) { + if (source[start - 1] == '\n') break; + } + var end = c_error.offset; + while (true) : (end += 1) { + if (source[end] == 0) break; + if (source[end] == '\n') break; + } + break :line try sema.gpa.dupeZ(u8, source[start..end]); + }; + errdefer if (line) |some| sema.gpa.free(some); + + errs.appendAssumeCapacity(.{ + .path = path orelse null, + .source_line = line orelse null, + .line = c_error.line, + .column = c_error.column, + .offset = c_error.offset, + .msg = c_msg, + }); + } + gop.value_ptr.* = errs.items; } - @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); diff --git a/src/clang.zig b/src/clang.zig index 36b9c71a87..a3a364c0ec 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -1897,13 +1897,13 @@ pub const OffsetOfNode_Kind = enum(c_int) { Base, }; -pub const Stage2ErrorMsg = extern struct { +pub const ErrorMsg = extern struct { filename_ptr: ?[*]const u8, filename_len: usize, msg_ptr: [*]const u8, msg_len: usize, // valid until the ASTUnit is freed - source: ?[*]const u8, + source: ?[*:0]const u8, // 0 based line: c_uint, // 0 based @@ -1912,14 +1912,14 @@ pub const Stage2ErrorMsg = extern struct { offset: c_uint, pub const delete = ZigClangErrorMsg_delete; - extern fn ZigClangErrorMsg_delete(ptr: [*]Stage2ErrorMsg, len: usize) void; + extern fn ZigClangErrorMsg_delete(ptr: [*]ErrorMsg, len: usize) void; }; pub const LoadFromCommandLine = ZigClangLoadFromCommandLine; extern fn ZigClangLoadFromCommandLine( args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, - errors_ptr: *[*]Stage2ErrorMsg, + errors_ptr: *[*]ErrorMsg, errors_len: *usize, resources_path: [*:0]const u8, ) ?*ASTUnit; diff --git a/src/main.zig b/src/main.zig index 9e428a3c3a..a7d4dc6f03 100644 --- a/src/main.zig +++ b/src/main.zig @@ -19,6 +19,7 @@ const introspect = @import("introspect.zig"); const LibCInstallation = @import("libc_installation.zig").LibCInstallation; const wasi_libc = @import("wasi_libc.zig"); const translate_c = @import("translate_c.zig"); +const clang = @import("clang.zig"); const Cache = @import("Cache.zig"); const target_util = @import("target.zig"); const ThreadPool = @import("ThreadPool.zig"); @@ -3552,7 +3553,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); - var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; + var clang_errors: []clang.ErrorMsg = &[0]clang.ErrorMsg{}; var tree = translate_c.translate( comp.gpa, new_argv.ptr, diff --git a/src/translate_c.zig b/src/translate_c.zig index 8ead8e6a28..47a21f5b5c 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -13,8 +13,6 @@ const Tag = Node.Tag; const CallingConvention = std.builtin.CallingConvention; -pub const ClangErrMsg = clang.Stage2ErrorMsg; - pub const Error = std.mem.Allocator.Error; const MacroProcessingError = Error || error{UnexpectedMacroToken}; const TypeError = Error || error{UnsupportedType}; @@ -350,7 +348,7 @@ pub fn translate( gpa: mem.Allocator, args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, - errors: *[]ClangErrMsg, + errors: *[]clang.ErrorMsg, resources_path: [*:0]const u8, ) !std.zig.Ast { // TODO stage2 bug @@ -5115,10 +5113,6 @@ pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, compti try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment)); } -pub fn freeErrors(errors: []ClangErrMsg) void { - errors.ptr.delete(errors.len); -} - const PatternList = struct { patterns: []Pattern, -- cgit v1.2.3