mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Part of #19063. Primarily, this moves Aro from deps/ to lib/compiler/ so that it can be lazily compiled from source. src/aro_translate_c.zig is moved to lib/compiler/aro_translate_c.zig and some of Zig CLI logic moved to a main() function there. aro_translate_c.zig becomes the "common" import for clang-based translate-c. Not all of the compiler was able to be detangled from Aro, however, so it still, for now, remains being compiled with the main compiler sources due to the clang-based translate-c depending on it. Once aro-based translate-c achieves feature parity with the clang-based translate-c implementation, the clang-based one can be removed from Zig. Aro made it unnecessarily difficult to depend on with these .def files and all these Zig module requirements. I looked at the .def files and made these observations: - The canonical source is llvm .def files. - Therefore there is an update process to sync with llvm that involves regenerating the .def files in Aro. - Therefore you might as well just regenerate the .zig files directly and check those into Aro. - Also with a small amount of tinkering, the file size on disk of these generated .zig files can be made many times smaller, without compromising type safety in the usage of the data. This would make things much easier on Zig as downstream project, particularly we could remove those pesky stubs when bootstrapping. I have gone ahead with these changes since they unblock me and I will have a chat with Vexu to see what he thinks.
200 lines
7.3 KiB
Zig
200 lines
7.3 KiB
Zig
const std = @import("std");
|
|
const mem = std.mem;
|
|
const Compilation = @import("../Compilation.zig");
|
|
const Pragma = @import("../Pragma.zig");
|
|
const Diagnostics = @import("../Diagnostics.zig");
|
|
const Preprocessor = @import("../Preprocessor.zig");
|
|
const Parser = @import("../Parser.zig");
|
|
const TokenIndex = @import("../Tree.zig").TokenIndex;
|
|
|
|
const GCC = @This();
|
|
|
|
pragma: Pragma = .{
|
|
.beforeParse = beforeParse,
|
|
.beforePreprocess = beforePreprocess,
|
|
.afterParse = afterParse,
|
|
.deinit = deinit,
|
|
.preprocessorHandler = preprocessorHandler,
|
|
.parserHandler = parserHandler,
|
|
.preserveTokens = preserveTokens,
|
|
},
|
|
original_options: Diagnostics.Options = .{},
|
|
options_stack: std.ArrayListUnmanaged(Diagnostics.Options) = .{},
|
|
|
|
const Directive = enum {
|
|
warning,
|
|
@"error",
|
|
diagnostic,
|
|
poison,
|
|
const Diagnostics = enum {
|
|
ignored,
|
|
warning,
|
|
@"error",
|
|
fatal,
|
|
push,
|
|
pop,
|
|
};
|
|
};
|
|
|
|
fn beforePreprocess(pragma: *Pragma, comp: *Compilation) void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
self.original_options = comp.diagnostics.options;
|
|
}
|
|
|
|
fn beforeParse(pragma: *Pragma, comp: *Compilation) void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
comp.diagnostics.options = self.original_options;
|
|
self.options_stack.items.len = 0;
|
|
}
|
|
|
|
fn afterParse(pragma: *Pragma, comp: *Compilation) void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
comp.diagnostics.options = self.original_options;
|
|
self.options_stack.items.len = 0;
|
|
}
|
|
|
|
pub fn init(allocator: mem.Allocator) !*Pragma {
|
|
var gcc = try allocator.create(GCC);
|
|
gcc.* = .{};
|
|
return &gcc.pragma;
|
|
}
|
|
|
|
fn deinit(pragma: *Pragma, comp: *Compilation) void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
self.options_stack.deinit(comp.gpa);
|
|
comp.gpa.destroy(self);
|
|
}
|
|
|
|
fn diagnosticHandler(self: *GCC, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {
|
|
const diagnostic_tok = pp.tokens.get(start_idx);
|
|
if (diagnostic_tok.id == .nl) return;
|
|
|
|
const diagnostic = std.meta.stringToEnum(Directive.Diagnostics, pp.expandedSlice(diagnostic_tok)) orelse
|
|
return error.UnknownPragma;
|
|
|
|
switch (diagnostic) {
|
|
.ignored, .warning, .@"error", .fatal => {
|
|
const str = Pragma.pasteTokens(pp, start_idx + 1) catch |err| switch (err) {
|
|
error.ExpectedStringLiteral => {
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .pragma_requires_string_literal,
|
|
.loc = diagnostic_tok.loc,
|
|
.extra = .{ .str = "GCC diagnostic" },
|
|
}, diagnostic_tok.expansionSlice());
|
|
},
|
|
else => |e| return e,
|
|
};
|
|
if (!mem.startsWith(u8, str, "-W")) {
|
|
const next = pp.tokens.get(start_idx + 1);
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .malformed_warning_check,
|
|
.loc = next.loc,
|
|
.extra = .{ .str = "GCC diagnostic" },
|
|
}, next.expansionSlice());
|
|
}
|
|
const new_kind: Diagnostics.Kind = switch (diagnostic) {
|
|
.ignored => .off,
|
|
.warning => .warning,
|
|
.@"error" => .@"error",
|
|
.fatal => .@"fatal error",
|
|
else => unreachable,
|
|
};
|
|
|
|
try pp.comp.diagnostics.set(str[2..], new_kind);
|
|
},
|
|
.push => try self.options_stack.append(pp.comp.gpa, pp.comp.diagnostics.options),
|
|
.pop => pp.comp.diagnostics.options = self.options_stack.popOrNull() orelse self.original_options,
|
|
}
|
|
}
|
|
|
|
fn preprocessorHandler(pragma: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) Pragma.Error!void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
const directive_tok = pp.tokens.get(start_idx + 1);
|
|
if (directive_tok.id == .nl) return;
|
|
|
|
const gcc_pragma = std.meta.stringToEnum(Directive, pp.expandedSlice(directive_tok)) orelse
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .unknown_gcc_pragma,
|
|
.loc = directive_tok.loc,
|
|
}, directive_tok.expansionSlice());
|
|
|
|
switch (gcc_pragma) {
|
|
.warning, .@"error" => {
|
|
const text = Pragma.pasteTokens(pp, start_idx + 2) catch |err| switch (err) {
|
|
error.ExpectedStringLiteral => {
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .pragma_requires_string_literal,
|
|
.loc = directive_tok.loc,
|
|
.extra = .{ .str = @tagName(gcc_pragma) },
|
|
}, directive_tok.expansionSlice());
|
|
},
|
|
else => |e| return e,
|
|
};
|
|
const extra = Diagnostics.Message.Extra{ .str = try pp.comp.diagnostics.arena.allocator().dupe(u8, text) };
|
|
const diagnostic_tag: Diagnostics.Tag = if (gcc_pragma == .warning) .pragma_warning_message else .pragma_error_message;
|
|
return pp.comp.addDiagnostic(
|
|
.{ .tag = diagnostic_tag, .loc = directive_tok.loc, .extra = extra },
|
|
directive_tok.expansionSlice(),
|
|
);
|
|
},
|
|
.diagnostic => return self.diagnosticHandler(pp, start_idx + 2) catch |err| switch (err) {
|
|
error.UnknownPragma => {
|
|
const tok = pp.tokens.get(start_idx + 2);
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .unknown_gcc_pragma_directive,
|
|
.loc = tok.loc,
|
|
}, tok.expansionSlice());
|
|
},
|
|
else => |e| return e,
|
|
},
|
|
.poison => {
|
|
var i: usize = 2;
|
|
while (true) : (i += 1) {
|
|
const tok = pp.tokens.get(start_idx + i);
|
|
if (tok.id == .nl) break;
|
|
|
|
if (!tok.id.isMacroIdentifier()) {
|
|
return pp.comp.addDiagnostic(.{
|
|
.tag = .pragma_poison_identifier,
|
|
.loc = tok.loc,
|
|
}, tok.expansionSlice());
|
|
}
|
|
const str = pp.expandedSlice(tok);
|
|
if (pp.defines.get(str) != null) {
|
|
try pp.comp.addDiagnostic(.{
|
|
.tag = .pragma_poison_macro,
|
|
.loc = tok.loc,
|
|
}, tok.expansionSlice());
|
|
}
|
|
try pp.poisoned_identifiers.put(str, {});
|
|
}
|
|
return;
|
|
},
|
|
}
|
|
}
|
|
|
|
fn parserHandler(pragma: *Pragma, p: *Parser, start_idx: TokenIndex) Compilation.Error!void {
|
|
var self = @fieldParentPtr(GCC, "pragma", pragma);
|
|
const directive_tok = p.pp.tokens.get(start_idx + 1);
|
|
if (directive_tok.id == .nl) return;
|
|
const name = p.pp.expandedSlice(directive_tok);
|
|
if (mem.eql(u8, name, "diagnostic")) {
|
|
return self.diagnosticHandler(p.pp, start_idx + 2) catch |err| switch (err) {
|
|
error.UnknownPragma => {}, // handled during preprocessing
|
|
error.StopPreprocessing => unreachable, // Only used by #pragma once
|
|
else => |e| return e,
|
|
};
|
|
}
|
|
}
|
|
|
|
fn preserveTokens(_: *Pragma, pp: *Preprocessor, start_idx: TokenIndex) bool {
|
|
const next = pp.tokens.get(start_idx + 1);
|
|
if (next.id != .nl) {
|
|
const name = pp.expandedSlice(next);
|
|
if (mem.eql(u8, name, "poison")) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|