Skip to content

Commit 4dfe787

Browse files
committed
translate-c: unify API for self-hosted and C++ translate-c
See #1964
1 parent 93a72bd commit 4dfe787

12 files changed

+281
-143
lines changed

src-self-hosted/clang.zig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;
862862
pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*c]const u64;
863863
pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;
864864
pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;
865+
pub extern fn ZigClangASTUnit_delete(arg0: ?*struct_ZigClangASTUnit) void;
865866
pub const ZigClangSourceLocation = struct_ZigClangSourceLocation;
866867
pub const ZigClangQualType = struct_ZigClangQualType;
867868
pub const ZigClangAPValueLValueBase = struct_ZigClangAPValueLValueBase;
@@ -942,3 +943,19 @@ pub const ZigClangTypeClass = enum_ZigClangTypeClass;
942943
pub const ZigClangStmtClass = enum_ZigClangStmtClass;
943944
pub const ZigClangCK = enum_ZigClangCK;
944945
pub const ZigClangAPValueKind = enum_ZigClangAPValueKind;
946+
947+
pub const Stage2ErrorMsg = extern struct {
948+
filename_ptr: ?[*]const u8,
949+
filename_len: usize,
950+
msg_ptr: [*]const u8,
951+
msg_len: usize,
952+
// valid until the ASTUnit is freed
953+
source: ?[*]const u8,
954+
// 0 based
955+
line: c_uint,
956+
// 0 based
957+
column: c_uint,
958+
// byte offset into source
959+
offset: c_uint,
960+
};
961+
pub extern fn ZigClangErrorMsg_delete(ptr: [*c]Stage2ErrorMsg, len: usize) void;

src-self-hosted/main.zig

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,23 @@ fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
858858
try stdout.write(usage);
859859
}
860860

861-
const info_zen = @import("stage1.zig").info_zen;
861+
pub const info_zen =
862+
\\
863+
\\ * Communicate intent precisely.
864+
\\ * Edge cases matter.
865+
\\ * Favor reading code over writing code.
866+
\\ * Only one obvious way to do things.
867+
\\ * Runtime crashes are better than bugs.
868+
\\ * Compile errors are better than runtime crashes.
869+
\\ * Incremental improvements.
870+
\\ * Avoid local maximums.
871+
\\ * Reduce the amount one must remember.
872+
\\ * Minimize energy spent on coding style.
873+
\\ * Together we serve end users.
874+
\\
875+
\\
876+
;
877+
862878
fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
863879
try stdout.write(info_zen);
864880
}

src-self-hosted/stage1.zig

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,25 @@
33

44
const std = @import("std");
55

6-
pub const info_zen =
7-
\\
8-
\\ * Communicate intent precisely.
9-
\\ * Edge cases matter.
10-
\\ * Favor reading code over writing code.
11-
\\ * Only one obvious way to do things.
12-
\\ * Runtime crashes are better than bugs.
13-
\\ * Compile errors are better than runtime crashes.
14-
\\ * Incremental improvements.
15-
\\ * Avoid local maximums.
16-
\\ * Reduce the amount one must remember.
17-
\\ * Minimize energy spent on coding style.
18-
\\ * Together we serve end users.
19-
\\
20-
\\
21-
;
22-
6+
// ABI warning
237
export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
8+
const info_zen = @import("main.zig").info_zen;
249
ptr.* = &info_zen;
2510
len.* = info_zen.len;
2611
}
2712

13+
// ABI warning
2814
export fn stage2_panic(ptr: [*]const u8, len: usize) void {
2915
@panic(ptr[0..len]);
3016
}
3117

18+
// ABI warning
3219
const TranslateMode = extern enum {
3320
import,
3421
translate,
3522
};
3623

24+
// ABI warning
3725
const Error = extern enum {
3826
None,
3927
OutOfMemory,
@@ -84,24 +72,33 @@ const Error = extern enum {
8472

8573
const FILE = std.c.FILE;
8674
const ast = std.zig.ast;
75+
const translate_c = @import("translate_c.zig");
8776

8877
/// Args should have a null terminating last arg.
8978
export fn stage2_translate_c(
9079
out_ast: **ast.Tree,
80+
out_errors_ptr: *[*]translate_c.ClangErrMsg,
81+
out_errors_len: *usize,
9182
args_begin: [*]?[*]const u8,
9283
args_end: [*]?[*]const u8,
9384
mode: TranslateMode,
85+
resources_path: [*]const u8,
9486
) Error {
95-
const translate_c = @import("translate_c.zig");
87+
var errors: []translate_c.ClangErrMsg = undefined;
9688
out_ast.* = translate_c.translate(args_begin, args_end, switch (mode) {
9789
.import => translate_c.Mode.import,
9890
.translate => translate_c.Mode.translate,
99-
}) catch |err| switch (err) {
91+
}, &errors) catch |err| switch (err) {
10092
error.Unimplemented => return Error.Unimplemented,
10193
};
94+
10295
return Error.None;
10396
}
10497

98+
export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
99+
translate_c.freeErrors(errors_ptr[0..errors_len]);
100+
}
101+
105102
export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
106103
const c_out_stream = &std.io.COutStream.init(output_file).stream;
107104
_ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {

src-self-hosted/translate_c.zig

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ pub const Mode = enum {
1010
translate,
1111
};
1212

13-
pub fn translate(args_begin: [*]?[*]const u8, args_end: [*]?[*]const u8, mode: Mode) !*ast.Tree {
13+
pub const ClangErrMsg = Stage2ErrorMsg;
14+
15+
pub fn translate(
16+
args_begin: [*]?[*]const u8,
17+
args_end: [*]?[*]const u8,
18+
mode: Mode,
19+
errors: *[]ClangErrMsg,
20+
) !*ast.Tree {
1421
return error.Unimplemented;
1522
}
23+
24+
pub fn freeErrors(errors: []ClangErrMsg) void {
25+
ZigClangErrorMsg_delete(errors.ptr, errors.len);
26+
}

src/codegen.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8298,31 +8298,42 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us
82988298

82998299
clang_argv.append(nullptr); // to make the [start...end] argument work
83008300

8301+
const char *resources_path = buf_ptr(g->zig_c_headers_dir);
8302+
Stage2ErrorMsg *errors_ptr;
8303+
size_t errors_len;
8304+
Stage2Ast *ast;
8305+
AstNode *root_node;
8306+
83018307
if (use_userland_implementation) {
8302-
Stage2Ast *ast;
8303-
if ((err = stage2_translate_c(&ast, &clang_argv.at(0), &clang_argv.last(), trans_mode))) {
8304-
zig_panic("TODO");
8305-
}
8306-
stage2_render_ast(ast, out_file);
8308+
err = stage2_translate_c(&ast, &errors_ptr, &errors_len,
8309+
&clang_argv.at(0), &clang_argv.last(), trans_mode, resources_path);
83078310
} else {
8308-
ZigList<ErrorMsg *> errors = {0};
8309-
AstNode *root_node;
8310-
8311-
err = parse_h_file(g, &root_node, &clang_argv.at(0), &clang_argv.last(), trans_mode, &errors);
8311+
err = parse_h_file(g, &root_node, &errors_ptr, &errors_len, &clang_argv.at(0), &clang_argv.last(),
8312+
trans_mode, resources_path);
8313+
}
83128314

8313-
if (err == ErrorCCompileErrors && errors.length > 0) {
8314-
for (size_t i = 0; i < errors.length; i += 1) {
8315-
ErrorMsg *err_msg = errors.at(i);
8316-
print_err_msg(err_msg, g->err_color);
8317-
}
8318-
exit(1);
8315+
if (err == ErrorCCompileErrors && errors_len > 0) {
8316+
for (size_t i = 0; i < errors_len; i += 1) {
8317+
Stage2ErrorMsg *clang_err = &errors_ptr[i];
8318+
ErrorMsg *err_msg = err_msg_create_with_offset(
8319+
clang_err->filename_ptr ?
8320+
buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
8321+
clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
8322+
buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
8323+
print_err_msg(err_msg, g->err_color);
83198324
}
8325+
exit(1);
8326+
}
83208327

8321-
if (err) {
8322-
fprintf(stderr, "unable to parse C file: %s\n", err_str(err));
8323-
exit(1);
8324-
}
8328+
if (err) {
8329+
fprintf(stderr, "unable to parse C file: %s\n", err_str(err));
8330+
exit(1);
8331+
}
83258332

8333+
8334+
if (use_userland_implementation) {
8335+
stage2_render_ast(ast, out_file);
8336+
} else {
83268337
ast_render(out_file, root_node, 4);
83278338
}
83288339
}

src/ir.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19084,25 +19084,32 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
1908419084

1908519085
clang_argv.append(nullptr); // to make the [start...end] argument work
1908619086

19087-
ZigList<ErrorMsg *> errors = {0};
1908819087
AstNode *root_node;
19088+
Stage2ErrorMsg *errors_ptr;
19089+
size_t errors_len;
1908919090

19090-
if ((err = parse_h_file(ira->codegen, &root_node, &clang_argv.at(0), &clang_argv.last(),
19091-
Stage2TranslateModeImport, &errors)))
19091+
const char *resources_path = buf_ptr(ira->codegen->zig_c_headers_dir);
19092+
19093+
if ((err = parse_h_file(ira->codegen, &root_node, &errors_ptr, &errors_len,
19094+
&clang_argv.at(0), &clang_argv.last(), Stage2TranslateModeImport, resources_path)))
1909219095
{
1909319096
if (err != ErrorCCompileErrors) {
1909419097
ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err)));
1909519098
return ira->codegen->invalid_instruction;
1909619099
}
19097-
assert(errors.length > 0);
1909819100

1909919101
ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed"));
1910019102
if (ira->codegen->libc_link_lib == nullptr) {
1910119103
add_error_note(ira->codegen, parent_err_msg, node,
1910219104
buf_sprintf("libc headers not available; compilation does not link against libc"));
1910319105
}
19104-
for (size_t i = 0; i < errors.length; i += 1) {
19105-
ErrorMsg *err_msg = errors.at(i);
19106+
for (size_t i = 0; i < errors_len; i += 1) {
19107+
Stage2ErrorMsg *clang_err = &errors_ptr[i];
19108+
ErrorMsg *err_msg = err_msg_create_with_offset(
19109+
clang_err->filename_ptr ?
19110+
buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(),
19111+
clang_err->line, clang_err->column, clang_err->offset, clang_err->source,
19112+
buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len));
1910619113
err_msg_add_note(parent_err_msg, err_msg);
1910719114
}
1910819115

src/translate_c.cpp

Lines changed: 9 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,9 @@ struct TransScopeWhile {
7676
};
7777

7878
struct Context {
79-
ZigList<ErrorMsg *> *errors;
79+
AstNode *root;
8080
VisibMod visib_mod;
8181
bool want_export;
82-
AstNode *root;
8382
HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table;
8483
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
8584
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;
@@ -4897,13 +4896,14 @@ static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {
48974896
}
48984897
}
48994898

4900-
Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, const char **args_begin, const char **args_end,
4901-
Stage2TranslateMode mode, ZigList<ErrorMsg *> *errors)
4899+
Error parse_h_file(CodeGen *codegen, AstNode **out_root_node,
4900+
Stage2ErrorMsg **errors_ptr, size_t *errors_len,
4901+
const char **args_begin, const char **args_end,
4902+
Stage2TranslateMode mode, const char *resources_path)
49024903
{
49034904
Context context = {0};
49044905
Context *c = &context;
49054906
c->warnings_on = codegen->verbose_cimport;
4906-
c->errors = errors;
49074907
if (mode == Stage2TranslateModeImport) {
49084908
c->visib_mod = VisibModPub;
49094909
c->want_export = false;
@@ -4918,78 +4918,10 @@ Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, const char **args_
49184918
c->codegen = codegen;
49194919
c->global_scope = trans_scope_root_create(c);
49204920

4921-
4922-
clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions));
4923-
4924-
std::shared_ptr<clang::PCHContainerOperations> pch_container_ops = std::make_shared<clang::PCHContainerOperations>();
4925-
4926-
bool only_local_decls = true;
4927-
bool capture_diagnostics = true;
4928-
bool user_files_are_volatile = true;
4929-
bool allow_pch_with_compiler_errors = false;
4930-
bool single_file_parse = false;
4931-
bool for_serialization = false;
4932-
const char *resources_path = buf_ptr(codegen->zig_c_headers_dir);
4933-
std::unique_ptr<clang::ASTUnit> err_unit;
4934-
ZigClangASTUnit *ast_unit = reinterpret_cast<ZigClangASTUnit *>(clang::ASTUnit::LoadFromCommandLine(
4935-
args_begin, args_end,
4936-
pch_container_ops, diags, resources_path,
4937-
only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete,
4938-
false, false, allow_pch_with_compiler_errors, clang::SkipFunctionBodiesScope::None,
4939-
single_file_parse, user_files_are_volatile, for_serialization, clang::None, &err_unit,
4940-
nullptr));
4941-
4942-
// Early failures in LoadFromCommandLine may return with ErrUnit unset.
4943-
if (!ast_unit && !err_unit) {
4944-
return ErrorFileSystem;
4945-
}
4946-
4947-
if (diags->getClient()->getNumErrors() > 0) {
4948-
if (ast_unit) {
4949-
err_unit = std::unique_ptr<clang::ASTUnit>(reinterpret_cast<clang::ASTUnit *>(ast_unit));
4950-
}
4951-
4952-
for (clang::ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(),
4953-
it_end = err_unit->stored_diag_end();
4954-
it != it_end; ++it)
4955-
{
4956-
switch (it->getLevel()) {
4957-
case clang::DiagnosticsEngine::Ignored:
4958-
case clang::DiagnosticsEngine::Note:
4959-
case clang::DiagnosticsEngine::Remark:
4960-
case clang::DiagnosticsEngine::Warning:
4961-
continue;
4962-
case clang::DiagnosticsEngine::Error:
4963-
case clang::DiagnosticsEngine::Fatal:
4964-
break;
4965-
}
4966-
llvm::StringRef msg_str_ref = it->getMessage();
4967-
Buf *msg = string_ref_to_buf(msg_str_ref);
4968-
clang::FullSourceLoc fsl = it->getLocation();
4969-
if (fsl.hasManager()) {
4970-
clang::FileID file_id = fsl.getFileID();
4971-
clang::StringRef filename = fsl.getManager().getFilename(fsl);
4972-
unsigned line = fsl.getSpellingLineNumber() - 1;
4973-
unsigned column = fsl.getSpellingColumnNumber() - 1;
4974-
unsigned offset = fsl.getManager().getFileOffset(fsl);
4975-
const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
4976-
Buf *path;
4977-
if (filename.empty()) {
4978-
path = buf_alloc();
4979-
} else {
4980-
path = string_ref_to_buf(filename);
4981-
}
4982-
4983-
ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
4984-
4985-
c->errors->append(err_msg);
4986-
} else {
4987-
// NOTE the only known way this gets triggered right now is if you have a lot of errors
4988-
// clang emits "too many errors emitted, stopping now"
4989-
fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg));
4990-
}
4991-
}
4992-
4921+
ZigClangASTUnit *ast_unit = ZigClangLoadFromCommandLine(args_begin, args_end, errors_ptr, errors_len,
4922+
resources_path);
4923+
if (ast_unit == nullptr) {
4924+
if (*errors_len == 0) return ErrorNoMem;
49934925
return ErrorCCompileErrors;
49944926
}
49954927

src/translate_c.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
#include "all_types.hpp"
1313

14-
Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, const char **args_begin, const char **args_end,
15-
Stage2TranslateMode mode, ZigList<ErrorMsg *> *errors);
14+
Error parse_h_file(CodeGen *codegen, AstNode **out_root_node,
15+
Stage2ErrorMsg **errors_ptr, size_t *errors_len,
16+
const char **args_begin, const char **args_end,
17+
Stage2TranslateMode mode, const char *resources_path);
1618

1719
#endif

src/userland.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@
88
#include <string.h>
99

1010
Error stage2_translate_c(struct Stage2Ast **out_ast,
11-
const char **args_begin, const char **args_end, enum Stage2TranslateMode mode)
11+
struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len,
12+
const char **args_begin, const char **args_end, enum Stage2TranslateMode mode,
13+
const char *resources_path)
1214
{
1315
const char *msg = "stage0 called stage2_translate_c";
1416
stage2_panic(msg, strlen(msg));
1517
}
1618

19+
void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) {
20+
const char *msg = "stage0 called stage2_free_clang_errors";
21+
stage2_panic(msg, strlen(msg));
22+
}
23+
1724
void stage2_zen(const char **ptr, size_t *len) {
1825
const char *msg = "stage0 called stage2_zen";
1926
stage2_panic(msg, strlen(msg));

0 commit comments

Comments
 (0)