| author | |
| committer | |
| log | bc97a5662da4dd0a82840de79dd5600cef0ef825 |
| tree | c259592c1eca178bf6fc6b6380cd58896bb3035b |
| parent | 886fa455fad4997cf766ec2adcbac09d7e28f668 |
8 files changed, 115 insertions(+), 31 deletions(-)
src/Compilation.zig+24-3| ... | ... | @@ -31,6 +31,7 @@ const clangMain = @import("main.zig").clangMain; |
| 31 | 31 | const Module = @import("Module.zig"); |
| 32 | 32 | const Cache = @import("Cache.zig"); |
| 33 | 33 | const translate_c = @import("translate_c.zig"); |
| 34 | const clang = @import("clang.zig"); | |
| 34 | 35 | const c_codegen = @import("codegen/c.zig"); |
| 35 | 36 | const ThreadPool = @import("ThreadPool.zig"); |
| 36 | 37 | const WaitGroup = @import("WaitGroup.zig"); |
| ... | ... | @@ -2749,6 +2750,9 @@ pub fn totalErrorCount(self: *Compilation) usize { |
| 2749 | 2750 | const decl = module.declPtr(key); |
| 2750 | 2751 | if (decl.getFileScope().okToReportErrors()) { |
| 2751 | 2752 | total += 1; |
| 2753 | if (module.cimport_errors.get(key)) |errors| { | |
| 2754 | total += errors.len; | |
| 2755 | } | |
| 2752 | 2756 | } |
| 2753 | 2757 | } |
| 2754 | 2758 | if (module.emit_h) |emit_h| { |
| ... | ... | @@ -2858,6 +2862,23 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { |
| 2858 | 2862 | // We'll try again once parsing succeeds. |
| 2859 | 2863 | if (decl.getFileScope().okToReportErrors()) { |
| 2860 | 2864 | 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 | }; | |
| 2861 | 2882 | } |
| 2862 | 2883 | } |
| 2863 | 2884 | } |
| ... | ... | @@ -3524,7 +3545,7 @@ test "cImport" { |
| 3524 | 3545 | |
| 3525 | 3546 | const CImportResult = struct { |
| 3526 | 3547 | out_zig_path: []u8, |
| 3527 | errors: []translate_c.ClangErrMsg, | |
| 3548 | errors: []clang.ErrorMsg, | |
| 3528 | 3549 | }; |
| 3529 | 3550 | |
| 3530 | 3551 | /// Caller owns returned memory. |
| ... | ... | @@ -3599,7 +3620,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { |
| 3599 | 3620 | |
| 3600 | 3621 | const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); |
| 3601 | 3622 | 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{}; | |
| 3603 | 3624 | var tree = translate_c.translate( |
| 3604 | 3625 | comp.gpa, |
| 3605 | 3626 | new_argv.ptr, |
| ... | ... | @@ -3665,7 +3686,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { |
| 3665 | 3686 | } |
| 3666 | 3687 | return CImportResult{ |
| 3667 | 3688 | .out_zig_path = out_zig_path, |
| 3668 | .errors = &[0]translate_c.ClangErrMsg{}, | |
| 3689 | .errors = &[0]clang.ErrorMsg{}, | |
| 3669 | 3690 | }; |
| 3670 | 3691 | } |
| 3671 | 3692 |
src/Module.zig+30| ... | ... | @@ -31,6 +31,7 @@ const target_util = @import("target.zig"); |
| 31 | 31 | const build_options = @import("build_options"); |
| 32 | 32 | const Liveness = @import("Liveness.zig"); |
| 33 | 33 | const isUpDir = @import("introspect.zig").isUpDir; |
| 34 | const clang = @import("clang.zig"); | |
| 34 | 35 | |
| 35 | 36 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 36 | 37 | gpa: Allocator, |
| ... | ... | @@ -111,6 +112,9 @@ failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{}, |
| 111 | 112 | /// Using a map here for consistency with the other fields here. |
| 112 | 113 | /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. |
| 113 | 114 | 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) = .{}, | |
| 114 | 118 | |
| 115 | 119 | /// Candidates for deletion. After a semantic analysis update completes, this list |
| 116 | 120 | /// 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 { |
| 172 | 176 | src: LazySrcLoc, |
| 173 | 177 | }) = .{}, |
| 174 | 178 | |
| 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 | ||
| 175 | 194 | pub const StringLiteralContext = struct { |
| 176 | 195 | bytes: *ArrayListUnmanaged(u8), |
| 177 | 196 | |
| ... | ... | @@ -3449,6 +3468,11 @@ pub fn deinit(mod: *Module) void { |
| 3449 | 3468 | } |
| 3450 | 3469 | mod.failed_exports.deinit(gpa); |
| 3451 | 3470 | |
| 3471 | for (mod.cimport_errors.values()) |errs| { | |
| 3472 | for (errs) |err| err.deinit(gpa); | |
| 3473 | } | |
| 3474 | mod.cimport_errors.deinit(gpa); | |
| 3475 | ||
| 3452 | 3476 | mod.compile_log_decls.deinit(gpa); |
| 3453 | 3477 | |
| 3454 | 3478 | for (mod.decl_exports.values()) |*export_list| { |
| ... | ... | @@ -5381,6 +5405,9 @@ pub fn clearDecl( |
| 5381 | 5405 | if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| 5382 | 5406 | kv.value.destroy(gpa); |
| 5383 | 5407 | } |
| 5408 | if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { | |
| 5409 | for (kv.value) |err| err.deinit(gpa); | |
| 5410 | } | |
| 5384 | 5411 | if (mod.emit_h) |emit_h| { |
| 5385 | 5412 | if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| 5386 | 5413 | kv.value.destroy(gpa); |
| ... | ... | @@ -5768,6 +5795,9 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5768 | 5795 | if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| 5769 | 5796 | kv.value.destroy(mod.gpa); |
| 5770 | 5797 | } |
| 5798 | if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { | |
| 5799 | for (kv.value) |err| err.deinit(mod.gpa); | |
| 5800 | } | |
| 5771 | 5801 | if (decl.has_tv and decl.owns_tv) { |
| 5772 | 5802 | if (decl.val.castTag(.function)) |payload| { |
| 5773 | 5803 | const func = payload.data; |
src/Sema.zig+45-7| ... | ... | @@ -5130,20 +5130,58 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5130 | 5130 | |
| 5131 | 5131 | if (c_import_res.errors.len != 0) { |
| 5132 | 5132 | const msg = msg: { |
| 5133 | defer @import("clang.zig").ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); | |
| 5134 | ||
| 5133 | 5135 | const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); |
| 5134 | 5136 | errdefer msg.destroy(sema.gpa); |
| 5135 | 5137 | |
| 5136 | 5138 | if (!mod.comp.bin_file.options.link_libc) |
| 5137 | 5139 | try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); |
| 5138 | 5140 | |
| 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; | |
| 5145 | 5184 | } |
| 5146 | @import("clang.zig").Stage2ErrorMsg.delete(c_import_res.errors.ptr, c_import_res.errors.len); | |
| 5147 | 5185 | break :msg msg; |
| 5148 | 5186 | }; |
| 5149 | 5187 | return sema.failWithOwnedErrorMsg(msg); |
src/clang.zig+4-4| ... | ... | @@ -1897,13 +1897,13 @@ pub const OffsetOfNode_Kind = enum(c_int) { |
| 1897 | 1897 | Base, |
| 1898 | 1898 | }; |
| 1899 | 1899 | |
| 1900 | pub const Stage2ErrorMsg = extern struct { | |
| 1900 | pub const ErrorMsg = extern struct { | |
| 1901 | 1901 | filename_ptr: ?[*]const u8, |
| 1902 | 1902 | filename_len: usize, |
| 1903 | 1903 | msg_ptr: [*]const u8, |
| 1904 | 1904 | msg_len: usize, |
| 1905 | 1905 | // valid until the ASTUnit is freed |
| 1906 | source: ?[*]const u8, | |
| 1906 | source: ?[*:0]const u8, | |
| 1907 | 1907 | // 0 based |
| 1908 | 1908 | line: c_uint, |
| 1909 | 1909 | // 0 based |
| ... | ... | @@ -1912,14 +1912,14 @@ pub const Stage2ErrorMsg = extern struct { |
| 1912 | 1912 | offset: c_uint, |
| 1913 | 1913 | |
| 1914 | 1914 | 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; | |
| 1916 | 1916 | }; |
| 1917 | 1917 | |
| 1918 | 1918 | pub const LoadFromCommandLine = ZigClangLoadFromCommandLine; |
| 1919 | 1919 | extern fn ZigClangLoadFromCommandLine( |
| 1920 | 1920 | args_begin: [*]?[*]const u8, |
| 1921 | 1921 | args_end: [*]?[*]const u8, |
| 1922 | errors_ptr: *[*]Stage2ErrorMsg, | |
| 1922 | errors_ptr: *[*]ErrorMsg, | |
| 1923 | 1923 | errors_len: *usize, |
| 1924 | 1924 | resources_path: [*:0]const u8, |
| 1925 | 1925 | ) ?*ASTUnit; |
src/main.zig+2-1| ... | ... | @@ -19,6 +19,7 @@ const introspect = @import("introspect.zig"); |
| 19 | 19 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 20 | 20 | const wasi_libc = @import("wasi_libc.zig"); |
| 21 | 21 | const translate_c = @import("translate_c.zig"); |
| 22 | const clang = @import("clang.zig"); | |
| 22 | 23 | const Cache = @import("Cache.zig"); |
| 23 | 24 | const target_util = @import("target.zig"); |
| 24 | 25 | const ThreadPool = @import("ThreadPool.zig"); |
| ... | ... | @@ -3552,7 +3553,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void |
| 3552 | 3553 | |
| 3553 | 3554 | const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); |
| 3554 | 3555 | 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{}; | |
| 3556 | 3557 | var tree = translate_c.translate( |
| 3557 | 3558 | comp.gpa, |
| 3558 | 3559 | new_argv.ptr, |
src/translate_c.zig+1-7| ... | ... | @@ -13,8 +13,6 @@ const Tag = Node.Tag; |
| 13 | 13 | |
| 14 | 14 | const CallingConvention = std.builtin.CallingConvention; |
| 15 | 15 | |
| 16 | pub const ClangErrMsg = clang.Stage2ErrorMsg; | |
| 17 | ||
| 18 | 16 | pub const Error = std.mem.Allocator.Error; |
| 19 | 17 | const MacroProcessingError = Error || error{UnexpectedMacroToken}; |
| 20 | 18 | const TypeError = Error || error{UnsupportedType}; |
| ... | ... | @@ -350,7 +348,7 @@ pub fn translate( |
| 350 | 348 | gpa: mem.Allocator, |
| 351 | 349 | args_begin: [*]?[*]const u8, |
| 352 | 350 | args_end: [*]?[*]const u8, |
| 353 | errors: *[]ClangErrMsg, | |
| 351 | errors: *[]clang.ErrorMsg, | |
| 354 | 352 | resources_path: [*:0]const u8, |
| 355 | 353 | ) !std.zig.Ast { |
| 356 | 354 | // TODO stage2 bug |
| ... | ... | @@ -5115,10 +5113,6 @@ pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, compti |
| 5115 | 5113 | try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment)); |
| 5116 | 5114 | } |
| 5117 | 5115 | |
| 5118 | pub fn freeErrors(errors: []ClangErrMsg) void { | |
| 5119 | errors.ptr.delete(errors.len); | |
| 5120 | } | |
| 5121 | ||
| 5122 | 5116 | const PatternList = struct { |
| 5123 | 5117 | patterns: []Pattern, |
| 5124 | 5118 |
test/cases/compile_errors/cImport_with_bogus_include.zig created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | const c = @cImport(@cInclude("bogus.h")); | |
| 2 | export fn entry() usize { return @sizeOf(@TypeOf(c.bogo)); } | |
| 3 | ||
| 4 | // error | |
| 5 | // backend=llvm | |
| 6 | // target=native | |
| 7 | // | |
| 8 | // :1:11: error: C import failed | |
| 9 | // :1:10: error: 'bogus.h' file not found |
test/cases/compile_errors/stage1/obj/cImport_with_bogus_include.zig deleted-9| ... | ... | @@ -1,9 +0,0 @@ |
| 1 | const c = @cImport(@cInclude("bogus.h")); | |
| 2 | export fn entry() usize { return @sizeOf(@TypeOf(c.bogo)); } | |
| 3 | ||
| 4 | // error | |
| 5 | // backend=stage1 | |
| 6 | // target=native | |
| 7 | // | |
| 8 | // tmp.zig:1:11: error: C import failed | |
| 9 | // .h:1:10: note: 'bogus.h' file not found |