diff --git a/CMakeLists.txt b/CMakeLists.txt index b40f360bca9f..64aa7d1bd406 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -448,7 +448,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp" "${CMAKE_SOURCE_DIR}/src/bigint.cpp" "${CMAKE_SOURCE_DIR}/src/buffer.cpp" - "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/cache_hash.cpp" "${CMAKE_SOURCE_DIR}/src/codegen.cpp" "${CMAKE_SOURCE_DIR}/src/compiler.cpp" @@ -465,7 +464,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/range_set.cpp" "${CMAKE_SOURCE_DIR}/src/target.cpp" "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" - "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" "${CMAKE_SOURCE_DIR}/src/util.cpp" "${ZIG_SOURCES_MEM_PROFILE}" ) diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index 8a0f677660e2..d67877b05117 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -224,7 +224,7 @@ test "crypto.chacha20 test vector sunscreen" { // Chacha20 is self-reversing. var plaintext: [114]u8 = undefined; chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); - testing.expect(mem.compare(u8, input, &plaintext) == mem.Compare.Equal); + testing.expect(mem.order(u8, input, &plaintext) == .eq); } // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 diff --git a/lib/std/http/headers.zig b/lib/std/http/headers.zig index 588ee7f79690..b1d047aeecf4 100644 --- a/lib/std/http/headers.zig +++ b/lib/std/http/headers.zig @@ -70,12 +70,12 @@ const HeaderEntry = struct { } // Sort lexicographically on header name - return mem.compare(u8, a.name, b.name) == mem.Compare.LessThan; + return mem.order(u8, a.name, b.name) == .lt; } // Sort lexicographically on header value if (!mem.eql(u8, a.value, b.value)) { - return mem.compare(u8, a.value, b.value) == mem.Compare.LessThan; + return mem.order(u8, a.value, b.value) == .lt; } // Doesn't matter here; need to pick something for sort consistency diff --git a/lib/std/math.zig b/lib/std/math.zig index a12bf5f4e944..051dc341a21f 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -926,9 +926,6 @@ test "minInt and maxInt" { } test "max value type" { - // If the type of maxInt(i32) was i32 then this implicit cast to - // u32 would not work. But since the value is a number literal, - // it works fine. const x: u32 = maxInt(i32); testing.expect(x == 2147483647); } @@ -944,7 +941,32 @@ test "math.mulWide" { testing.expect(mulWide(u8, 100, 100) == 10000); } -/// Not to be confused with `std.mem.Compare`. +/// See also `CompareOperator`. +pub const Order = enum { + /// Less than (`<`) + lt, + + /// Equal (`==`) + eq, + + /// Greater than (`>`) + gt, +}; + +/// Given two numbers, this function returns the order they are with respect to each other. +pub fn order(a: var, b: var) Order { + if (a == b) { + return .eq; + } else if (a < b) { + return .lt; + } else if (a > b) { + return .gt; + } else { + unreachable; + } +} + +/// See also `Order`. pub const CompareOperator = enum { /// Less than (`<`) lt, @@ -979,7 +1001,7 @@ pub fn compare(a: var, op: CompareOperator, b: var) bool { }; } -test "math.lt, et al < <= > >= between signed and unsigned" { +test "compare between signed and unsigned" { testing.expect(compare(@as(i8, -1), .lt, @as(u8, 255))); testing.expect(compare(@as(i8, 2), .gt, @as(u8, 1))); testing.expect(!compare(@as(i8, -1), .gte, @as(u8, 255))); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 133e3b8a2dca..48f4a68a5e43 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -239,12 +239,6 @@ pub const Allocator = struct { } }; -pub const Compare = enum { - LessThan, - Equal, - GreaterThan, -}; - /// Copy all of source into dest at position 0. /// dest.len must be >= source.len. /// dest.ptr must be <= src.ptr. @@ -297,46 +291,30 @@ test "mem.secureZero" { testing.expectEqualSlices(u8, a[0..], b[0..]); } -pub fn compare(comptime T: type, lhs: []const T, rhs: []const T) Compare { +pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order { const n = math.min(lhs.len, rhs.len); var i: usize = 0; while (i < n) : (i += 1) { - if (lhs[i] == rhs[i]) { - continue; - } else if (lhs[i] < rhs[i]) { - return Compare.LessThan; - } else if (lhs[i] > rhs[i]) { - return Compare.GreaterThan; - } else { - unreachable; + switch (math.order(lhs[i], rhs[i])) { + .eq => continue, + .lt => return .lt, + .gt => return .gt, } } - - if (lhs.len == rhs.len) { - return Compare.Equal; - } else if (lhs.len < rhs.len) { - return Compare.LessThan; - } else if (lhs.len > rhs.len) { - return Compare.GreaterThan; - } - unreachable; + return math.order(lhs.len, rhs.len); } -test "mem.compare" { - testing.expect(compare(u8, "abcd", "bee") == Compare.LessThan); - testing.expect(compare(u8, "abc", "abc") == Compare.Equal); - testing.expect(compare(u8, "abc", "abc0") == Compare.LessThan); - testing.expect(compare(u8, "", "") == Compare.Equal); - testing.expect(compare(u8, "", "a") == Compare.LessThan); +test "order" { + testing.expect(order(u8, "abcd", "bee") == .lt); + testing.expect(order(u8, "abc", "abc") == .eq); + testing.expect(order(u8, "abc", "abc0") == .lt); + testing.expect(order(u8, "", "") == .eq); + testing.expect(order(u8, "", "a") == .lt); } /// Returns true if lhs < rhs, false otherwise pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) bool { - var result = compare(T, lhs, rhs); - if (result == Compare.LessThan) { - return true; - } else - return false; + return order(T, lhs, rhs) == .lt; } test "mem.lessThan" { diff --git a/lib/std/rb.zig b/lib/std/rb.zig index 4180c7459c3c..c41a269a27f1 100644 --- a/lib/std/rb.zig +++ b/lib/std/rb.zig @@ -1,7 +1,7 @@ const std = @import("std.zig"); const assert = std.debug.assert; const testing = std.testing; -const mem = std.mem; // For mem.Compare +const Order = std.math.Order; const Color = enum(u1) { Black, @@ -132,7 +132,7 @@ pub const Node = struct { pub const Tree = struct { root: ?*Node, - compareFn: fn (*Node, *Node) mem.Compare, + compareFn: fn (*Node, *Node) Order, /// If you have a need for a version that caches this, please file a bug. pub fn first(tree: *Tree) ?*Node { @@ -389,7 +389,7 @@ pub const Tree = struct { var new = newconst; // I assume this can get optimized out if the caller already knows. - if (tree.compareFn(old, new) != mem.Compare.Equal) return ReplaceError.NotEqual; + if (tree.compareFn(old, new) != .eq) return ReplaceError.NotEqual; if (old.getParent()) |parent| { parent.setChild(new, parent.left == old); @@ -404,7 +404,7 @@ pub const Tree = struct { new.* = old.*; } - pub fn init(tree: *Tree, f: fn (*Node, *Node) mem.Compare) void { + pub fn init(tree: *Tree, f: fn (*Node, *Node) Order) void { tree.root = null; tree.compareFn = f; } @@ -469,19 +469,21 @@ fn doLookup(key: *Node, tree: *Tree, pparent: *?*Node, is_left: *bool) ?*Node { is_left.* = false; while (maybe_node) |node| { - var res: mem.Compare = tree.compareFn(node, key); - if (res == mem.Compare.Equal) { + const res = tree.compareFn(node, key); + if (res == .eq) { return node; } pparent.* = node; - if (res == mem.Compare.GreaterThan) { - is_left.* = true; - maybe_node = node.left; - } else if (res == mem.Compare.LessThan) { - is_left.* = false; - maybe_node = node.right; - } else { - unreachable; + switch (res) { + .gt => { + is_left.* = true; + maybe_node = node.left; + }, + .lt => { + is_left.* = false; + maybe_node = node.right; + }, + .eq => unreachable, // handled above } } return null; @@ -496,16 +498,16 @@ fn testGetNumber(node: *Node) *testNumber { return @fieldParentPtr(testNumber, "node", node); } -fn testCompare(l: *Node, r: *Node) mem.Compare { +fn testCompare(l: *Node, r: *Node) Order { var left = testGetNumber(l); var right = testGetNumber(r); if (left.value < right.value) { - return mem.Compare.LessThan; + return .lt; } else if (left.value == right.value) { - return mem.Compare.Equal; + return .eq; } else if (left.value > right.value) { - return mem.Compare.GreaterThan; + return .gt; } unreachable; } diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 349ae914c4c5..adbcef165e20 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -13,6 +13,7 @@ pub const Tree = struct { root_node: *Node.Root, arena_allocator: std.heap.ArenaAllocator, errors: ErrorList, + generated: bool = false, pub const TokenList = SegmentedList(Token, 64); pub const ErrorList = SegmentedList(Error, 0); @@ -58,6 +59,8 @@ pub const Tree = struct { .line_start = start_index, .line_end = self.source.len, }; + if (self.generated) + return loc; const token_start = token.start; for (self.source[start_index..]) |c, i| { if (i + start_index == token_start) { @@ -581,7 +584,7 @@ pub const Node = struct { } pub const Root = struct { - base: Node = Node {.id = .Root}, + base: Node = Node{ .id = .Root }, decls: DeclList, eof_token: TokenIndex, @@ -604,7 +607,7 @@ pub const Node = struct { }; pub const VarDecl = struct { - base: Node = Node {.id = .VarDecl}, + base: Node = Node{ .id = .VarDecl }, doc_comments: ?*DocComment, visib_token: ?TokenIndex, thread_local_token: ?TokenIndex, @@ -661,7 +664,7 @@ pub const Node = struct { }; pub const Use = struct { - base: Node = Node {.id = .Use}, + base: Node = Node{ .id = .Use }, doc_comments: ?*DocComment, visib_token: ?TokenIndex, use_token: TokenIndex, @@ -688,7 +691,7 @@ pub const Node = struct { }; pub const ErrorSetDecl = struct { - base: Node = Node {.id = .ErrorSetDecl}, + base: Node = Node{ .id = .ErrorSetDecl }, error_token: TokenIndex, decls: DeclList, rbrace_token: TokenIndex, @@ -714,7 +717,7 @@ pub const Node = struct { }; pub const ContainerDecl = struct { - base: Node = Node {.id = .ContainerDecl}, + base: Node = Node{ .id = .ContainerDecl }, layout_token: ?TokenIndex, kind_token: TokenIndex, init_arg_expr: InitArg, @@ -801,7 +804,7 @@ pub const Node = struct { }; pub const ErrorTag = struct { - base: Node = Node {.id = .ErrorTag}, + base: Node = Node{ .id = .ErrorTag }, doc_comments: ?*DocComment, name_token: TokenIndex, @@ -826,7 +829,7 @@ pub const Node = struct { }; pub const Identifier = struct { - base: Node = Node {.id = .Identifier}, + base: Node = Node{ .id = .Identifier }, token: TokenIndex, pub fn iterate(self: *Identifier, index: usize) ?*Node { @@ -843,7 +846,7 @@ pub const Node = struct { }; pub const FnProto = struct { - base: Node = Node {.id = .FnProto}, + base: Node = Node{ .id = .FnProto }, doc_comments: ?*DocComment, visib_token: ?TokenIndex, fn_token: TokenIndex, @@ -925,7 +928,7 @@ pub const Node = struct { }; pub const AnyFrameType = struct { - base: Node = Node {.id = .AnyFrameType}, + base: Node = Node{ .id = .AnyFrameType }, anyframe_token: TokenIndex, result: ?Result, @@ -956,7 +959,7 @@ pub const Node = struct { }; pub const ParamDecl = struct { - base: Node = Node {.id = .ParamDecl}, + base: Node = Node{ .id = .ParamDecl }, doc_comments: ?*DocComment, comptime_token: ?TokenIndex, noalias_token: ?TokenIndex, @@ -989,7 +992,7 @@ pub const Node = struct { }; pub const Block = struct { - base: Node = Node {.id = .Block}, + base: Node = Node{ .id = .Block }, label: ?TokenIndex, lbrace: TokenIndex, statements: StatementList, @@ -1020,7 +1023,7 @@ pub const Node = struct { }; pub const Defer = struct { - base: Node = Node {.id = .Defer}, + base: Node = Node{ .id = .Defer }, defer_token: TokenIndex, expr: *Node, @@ -1043,7 +1046,7 @@ pub const Node = struct { }; pub const Comptime = struct { - base: Node = Node {.id = .Comptime}, + base: Node = Node{ .id = .Comptime }, doc_comments: ?*DocComment, comptime_token: TokenIndex, expr: *Node, @@ -1067,7 +1070,7 @@ pub const Node = struct { }; pub const Payload = struct { - base: Node = Node {.id = .Payload}, + base: Node = Node{ .id = .Payload }, lpipe: TokenIndex, error_symbol: *Node, rpipe: TokenIndex, @@ -1091,7 +1094,7 @@ pub const Node = struct { }; pub const PointerPayload = struct { - base: Node = Node {.id = .PointerPayload}, + base: Node = Node{ .id = .PointerPayload }, lpipe: TokenIndex, ptr_token: ?TokenIndex, value_symbol: *Node, @@ -1116,7 +1119,7 @@ pub const Node = struct { }; pub const PointerIndexPayload = struct { - base: Node = Node {.id = .PointerIndexPayload}, + base: Node = Node{ .id = .PointerIndexPayload }, lpipe: TokenIndex, ptr_token: ?TokenIndex, value_symbol: *Node, @@ -1147,7 +1150,7 @@ pub const Node = struct { }; pub const Else = struct { - base: Node = Node {.id = .Else}, + base: Node = Node{ .id = .Else }, else_token: TokenIndex, payload: ?*Node, body: *Node, @@ -1176,7 +1179,7 @@ pub const Node = struct { }; pub const Switch = struct { - base: Node = Node {.id = .Switch}, + base: Node = Node{ .id = .Switch }, switch_token: TokenIndex, expr: *Node, @@ -1208,7 +1211,7 @@ pub const Node = struct { }; pub const SwitchCase = struct { - base: Node = Node {.id = .SwitchCase}, + base: Node = Node{ .id = .SwitchCase }, items: ItemList, arrow_token: TokenIndex, payload: ?*Node, @@ -1243,7 +1246,7 @@ pub const Node = struct { }; pub const SwitchElse = struct { - base: Node = Node {.id = .SwitchElse}, + base: Node = Node{ .id = .SwitchElse }, token: TokenIndex, pub fn iterate(self: *SwitchElse, index: usize) ?*Node { @@ -1260,7 +1263,7 @@ pub const Node = struct { }; pub const While = struct { - base: Node = Node {.id = .While}, + base: Node = Node{ .id = .While }, label: ?TokenIndex, inline_token: ?TokenIndex, while_token: TokenIndex, @@ -1319,7 +1322,7 @@ pub const Node = struct { }; pub const For = struct { - base: Node = Node {.id = .For}, + base: Node = Node{ .id = .For }, label: ?TokenIndex, inline_token: ?TokenIndex, for_token: TokenIndex, @@ -1370,7 +1373,7 @@ pub const Node = struct { }; pub const If = struct { - base: Node = Node {.id = .If}, + base: Node = Node{ .id = .If }, if_token: TokenIndex, condition: *Node, payload: ?*Node, @@ -1413,7 +1416,7 @@ pub const Node = struct { }; pub const InfixOp = struct { - base: Node = Node {.id = .InfixOp}, + base: Node = Node{ .id = .InfixOp }, op_token: TokenIndex, lhs: *Node, op: Op, @@ -1646,7 +1649,7 @@ pub const Node = struct { }; pub const FieldInitializer = struct { - base: Node = Node {.id = .FieldInitializer}, + base: Node = Node{ .id = .FieldInitializer }, period_token: TokenIndex, name_token: TokenIndex, expr: *Node, @@ -1670,7 +1673,7 @@ pub const Node = struct { }; pub const SuffixOp = struct { - base: Node = Node {.id = .SuffixOp}, + base: Node = Node{ .id = .SuffixOp }, lhs: Lhs, op: Op, rtoken: TokenIndex, @@ -1771,7 +1774,7 @@ pub const Node = struct { }; pub const GroupedExpression = struct { - base: Node = Node {.id = .GroupedExpression}, + base: Node = Node{ .id = .GroupedExpression }, lparen: TokenIndex, expr: *Node, rparen: TokenIndex, @@ -1795,7 +1798,7 @@ pub const Node = struct { }; pub const ControlFlowExpression = struct { - base: Node = Node {.id = .ControlFlowExpression}, + base: Node = Node{ .id = .ControlFlowExpression }, ltoken: TokenIndex, kind: Kind, rhs: ?*Node, @@ -1861,7 +1864,7 @@ pub const Node = struct { }; pub const Suspend = struct { - base: Node = Node {.id = .Suspend}, + base: Node = Node{ .id = .Suspend }, suspend_token: TokenIndex, body: ?*Node, @@ -1890,7 +1893,7 @@ pub const Node = struct { }; pub const IntegerLiteral = struct { - base: Node = Node {.id = .IntegerLiteral}, + base: Node = Node{ .id = .IntegerLiteral }, token: TokenIndex, pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node { @@ -1907,7 +1910,7 @@ pub const Node = struct { }; pub const EnumLiteral = struct { - base: Node = Node {.id = .EnumLiteral}, + base: Node = Node{ .id = .EnumLiteral }, dot: TokenIndex, name: TokenIndex, @@ -1925,7 +1928,7 @@ pub const Node = struct { }; pub const FloatLiteral = struct { - base: Node = Node {.id = .FloatLiteral}, + base: Node = Node{ .id = .FloatLiteral }, token: TokenIndex, pub fn iterate(self: *FloatLiteral, index: usize) ?*Node { @@ -1942,7 +1945,7 @@ pub const Node = struct { }; pub const BuiltinCall = struct { - base: Node = Node {.id = .BuiltinCall}, + base: Node = Node{ .id = .BuiltinCall }, builtin_token: TokenIndex, params: ParamList, rparen_token: TokenIndex, @@ -1968,7 +1971,7 @@ pub const Node = struct { }; pub const StringLiteral = struct { - base: Node = Node {.id = .StringLiteral}, + base: Node = Node{ .id = .StringLiteral }, token: TokenIndex, pub fn iterate(self: *StringLiteral, index: usize) ?*Node { @@ -1985,7 +1988,7 @@ pub const Node = struct { }; pub const MultilineStringLiteral = struct { - base: Node = Node {.id = .MultilineStringLiteral}, + base: Node = Node{ .id = .MultilineStringLiteral }, lines: LineList, pub const LineList = SegmentedList(TokenIndex, 4); @@ -2004,7 +2007,7 @@ pub const Node = struct { }; pub const CharLiteral = struct { - base: Node = Node {.id = .CharLiteral}, + base: Node = Node{ .id = .CharLiteral }, token: TokenIndex, pub fn iterate(self: *CharLiteral, index: usize) ?*Node { @@ -2021,7 +2024,7 @@ pub const Node = struct { }; pub const BoolLiteral = struct { - base: Node = Node {.id = .BoolLiteral}, + base: Node = Node{ .id = .BoolLiteral }, token: TokenIndex, pub fn iterate(self: *BoolLiteral, index: usize) ?*Node { @@ -2038,7 +2041,7 @@ pub const Node = struct { }; pub const NullLiteral = struct { - base: Node = Node {.id = .NullLiteral}, + base: Node = Node{ .id = .NullLiteral }, token: TokenIndex, pub fn iterate(self: *NullLiteral, index: usize) ?*Node { @@ -2055,7 +2058,7 @@ pub const Node = struct { }; pub const UndefinedLiteral = struct { - base: Node = Node {.id = .UndefinedLiteral}, + base: Node = Node{ .id = .UndefinedLiteral }, token: TokenIndex, pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node { @@ -2072,7 +2075,7 @@ pub const Node = struct { }; pub const AsmOutput = struct { - base: Node = Node {.id = .AsmOutput}, + base: Node = Node{ .id = .AsmOutput }, lbracket: TokenIndex, symbolic_name: *Node, constraint: *Node, @@ -2117,7 +2120,7 @@ pub const Node = struct { }; pub const AsmInput = struct { - base: Node = Node {.id = .AsmInput}, + base: Node = Node{ .id = .AsmInput }, lbracket: TokenIndex, symbolic_name: *Node, constraint: *Node, @@ -2149,7 +2152,7 @@ pub const Node = struct { }; pub const Asm = struct { - base: Node = Node {.id = .Asm}, + base: Node = Node{ .id = .Asm }, asm_token: TokenIndex, volatile_token: ?TokenIndex, template: *Node, @@ -2184,7 +2187,7 @@ pub const Node = struct { }; pub const Unreachable = struct { - base: Node = Node {.id = .Unreachable}, + base: Node = Node{ .id = .Unreachable }, token: TokenIndex, pub fn iterate(self: *Unreachable, index: usize) ?*Node { @@ -2201,7 +2204,7 @@ pub const Node = struct { }; pub const ErrorType = struct { - base: Node = Node {.id = .ErrorType}, + base: Node = Node{ .id = .ErrorType }, token: TokenIndex, pub fn iterate(self: *ErrorType, index: usize) ?*Node { @@ -2235,7 +2238,7 @@ pub const Node = struct { }; pub const DocComment = struct { - base: Node = Node {.id = .DocComment}, + base: Node = Node{ .id = .DocComment }, lines: LineList, pub const LineList = SegmentedList(TokenIndex, 4); @@ -2254,7 +2257,7 @@ pub const Node = struct { }; pub const TestDecl = struct { - base: Node = Node {.id = .TestDecl}, + base: Node = Node{ .id = .TestDecl }, doc_comments: ?*DocComment, test_token: TokenIndex, name: *Node, diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index d65d9bfc570c..6e1ee4a601c7 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -643,7 +643,7 @@ fn renderExpression( }, .ArrayAccess => |index_expr| { - const lbracket = tree.prevToken(index_expr.firstToken()); + const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken()); const rbracket = tree.nextToken(index_expr.lastToken()); try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); diff --git a/src-self-hosted/c_tokenizer.zig b/src-self-hosted/c_tokenizer.zig index ba4446756502..0b234ec7b957 100644 --- a/src-self-hosted/c_tokenizer.zig +++ b/src-self-hosted/c_tokenizer.zig @@ -8,7 +8,7 @@ pub const TokenList = std.SegmentedList(CToken, 32); pub const CToken = struct { id: Id, - bytes: []const u8, + bytes: []const u8 = "", num_lit_suffix: NumLitSuffix = .None, pub const Id = enum { @@ -17,20 +17,33 @@ pub const CToken = struct { NumLitInt, NumLitFloat, Identifier, + Plus, Minus, Slash, LParen, RParen, Eof, Dot, - Asterisk, - Bang, - Tilde, - Shl, - Lt, + Asterisk, // * + Ampersand, // & + And, // && + Assign, // = + Or, // || + Bang, // ! + Tilde, // ~ + Shl, // << + Shr, // >> + Lt, // < + Lte, // <= + Gt, // > + Gte, // >= + Eq, // == + Ne, // != + Increment, // ++ + Decrement, // -- Comma, Fn, - Arrow, + Arrow, // -> LBrace, RBrace, Pipe, @@ -225,7 +238,14 @@ fn zigifyEscapeSequences(ctx: *Context, loc: ZigClangSourceLocation, name: []con fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*:0]const u8, i: *usize) !CToken { var state: enum { Start, - GotLt, + SawLt, + SawGt, + SawPlus, + SawMinus, + SawAmpersand, + SawPipe, + SawBang, + SawEq, CharLit, OpenComment, Comment, @@ -235,7 +255,7 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: Identifier, Decimal, Octal, - GotZero, + SawZero, Hex, Bin, Float, @@ -246,7 +266,6 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: NumLitIntSuffixL, NumLitIntSuffixLL, NumLitIntSuffixUL, - Minus, Done, } = .Start; @@ -267,7 +286,7 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: .Hex, .Bin, .Octal, - .GotZero, + .SawZero, .Float, .FloatExp, => { @@ -275,13 +294,19 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: return result; }, .Start, - .Minus, + .SawMinus, .Done, .NumLitIntSuffixU, .NumLitIntSuffixL, .NumLitIntSuffixUL, .NumLitIntSuffixLL, - .GotLt, + .SawLt, + .SawGt, + .SawPlus, + .SawAmpersand, + .SawPipe, + .SawBang, + .SawEq, => { return result; }, @@ -333,7 +358,7 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: begin_index = i.*; }, '0' => { - state = .GotZero; + state = .SawZero; result.id = .NumLitInt; begin_index = i.*; }, @@ -343,7 +368,11 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: }, '<' => { result.id = .Lt; - state = .GotLt; + state = .SawLt; + }, + '>' => { + result.id = .Gt; + state = .SawGt; }, '(' => { result.id = .LParen; @@ -357,18 +386,26 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: result.id = .Asterisk; state = .Done; }, + '+' => { + result.id = .Plus; + state = .SawPlus; + }, '-' => { - state = .Minus; result.id = .Minus; + state = .SawMinus; }, '!' => { result.id = .Bang; - state = .Done; + state = .SawBang; }, '~' => { result.id = .Tilde; state = .Done; }, + '=' => { + result.id = .Assign; + state = .SawEq; + }, ',' => { result.id = .Comma; state = .Done; @@ -383,7 +420,11 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: }, '|' => { result.id = .Pipe; - state = .Done; + state = .SawPipe; + }, + '&' => { + result.id = .Ampersand; + state = .SawAmpersand; }, '?' => { result.id = .QuestionMark; @@ -400,26 +441,88 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: } }, .Done => return result, - .Minus => { + .SawMinus => { switch (c) { '>' => { result.id = .Arrow; state = .Done; }, - else => { - return result; + '-' => { + result.id = .Decrement; + state = .Done; }, + else => return result, } }, - .GotLt => { + .SawPlus => { + switch (c) { + '+' => { + result.id = .Increment; + state = .Done; + }, + else => return result, + } + }, + .SawLt => { switch (c) { '<' => { result.id = .Shl; state = .Done; }, - else => { - return result; + '=' => { + result.id = .Lte; + state = .Done; + }, + else => return result, + } + }, + .SawGt => { + switch (c) { + '>' => { + result.id = .Shr; + state = .Done; + }, + '=' => { + result.id = .Gte; + state = .Done; + }, + else => return result, + } + }, + .SawPipe => { + switch (c) { + '|' => { + result.id = .Or; + state = .Done; + }, + else => return result, + } + }, + .SawAmpersand => { + switch (c) { + '&' => { + result.id = .And; + state = .Done; + }, + else => return result, + } + }, + .SawBang => { + switch (c) { + '=' => { + result.id = .Ne; + state = .Done; }, + else => return result, + } + }, + .SawEq => { + switch (c) { + '=' => { + result.id = .Eq; + state = .Done; + }, + else => return result, } }, .Float => { @@ -454,7 +557,7 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: '0'...'9' => { state = .FloatExp; }, - else => { + else => { try failDecl(ctx, loc, name, "macro tokenizing failed: expected a digit or '+' or '-'", .{}); return error.TokenizingFailed; }, @@ -514,7 +617,7 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: }, } }, - .GotZero => { + .SawZero => { switch (c) { 'x', 'X' => { state = .Hex; @@ -726,76 +829,114 @@ fn next(ctx: *Context, loc: ZigClangSourceLocation, name: []const u8, chars: [*: unreachable; } +fn expectTokens(tl: *TokenList, src: [*:0]const u8, expected: []CToken) void { + // these can be undefined since they are only used for error reporting + tokenizeCMacro(undefined, undefined, undefined, tl, src) catch unreachable; + var it = tl.iterator(0); + for (expected) |t| { + var tok = it.next().?; + std.testing.expectEqual(t.id, tok.id); + if (t.bytes.len > 0) { + //std.debug.warn(" {} = {}\n", .{tok.bytes, t.bytes}); + std.testing.expectEqualSlices(u8, tok.bytes, t.bytes); + } + if (t.num_lit_suffix != .None) { + std.testing.expectEqual(t.num_lit_suffix, tok.num_lit_suffix); + } + } + std.testing.expect(it.next() == null); + tl.shrink(0); +} + test "tokenize macro" { var tl = TokenList.init(std.heap.page_allocator); defer tl.deinit(); - const src = "TEST(0\n"; - try tokenizeCMacro(&tl, src); - var it = tl.iterator(0); - expect(it.next().?.id == .Identifier); - expect(it.next().?.id == .Fn); - expect(it.next().?.id == .LParen); - expect(std.mem.eql(u8, it.next().?.bytes, "0")); - expect(it.next().?.id == .Eof); - expect(it.next() == null); - tl.shrink(0); + expectTokens(&tl, "TEST(0\n", &[_]CToken{ + .{ .id = .Identifier, .bytes = "TEST" }, + .{ .id = .Fn }, + .{ .id = .LParen }, + .{ .id = .NumLitInt, .bytes = "0" }, + .{ .id = .Eof }, + }); - const src2 = "__FLT_MIN_10_EXP__ -37\n"; - try tokenizeCMacro(&tl, src2); - it = tl.iterator(0); - expect(std.mem.eql(u8, it.next().?.bytes, "__FLT_MIN_10_EXP__")); - expect(it.next().?.id == .Minus); - expect(std.mem.eql(u8, it.next().?.bytes, "37")); - expect(it.next().?.id == .Eof); - expect(it.next() == null); - tl.shrink(0); + expectTokens(&tl, "__FLT_MIN_10_EXP__ -37\n", &[_]CToken{ + .{ .id = .Identifier, .bytes = "__FLT_MIN_10_EXP__" }, + .{ .id = .Minus }, + .{ .id = .NumLitInt, .bytes = "37" }, + .{ .id = .Eof }, + }); - const src3 = "__llvm__ 1\n#define"; - try tokenizeCMacro(&tl, src3); - it = tl.iterator(0); - expect(std.mem.eql(u8, it.next().?.bytes, "__llvm__")); - expect(std.mem.eql(u8, it.next().?.bytes, "1")); - expect(it.next().?.id == .Eof); - expect(it.next() == null); - tl.shrink(0); + expectTokens(&tl, "__llvm__ 1\n#define", &[_]CToken{ + .{ .id = .Identifier, .bytes = "__llvm__" }, + .{ .id = .NumLitInt, .bytes = "1" }, + .{ .id = .Eof }, + }); - const src4 = "TEST 2"; - try tokenizeCMacro(&tl, src4); - it = tl.iterator(0); - expect(it.next().?.id == .Identifier); - expect(std.mem.eql(u8, it.next().?.bytes, "2")); - expect(it.next().?.id == .Eof); - expect(it.next() == null); - tl.shrink(0); + expectTokens(&tl, "TEST 2", &[_]CToken{ + .{ .id = .Identifier, .bytes = "TEST" }, + .{ .id = .NumLitInt, .bytes = "2" }, + .{ .id = .Eof }, + }); - const src5 = "FOO 0ull"; - try tokenizeCMacro(&tl, src5); - it = tl.iterator(0); - expect(it.next().?.id == .Identifier); - expect(std.mem.eql(u8, it.next().?.bytes, "0")); - expect(it.next().?.id == .Eof); - expect(it.next() == null); - tl.shrink(0); + expectTokens(&tl, "FOO 0ull", &[_]CToken{ + .{ .id = .Identifier, .bytes = "FOO" }, + .{ .id = .NumLitInt, .bytes = "0", .num_lit_suffix = .LLU }, + .{ .id = .Eof }, + }); +} + +test "tokenize macro ops" { + var tl = TokenList.init(std.heap.page_allocator); + defer tl.deinit(); + + expectTokens(&tl, "ADD A + B", &[_]CToken{ + .{ .id = .Identifier, .bytes = "ADD" }, + .{ .id = .Identifier, .bytes = "A" }, + .{ .id = .Plus }, + .{ .id = .Identifier, .bytes = "B" }, + .{ .id = .Eof }, + }); + + expectTokens(&tl, "ADD (A) + B", &[_]CToken{ + .{ .id = .Identifier, .bytes = "ADD" }, + .{ .id = .LParen }, + .{ .id = .Identifier, .bytes = "A" }, + .{ .id = .RParen }, + .{ .id = .Plus }, + .{ .id = .Identifier, .bytes = "B" }, + .{ .id = .Eof }, + }); + + expectTokens(&tl, "ADD (A) + B", &[_]CToken{ + .{ .id = .Identifier, .bytes = "ADD" }, + .{ .id = .LParen }, + .{ .id = .Identifier, .bytes = "A" }, + .{ .id = .RParen }, + .{ .id = .Plus }, + .{ .id = .Identifier, .bytes = "B" }, + .{ .id = .Eof }, + }); } test "escape sequences" { var buf: [1024]u8 = undefined; var alloc = std.heap.FixedBufferAllocator.init(buf[0..]); const a = &alloc.allocator; - expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{ + // these can be undefined since they are only used for error reporting + expect(std.mem.eql(u8, (try zigifyEscapeSequences(undefined, undefined, undefined, a, .{ .id = .StrLit, .bytes = "\\x0077", })).bytes, "\\x77")); - expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{ + expect(std.mem.eql(u8, (try zigifyEscapeSequences(undefined, undefined, undefined, a, .{ .id = .StrLit, .bytes = "\\24500", })).bytes, "\\xa500")); - expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{ + expect(std.mem.eql(u8, (try zigifyEscapeSequences(undefined, undefined, undefined, a, .{ .id = .StrLit, .bytes = "\\x0077 abc", })).bytes, "\\x77 abc")); - expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{ + expect(std.mem.eql(u8, (try zigifyEscapeSequences(undefined, undefined, undefined, a, .{ .id = .StrLit, .bytes = "\\045abc", })).bytes, "\\x25abc")); diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 87970168e8f8..3eb2d6400593 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -43,6 +43,7 @@ pub const struct_ZigClangImplicitCastExpr = @OpaqueType(); pub const struct_ZigClangIncompleteArrayType = @OpaqueType(); pub const struct_ZigClangIntegerLiteral = @OpaqueType(); pub const struct_ZigClangMacroDefinitionRecord = @OpaqueType(); +pub const struct_ZigClangMacroExpansion = @OpaqueType(); pub const struct_ZigClangMacroQualifiedType = @OpaqueType(); pub const struct_ZigClangMemberExpr = @OpaqueType(); pub const struct_ZigClangNamedDecl = @OpaqueType(); @@ -803,8 +804,8 @@ pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *cons pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; -pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass; -pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType; +pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass; +pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType; pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation; pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr; pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr; @@ -831,6 +832,8 @@ pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bo pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass; pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl; pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt; +pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool; +pub extern fn ZigClangFunctionDecl_isInlineSpecified(self: *const ZigClangFunctionDecl) bool; pub extern fn ZigClangBuiltinType_getKind(self: *const struct_ZigClangBuiltinType) ZigClangBuiltinTypeKind; @@ -889,6 +892,7 @@ pub const ZigClangImplicitCastExpr = struct_ZigClangImplicitCastExpr; pub const ZigClangIncompleteArrayType = struct_ZigClangIncompleteArrayType; pub const ZigClangIntegerLiteral = struct_ZigClangIntegerLiteral; pub const ZigClangMacroDefinitionRecord = struct_ZigClangMacroDefinitionRecord; +pub const ZigClangMacroExpansion = struct_ZigClangMacroExpansion; pub const ZigClangMacroQualifiedType = struct_ZigClangMacroQualifiedType; pub const ZigClangMemberExpr = struct_ZigClangMemberExpr; pub const ZigClangNamedDecl = struct_ZigClangNamedDecl; @@ -1058,6 +1062,8 @@ pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClang pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; +pub extern fn ZigClangMacroExpansion_getDefinition(*const ZigClangMacroExpansion) *const ZigClangMacroDefinitionRecord; + pub extern fn ZigClangIfStmt_getThen(*const ZigClangIfStmt) *const ZigClangStmt; pub extern fn ZigClangIfStmt_getElse(*const ZigClangIfStmt) ?*const ZigClangStmt; pub extern fn ZigClangIfStmt_getCond(*const ZigClangIfStmt) *const ZigClangStmt; diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 38c4ce14a1a2..afe4d10c654f 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -119,11 +119,11 @@ fn linkDiagCallbackErrorable(ctx: *Context, msg: []const u8) !void { fn toExternObjectFormatType(ofmt: ObjectFormat) c.ZigLLVM_ObjectFormatType { return switch (ofmt) { - .unknown => c.ZigLLVM_UnknownObjectFormat, - .coff => c.ZigLLVM_COFF, - .elf => c.ZigLLVM_ELF, - .macho => c.ZigLLVM_MachO, - .wasm => c.ZigLLVM_Wasm, + .unknown => .ZigLLVM_UnknownObjectFormat, + .coff => .ZigLLVM_COFF, + .elf => .ZigLLVM_ELF, + .macho => .ZigLLVM_MachO, + .wasm => .ZigLLVM_Wasm, }; } diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 040bcdc51adf..41599682526f 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -226,24 +226,24 @@ pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction; pub const VerifierFailureAction = c.LLVMVerifierFailureAction; -pub const CodeGenLevelNone = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelNone; -pub const CodeGenLevelLess = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelLess; -pub const CodeGenLevelDefault = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault; -pub const CodeGenLevelAggressive = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive; +pub const CodeGenLevelNone = CodeGenOptLevel.LLVMCodeGenLevelNone; +pub const CodeGenLevelLess = CodeGenOptLevel.LLVMCodeGenLevelLess; +pub const CodeGenLevelDefault = CodeGenOptLevel.LLVMCodeGenLevelDefault; +pub const CodeGenLevelAggressive = CodeGenOptLevel.LLVMCodeGenLevelAggressive; pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel; -pub const RelocDefault = c.LLVMRelocMode.LLVMRelocDefault; -pub const RelocStatic = c.LLVMRelocMode.LLVMRelocStatic; -pub const RelocPIC = c.LLVMRelocMode.LLVMRelocPIC; -pub const RelocDynamicNoPic = c.LLVMRelocMode.LLVMRelocDynamicNoPic; +pub const RelocDefault = RelocMode.LLVMRelocDefault; +pub const RelocStatic = RelocMode.LLVMRelocStatic; +pub const RelocPIC = RelocMode.LLVMRelocPIC; +pub const RelocDynamicNoPic = RelocMode.LLVMRelocDynamicNoPic; pub const RelocMode = c.LLVMRelocMode; -pub const CodeModelDefault = c.LLVMCodeModel.LLVMCodeModelDefault; -pub const CodeModelJITDefault = c.LLVMCodeModel.LLVMCodeModelJITDefault; -pub const CodeModelSmall = c.LLVMCodeModel.LLVMCodeModelSmall; -pub const CodeModelKernel = c.LLVMCodeModel.LLVMCodeModelKernel; -pub const CodeModelMedium = c.LLVMCodeModel.LLVMCodeModelMedium; -pub const CodeModelLarge = c.LLVMCodeModel.LLVMCodeModelLarge; +pub const CodeModelDefault = CodeModel.LLVMCodeModelDefault; +pub const CodeModelJITDefault = CodeModel.LLVMCodeModelJITDefault; +pub const CodeModelSmall = CodeModel.LLVMCodeModelSmall; +pub const CodeModelKernel = CodeModel.LLVMCodeModelKernel; +pub const CodeModelMedium = CodeModel.LLVMCodeModelMedium; +pub const CodeModelLarge = CodeModel.LLVMCodeModelLarge; pub const CodeModel = c.LLVMCodeModel; pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly; @@ -251,13 +251,13 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary; pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr; pub const EmitOutputType = c.ZigLLVM_EmitOutputType; -pub const CCallConv = c.LLVMCCallConv; -pub const FastCallConv = c.LLVMFastCallConv; -pub const ColdCallConv = c.LLVMColdCallConv; -pub const WebKitJSCallConv = c.LLVMWebKitJSCallConv; -pub const AnyRegCallConv = c.LLVMAnyRegCallConv; -pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv; -pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv; +pub const CCallConv = CallConv.LLVMCCallConv; +pub const FastCallConv = CallConv.LLVMFastCallConv; +pub const ColdCallConv = CallConv.LLVMColdCallConv; +pub const WebKitJSCallConv = CallConv.LLVMWebKitJSCallConv; +pub const AnyRegCallConv = CallConv.LLVMAnyRegCallConv; +pub const X86StdcallCallConv = CallConv.LLVMX86StdcallCallConv; +pub const X86FastcallCallConv = CallConv.LLVMX86FastcallCallConv; pub const CallConv = c.LLVMCallConv; pub const CallAttr = extern enum { @@ -288,6 +288,6 @@ extern fn ZigLLVMTargetMachineEmitToFile( ) bool; pub const BuildCall = ZigLLVMBuildCall; -extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value; +extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: CallConv, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value; pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index 6f1faa3f3feb..ec683e4ba882 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -95,7 +95,7 @@ export fn stage2_translate_c( args_end: [*]?[*]const u8, resources_path: [*:0]const u8, ) Error { - var errors: []translate_c.ClangErrMsg = undefined; + var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { error.SemanticAnalyzeFail => { out_errors_ptr.* = errors.ptr; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index cdfed31b129b..d0cb778bfccb 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -9,6 +9,7 @@ usingnamespace @import("clang.zig"); const ctok = @import("c_tokenizer.zig"); const CToken = ctok.CToken; const mem = std.mem; +const math = std.math; const CallingConvention = std.builtin.TypeInfo.CallingConvention; @@ -64,6 +65,7 @@ const Scope = struct { block_node: *ast.Node.Block, variables: AliasList, label: ?[]const u8, + mangle_count: u32 = 0, /// Don't forget to set rbrace token and block_node later fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block { @@ -80,7 +82,19 @@ const Scope = struct { return block; } - fn getAlias(scope: *Block, name: []const u8) ?[]const u8 { + /// Given the desired name, return a name that does not shadow anything from outer scopes. + /// Inserts the returned name into the scope. + fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 { + var proposed_name = name; + while (scope.contains(proposed_name)) { + scope.mangle_count += 1; + proposed_name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count }); + } + try scope.variables.push(.{ .name = name, .alias = proposed_name }); + return proposed_name; + } + + fn getAlias(scope: *Block, name: []const u8) []const u8 { var it = scope.variables.iterator(0); while (it.next()) |p| { if (mem.eql(u8, p.name, name)) @@ -89,12 +103,18 @@ const Scope = struct { return scope.base.parent.?.getAlias(name); } - fn contains(scope: *Block, name: []const u8) bool { + fn localContains(scope: *Block, name: []const u8) bool { var it = scope.variables.iterator(0); while (it.next()) |p| { if (mem.eql(u8, p.name, name)) return true; } + return false; + } + + fn contains(scope: *Block, name: []const u8) bool { + if (scope.localContains(name)) + return true; return scope.base.parent.?.contains(name); } }; @@ -103,6 +123,7 @@ const Scope = struct { base: Scope, sym_table: SymbolTable, macro_table: SymbolTable, + context: *Context, fn init(c: *Context) Root { return .{ @@ -112,11 +133,21 @@ const Scope = struct { }, .sym_table = SymbolTable.init(c.a()), .macro_table = SymbolTable.init(c.a()), + .context = c, }; } + /// Check if the global scope contains this name, without looking into the "future", e.g. + /// ignore the preprocessed decl and macro names. + fn containsNow(scope: *Root, name: []const u8) bool { + return isZigPrimitiveType(name) or + scope.sym_table.contains(name) or + scope.macro_table.contains(name); + } + + /// Check if the global scope contains the name, includes all decls that haven't been translated yet. fn contains(scope: *Root, name: []const u8) bool { - return scope.sym_table.contains(name) or scope.macro_table.contains(name); + return scope.containsNow(name) or scope.context.global_names.contains(name); } }; @@ -135,16 +166,9 @@ const Scope = struct { } } - fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 { - if (isZigPrimitiveType(name) or scope.contains(name)) { - return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }); - } - return null; - } - - fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { + fn getAlias(scope: *Scope, name: []const u8) []const u8 { return switch (scope.id) { - .Root => null, + .Root => return name, .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), }; @@ -191,9 +215,15 @@ pub const Context = struct { alias_list: AliasList, global_scope: *Scope.Root, clang_context: *ZigClangASTContext, - mangle_count: u64 = 0, + mangle_count: u32 = 0, + + /// This one is different than the root scope's name table. This contains + /// a list of names that we found by visiting all the top level decls without + /// translating them. The other maps are updated as we translate; this one is updated + /// up front in a pre-processing step. + global_names: std.StringHashMap(void), - fn getMangle(c: *Context) u64 { + fn getMangle(c: *Context) u32 { c.mangle_count += 1; return c.mangle_count; } @@ -249,6 +279,7 @@ pub fn translate( .arena_allocator = tree_arena, .tokens = undefined, // can't reference the allocator yet .errors = undefined, // can't reference the allocator yet + .generated = true, }; break :blk tree; }; @@ -276,9 +307,12 @@ pub fn translate( .alias_list = AliasList.init(arena), .global_scope = try arena.create(Scope.Root), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, + .global_names = std.StringHashMap(void).init(arena), }; context.global_scope.* = Scope.Root.init(&context); + try prepopulateGlobalNameTable(ast_unit, &context); + if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { return context.err; } @@ -306,6 +340,38 @@ pub fn translate( return tree; } +fn prepopulateGlobalNameTable(ast_unit: *ZigClangASTUnit, c: *Context) !void { + if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, declVisitorNamesOnlyC)) { + return c.err; + } + + // TODO if we see #undef, delete it from the table + var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(ast_unit); + const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(ast_unit); + + while (it.I != it_end.I) : (it.I += 1) { + const entity = ZigClangPreprocessingRecord_iterator_deref(it); + switch (ZigClangPreprocessedEntity_getKind(entity)) { + .MacroDefinitionKind => { + const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity); + const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); + const name = try c.str(raw_name); + _ = try c.global_names.put(name, {}); + }, + else => {}, + } + } +} + +extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool { + const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); + declVisitorNamesOnly(c, decl) catch |err| { + c.err = err; + return false; + }; + return true; +} + extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool { const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); declVisitor(c, decl) catch |err| { @@ -315,6 +381,11 @@ extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool { return true; } +fn declVisitorNamesOnly(c: *Context, decl: *const ZigClangDecl) Error!void { + const decl_name = try c.str(ZigClangDecl_getName_bytes_begin(decl)); + _ = try c.global_names.put(decl_name, {}); +} + fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { switch (ZigClangDecl_getKind(decl)) { .Function => { @@ -352,7 +423,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { .has_body = has_body, .storage_class = storage_class, .is_export = switch (storage_class) { - .None => has_body, + .None => has_body and !ZigClangFunctionDecl_isInlineSpecified(fn_decl), .Extern, .Static => false, .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}), .Auto => unreachable, // Not legal on functions @@ -409,13 +480,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { const param_name = tokenSlice(c, param.name_token orelse return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name})); - const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: { - try block_scope.variables.push(.{ .name = param_name, .alias = a }); - break :blk a; - } else param_name; - const arg_name = try std.fmt.allocPrint(c.a(), "_arg_{}", .{checked_param_name}); + const mangled_param_name = try block_scope.makeMangledName(c, param_name); + + const arg_name = blk: { + const bare_arg_name = try std.fmt.allocPrint(c.a(), "arg_{}", .{mangled_param_name}); + break :blk try block_scope.makeMangledName(c, bare_arg_name); + }; - const node = try transCreateNodeVarDecl(c, false, false, checked_param_name); + const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name); node.eq_token = try appendToken(c, .Equal, "="); node.init_node = try transCreateNodeIdentifier(c, arg_name); node.semicolon_token = try appendToken(c, .Semicolon, ";"); @@ -483,10 +555,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { var eq_tok: ast.TokenIndex = undefined; var init_node: ?*ast.Node = null; + // If the initialization expression is not present, initialize with undefined. + // If it is an integer literal, we can skip the @as since it will be redundant + // with the variable type. if (ZigClangVarDecl_hasInit(var_decl)) { eq_tok = try appendToken(c, .Equal, "="); init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| - transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { + transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { error.UnsupportedTranslation, error.UnsupportedType, => { @@ -532,49 +607,53 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - if (mem.eql(u8, typedef_name, "uint8_t")) + // TODO https://github.com/ziglang/zig/issues/3756 + // TODO https://github.com/ziglang/zig/issues/1802 + const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "_{}", .{typedef_name}) else typedef_name; + + if (mem.eql(u8, checked_name, "uint8_t")) return transTypeDefAsBuiltin(c, typedef_decl, "u8") - else if (mem.eql(u8, typedef_name, "int8_t")) + else if (mem.eql(u8, checked_name, "int8_t")) return transTypeDefAsBuiltin(c, typedef_decl, "i8") - else if (mem.eql(u8, typedef_name, "uint16_t")) + else if (mem.eql(u8, checked_name, "uint16_t")) return transTypeDefAsBuiltin(c, typedef_decl, "u16") - else if (mem.eql(u8, typedef_name, "int16_t")) + else if (mem.eql(u8, checked_name, "int16_t")) return transTypeDefAsBuiltin(c, typedef_decl, "i16") - else if (mem.eql(u8, typedef_name, "uint32_t")) + else if (mem.eql(u8, checked_name, "uint32_t")) return transTypeDefAsBuiltin(c, typedef_decl, "u32") - else if (mem.eql(u8, typedef_name, "int32_t")) + else if (mem.eql(u8, checked_name, "int32_t")) return transTypeDefAsBuiltin(c, typedef_decl, "i32") - else if (mem.eql(u8, typedef_name, "uint64_t")) + else if (mem.eql(u8, checked_name, "uint64_t")) return transTypeDefAsBuiltin(c, typedef_decl, "u64") - else if (mem.eql(u8, typedef_name, "int64_t")) + else if (mem.eql(u8, checked_name, "int64_t")) return transTypeDefAsBuiltin(c, typedef_decl, "i64") - else if (mem.eql(u8, typedef_name, "intptr_t")) + else if (mem.eql(u8, checked_name, "intptr_t")) return transTypeDefAsBuiltin(c, typedef_decl, "isize") - else if (mem.eql(u8, typedef_name, "uintptr_t")) + else if (mem.eql(u8, checked_name, "uintptr_t")) return transTypeDefAsBuiltin(c, typedef_decl, "usize") - else if (mem.eql(u8, typedef_name, "ssize_t")) + else if (mem.eql(u8, checked_name, "ssize_t")) return transTypeDefAsBuiltin(c, typedef_decl, "isize") - else if (mem.eql(u8, typedef_name, "size_t")) + else if (mem.eql(u8, checked_name, "size_t")) return transTypeDefAsBuiltin(c, typedef_decl, "usize"); - _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); + _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), checked_name); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); const const_tok = try appendToken(c, .Keyword_const, "const"); - const node = try transCreateNodeVarDecl(c, true, true, typedef_name); + const node = try transCreateNodeVarDecl(c, true, true, checked_name); node.eq_token = try appendToken(c, .Equal, "="); const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { error.UnsupportedType => { - try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); + try failDecl(c, typedef_loc, checked_name, "unable to resolve typedef child type", .{}); return null; }, error.OutOfMemory => |e| return e, }; node.semicolon_token = try appendToken(c, .Semicolon, ";"); - try addTopLevelDecl(c, typedef_name, &node.base); - return transCreateNodeIdentifier(c, typedef_name); + try addTopLevelDecl(c, checked_name, &node.base); + return transCreateNodeIdentifier(c, checked_name); } fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { @@ -838,19 +917,19 @@ fn transStmt( .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)), .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue), .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used), - .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), + .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used, .with_as), .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), .ParenExprClass => { - const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue); - if (expr.id == .GroupedExpression) return expr; + const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue); + if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); const node = try rp.c.a().create(ast.Node.GroupedExpression); node.* = .{ .lparen = try appendToken(rp.c, .LParen, "("), .expr = expr, .rparen = try appendToken(rp.c, .RParen, ")"), }; - return &node.base; + return maybeSuppressResult(rp, scope, result_used, &node.base); }, .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), @@ -872,7 +951,7 @@ fn transStmt( .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)), .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), - .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), + .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used, .with_as), .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used), @@ -1132,11 +1211,8 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) const name = try c.str(ZigClangDecl_getName_bytes_begin( @ptrCast(*const ZigClangDecl, var_decl), )); - const checked_name = if (try scope.createAlias(c, name)) |a| blk: { - try block_scope.variables.push(.{ .name = name, .alias = a }); - break :blk a; - } else name; - const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), checked_name); + const mangled_name = try block_scope.makeMangledName(c, name); + const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name); _ = try appendToken(c, .Colon, ":"); const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); @@ -1144,7 +1220,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) node.eq_token = try appendToken(c, .Equal, "="); var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| - try transExpr(rp, scope, expr, .used, .r_value) + try transExprCoercing(rp, scope, expr, .used, .r_value) else try transCreateNodeUndefinedLiteral(c); if (isBoolRes(init_node)) { @@ -1177,8 +1253,8 @@ fn transDeclRefExpr( ) TransError!*ast.Node { const value_decl = ZigClangDeclRefExpr_getDecl(expr); const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); - const checked_name = if (scope.getAlias(name)) |a| a else name; - return transCreateNodeIdentifier(rp.c, checked_name); + const mangled_name = scope.getAlias(name); + return transCreateNodeIdentifier(rp.c, mangled_name); } fn transImplicitCastExpr( @@ -1193,7 +1269,7 @@ fn transImplicitCastExpr( const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); const src_type = getExprQualType(c, sub_expr); switch (ZigClangImplicitCastExpr_getCastKind(expr)) { - .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => { + .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => { return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); }, .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => { @@ -1220,29 +1296,6 @@ fn transImplicitCastExpr( const rhs_node = try transCreateNodeInt(rp.c, 0); return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, result_used, false); }, - .PointerToIntegral => { - // @intCast(dest_type, @ptrToInt(val)) - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); - try cast_node.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); - _ = try appendToken(rp.c, .Comma, ","); - - const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); - try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); - ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); - try cast_node.params.push(&ptr_to_int.base); - cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, &cast_node.base); - }, - .IntegralToPointer => { - // @intToPtr(dest_type, val) - const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); - try int_to_ptr.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); - _ = try appendToken(rp.c, .Comma, ","); - - try int_to_ptr.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); - int_to_ptr.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, &int_to_ptr.base); - }, else => |kind| return revertAndWarn( rp, error.UnsupportedTranslation, @@ -1398,19 +1451,50 @@ fn finishBoolExpr( return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{}); } +const SuppressCast = enum { + with_as, + no_as, +}; fn transIntegerLiteral( rp: RestorePoint, scope: *Scope, expr: *const ZigClangIntegerLiteral, result_used: ResultUsed, + suppress_as: SuppressCast, ) TransError!*ast.Node { var eval_result: ZigClangExprEvalResult = undefined; if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) { const loc = ZigClangIntegerLiteral_getBeginLoc(expr); return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); } - const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); - return maybeSuppressResult(rp, scope, result_used, node); + + if (suppress_as == .no_as) { + const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); + return maybeSuppressResult(rp, scope, result_used, int_lit_node); + } + + // Integer literals in C have types, and this can matter for several reasons. + // For example, this is valid C: + // unsigned char y = 256; + // How this gets evaluated is the 256 is an integer, which gets truncated to signed char, then bit-casted + // to unsigned char, resulting in 0. In order for this to work, we have to emit this zig code: + // var y = @bitCast(u8, @truncate(i8, @as(c_int, 256))); + // Ideally in translate-c we could flatten this out to simply: + // var y: u8 = 0; + // But the first step is to be correct, and the next step is to make the output more elegant. + + // @as(T, x) + const expr_base = @ptrCast(*const ZigClangExpr, expr); + const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); + try as_node.params.push(ty_node); + _ = try appendToken(rp.c, .Comma, ","); + + const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); + try as_node.params.push(int_lit_node); + + as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return maybeSuppressResult(rp, scope, result_used, &as_node.base); } fn transReturnStmt( @@ -1420,7 +1504,7 @@ fn transReturnStmt( ) TransError!*ast.Node { const node = try transCreateNodeReturnExpr(rp.c); if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { - node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value); + node.rhs = try transExprCoercing(rp, scope, val_expr, .used, .r_value); } _ = try appendToken(rp.c, .Semicolon, ";"); return &node.base; @@ -1508,8 +1592,48 @@ fn transCCast( if (ZigClangQualType_eq(dst_type, src_type)) return expr; if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type)) return transCPtrCast(rp, loc, dst_type, src_type, expr); - if (cIsUnsignedInteger(dst_type) and qualTypeIsPtr(src_type)) { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + if (cIsInteger(dst_type) and cIsInteger(src_type)) { + // 1. Extend or truncate without changing signed-ness. + // 2. Bit-cast to correct signed-ness + + // @bitCast(dest_type, intermediate_value) + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); + try cast_node.params.push(try transQualType(rp, dst_type, loc)); + _ = try appendToken(rp.c, .Comma, ","); + + switch (cIntTypeCmp(dst_type, src_type)) { + .lt => { + // @truncate(SameSignSmallerInt, src_type) + const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate"); + const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); + try trunc_node.params.push(ty_node); + _ = try appendToken(rp.c, .Comma, ","); + try trunc_node.params.push(expr); + trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + + try cast_node.params.push(&trunc_node.base); + }, + .gt => { + // @as(SameSignBiggerInt, src_type) + const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); + try as_node.params.push(ty_node); + _ = try appendToken(rp.c, .Comma, ","); + try as_node.params.push(expr); + as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + + try cast_node.params.push(&as_node.base); + }, + .eq => { + try cast_node.params.push(expr); + }, + } + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return &cast_node.base; + } + if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { + // @intCast(dest_type, @ptrToInt(val)) + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); try cast_node.params.push(try transQualType(rp, dst_type, loc)); _ = try appendToken(rp.c, .Comma, ","); const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); @@ -1519,7 +1643,8 @@ fn transCCast( cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &cast_node.base; } - if (cIsUnsignedInteger(src_type) and qualTypeIsPtr(dst_type)) { + if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { + // @intToPtr(dest_type, val) const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); try builtin_node.params.push(try transQualType(rp, dst_type, loc)); _ = try appendToken(rp.c, .Comma, ","); @@ -1575,9 +1700,6 @@ fn transCCast( builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } - // TODO: maybe widen to increase size - // TODO: maybe bitcast to change sign - // TODO: maybe truncate to reduce size const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); try cast_node.params.push(try transQualType(rp, dst_type, loc)); _ = try appendToken(rp.c, .Comma, ","); @@ -1596,6 +1718,33 @@ fn transExpr( return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue); } +/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore +/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals. +fn transExprCoercing( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangExpr, + used: ResultUsed, + lrvalue: LRValue, +) TransError!*ast.Node { + switch (ZigClangStmt_getStmtClass(@ptrCast(*const ZigClangStmt, expr))) { + .IntegerLiteralClass => { + return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, expr), .used, .no_as); + }, + .CharacterLiteralClass => { + return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, expr), .used, .no_as); + }, + .UnaryOperatorClass => { + const un_expr = @ptrCast(*const ZigClangUnaryOperator, expr); + if (ZigClangUnaryOperator_getOpcode(un_expr) == .Extension) { + return transExprCoercing(rp, scope, ZigClangUnaryOperator_getSubExpr(un_expr), used, lrvalue); + } + }, + else => {}, + } + return transExpr(rp, scope, expr, .used, .r_value); +} + fn transInitListExpr( rp: RestorePoint, scope: *Scope, @@ -1621,7 +1770,7 @@ fn transInitListExpr( const init_count = ZigClangInitListExpr_getNumInits(expr); const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type); const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); - const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize)); + const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize)); const leftover_count = all_count - init_count; var init_node: *ast.Node.SuffixOp = undefined; @@ -1793,7 +1942,10 @@ fn transDoWhileLoop( // zig: b; // zig: if (!cond) break; // zig: } - break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; + const body = (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; + // if this is used as an expression in Zig it needs to be immediately followed by a semicolon + _ = try appendToken(rp.c, .Semicolon, ";"); + break :blk body; } else blk: { // the C statement is without a block, so we need to create a block to contain it. // c: do @@ -2026,16 +2178,17 @@ fn transCharLiteral( scope: *Scope, stmt: *const ZigClangCharacterLiteral, result_used: ResultUsed, + suppress_as: SuppressCast, ) TransError!*ast.Node { const kind = ZigClangCharacterLiteral_getKind(stmt); - switch (kind) { - .Ascii, .UTF8 => { + const int_lit_node = switch (kind) { + .Ascii, .UTF8 => blk: { const val = ZigClangCharacterLiteral_getValue(stmt); if (kind == .Ascii) { // C has a somewhat obscure feature called multi-character character // constant if (val > 255) - return transCreateNodeInt(rp.c, val); + break :blk try transCreateNodeInt(rp.c, val); } var char_buf: [4]u8 = undefined; const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); @@ -2043,7 +2196,7 @@ fn transCharLiteral( node.* = .{ .token = token, }; - return maybeSuppressResult(rp, scope, result_used, &node.base); + break :blk &node.base; }, .UTF16, .UTF32, .Wide => return revertAndWarn( rp, @@ -2053,7 +2206,22 @@ fn transCharLiteral( .{kind}, ), else => unreachable, + }; + if (suppress_as == .no_as) { + return maybeSuppressResult(rp, scope, result_used, int_lit_node); } + // See comment in `transIntegerLiteral` for why this code is here. + // @as(T, x) + const expr_base = @ptrCast(*const ZigClangExpr, stmt); + const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); + try as_node.params.push(ty_node); + _ = try appendToken(rp.c, .Comma, ","); + + try as_node.params.push(int_lit_node); + + as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return maybeSuppressResult(rp, scope, result_used, &as_node.base); } fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node { @@ -2096,6 +2264,9 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE } const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt)))); + if (name.len == 0) { + return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), "TODO access of anonymous field", .{}); + } const node = try transCreateNodeFieldAccess(rp.c, container_node, name); return maybeSuppressResult(rp, scope, result_used, node); } @@ -2208,32 +2379,32 @@ fn transUnaryExprOrTypeTraitExpr( return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); } -fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool { - if (cIsSignedInteger(qt) or cIsFloating(qt)) { - // float and signed integer overflow is undefined behavior. - return false; - } else { +fn qualTypeHasWrappingOverflow(qt: ZigClangQualType) bool { + if (cIsUnsignedInteger(qt)) { // unsigned integer overflow wraps around. return true; + } else { + // float, signed integer, and pointer overflow is undefined behavior. + return false; } } fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node { const op_expr = ZigClangUnaryOperator_getSubExpr(stmt); switch (ZigClangUnaryOperator_getOpcode(stmt)) { - .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt))) + .PostInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt))) return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used) else return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), - .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt))) + .PostDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt))) return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used) else return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), - .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt))) + .PreInc => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt))) return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used) else return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), - .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt))) + .PreDec => if (qualTypeHasWrappingOverflow(ZigClangUnaryOperator_getType(stmt))) return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used) else return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), @@ -2253,7 +2424,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar }, .Plus => return transExpr(rp, scope, op_expr, used, .r_value), .Minus => { - if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) { + if (!qualTypeHasWrappingOverflow(ZigClangExpr_getType(op_expr))) { const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-"); op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); return &op_node.base; @@ -2313,7 +2484,7 @@ fn transCreatePreCrement( // zig: }) const block_scope = try Scope.Block.init(rp.c, scope, "blk"); block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); - const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); + const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); node.eq_token = try appendToken(rp.c, .Equal, "="); @@ -2378,7 +2549,7 @@ fn transCreatePostCrement( // zig: }) const block_scope = try Scope.Block.init(rp.c, scope, "blk"); block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); - const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); + const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); node.eq_token = try appendToken(rp.c, .Equal, "="); @@ -2392,7 +2563,7 @@ fn transCreatePostCrement( const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); _ = try appendToken(rp.c, .Semicolon, ";"); - const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); + const tmp = try block_scope.makeMangledName(rp.c, "tmp"); const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp); tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); tmp_node.init_node = ref_node; @@ -2421,15 +2592,15 @@ fn transCreatePostCrement( fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node { switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) { - .MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) + .MulAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used) else return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used), - .AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) + .AddAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used) else return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used), - .SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) + .SubAssign => if (qualTypeHasWrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt))) return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used) else return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used), @@ -2470,7 +2641,10 @@ fn transCreateCompoundAssign( // zig: lhs += rhs const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes); - var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); + var rhs_node = if (is_shift) + try transExprCoercing(rp, scope, rhs, .used, .r_value) + else + try transExpr(rp, scope, rhs, .used, .r_value); if (is_shift) { const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); @@ -2494,7 +2668,7 @@ fn transCreateCompoundAssign( // zig: }) const block_scope = try Scope.Block.init(rp.c, scope, "blk"); block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); - const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); + const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); node.eq_token = try appendToken(rp.c, .Equal, "="); @@ -2671,6 +2845,30 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); } +/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness. +/// Asserts the type is an integer. +fn transQualTypeIntWidthOf(c: *Context, ty: ZigClangQualType, is_signed: bool) TypeError!*ast.Node { + return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed); +} + +/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness. +/// Asserts the type is an integer. +fn transTypeIntWidthOf(c: *Context, ty: *const ZigClangType, is_signed: bool) TypeError!*ast.Node { + assert(ZigClangType_getTypeClass(ty) == .Builtin); + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); + return transCreateNodeIdentifier(c, switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8", + .UShort, .Short => if (is_signed) "c_short" else "c_ushort", + .UInt, .Int => if (is_signed) "c_int" else "c_uint", + .ULong, .Long => if (is_signed) "c_long" else "c_ulong", + .ULongLong, .LongLong => if (is_signed) "c_longlong" else "c_ulonglong", + .UInt128, .Int128 => if (is_signed) "i128" else "u128", + .Char16 => if (is_signed) "i16" else "u16", + .Char32 => if (is_signed) "i32" else "u32", + else => unreachable, // only call this function when it has already been determined the type is int + }); +} + fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { const c_type = qualTypeCanon(qt); if (ZigClangType_getTypeClass(c_type) != .Builtin) @@ -2732,7 +2930,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC if (int_bit_width != 0) { // we can perform the log2 now. - const cast_bit_width = std.math.log2_int(u64, int_bit_width); + const cast_bit_width = math.log2_int(u64, int_bit_width); const node = try rp.c.a().create(ast.Node.IntegerLiteral); node.* = ast.Node.IntegerLiteral{ .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}), @@ -2869,6 +3067,10 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio } } +fn cIsInteger(qt: ZigClangQualType) bool { + return cIsSignedInteger(qt) or cIsUnsignedInteger(qt); +} + fn cIsUnsignedInteger(qt: ZigClangQualType) bool { const c_type = qualTypeCanon(qt); if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; @@ -2888,6 +3090,28 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool { }; } +fn cIntTypeToIndex(qt: ZigClangQualType) u8 { + const c_type = qualTypeCanon(qt); + assert(ZigClangType_getTypeClass(c_type) == .Builtin); + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); + return switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Bool, .Char_U, .Char_S, .UChar, .SChar, .Char8 => 1, + .WChar_U, .WChar_S => 2, + .UShort, .Short, .Char16 => 3, + .UInt, .Int, .Char32 => 4, + .ULong, .Long => 5, + .ULongLong, .LongLong => 6, + .UInt128, .Int128 => 7, + else => unreachable, + }; +} + +fn cIntTypeCmp(a: ZigClangQualType, b: ZigClangQualType) math.Order { + const a_index = cIntTypeToIndex(a); + const b_index = cIntTypeToIndex(b); + return math.order(a_index, b_index); +} + fn cIsSignedInteger(qt: ZigClangQualType) bool { const c_type = qualTypeCanon(qt); if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; @@ -2932,7 +3156,7 @@ fn transCreateNodeAssign( if (result_used == .unused) { const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); const eq_token = try appendToken(rp.c, .Equal, "="); - var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); + var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value); if (isBoolRes(rhs_node)) { const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); try builtin_node.params.push(rhs_node); @@ -2953,11 +3177,11 @@ fn transCreateNodeAssign( // zig: }) const block_scope = try Scope.Block.init(rp.c, scope, "blk"); block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); - const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); + const tmp = try block_scope.makeMangledName(rp.c, "tmp"); const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); node.eq_token = try appendToken(rp.c, .Equal, "="); - var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); + var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value); if (isBoolRes(rhs_node)) { const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); try builtin_node.params.push(rhs_node); @@ -2968,12 +3192,12 @@ fn transCreateNodeAssign( node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); try block_scope.block_node.statements.push(&node.base); - const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); + const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value); const eq_token = try appendToken(rp.c, .Equal, "="); const ident = try transCreateNodeIdentifier(rp.c, tmp); _ = try appendToken(rp.c, .Semicolon, ";"); - const assign = try transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, ident, .used, false); + const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false); try block_scope.block_node.statements.push(assign); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); @@ -3144,7 +3368,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int); if (is_negative) aps_int = ZigClangAPSInt_negate(aps_int); - var big = try std.math.big.Int.initCapacity(c.a(), num_limbs); + var big = try math.big.Int.initCapacity(c.a(), num_limbs); if (is_negative) big.negate(); defer big.deinit(); @@ -3508,7 +3732,7 @@ fn transCreateNodeShiftOp( const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location); try as_node.params.push(rhs_type); _ = try appendToken(rp.c, .Comma, ","); - const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value); + const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value); try as_node.params.push(rhs); as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -3638,7 +3862,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, ty); const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); - const size = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize)); + const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize)); var node = try transCreateNodePrefixOp( rp.c, .{ @@ -4072,7 +4296,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); var tok_list = ctok.TokenList.init(c.a()); - const scope = &c.global_scope.base; + const scope = c.global_scope; while (it.I != it_end.I) : (it.I += 1) { const entity = ZigClangPreprocessingRecord_iterator_deref(it); @@ -4084,15 +4308,15 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); const name = try c.str(raw_name); - // TODO https://github.com/ziglang/zig/issues/3756 // TODO https://github.com/ziglang/zig/issues/1802 - const checked_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name; - if (scope.contains(checked_name)) { + const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name; + if (scope.containsNow(mangled_name)) { continue; } + const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); - ctok.tokenizeCMacro(c, begin_loc, checked_name, &tok_list, begin_c) catch |err| switch (err) { + ctok.tokenizeCMacro(c, begin_loc, mangled_name, &tok_list, begin_c) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => { continue; @@ -4107,7 +4331,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { .Identifier => { // if it equals itself, ignore. for example, from stdio.h: // #define stdin stdin - if (mem.eql(u8, checked_name, next.bytes)) { + if (mem.eql(u8, name, next.bytes)) { continue; } }, @@ -4118,15 +4342,16 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { }, else => {}, } + const macro_fn = if (tok_it.peek().?.id == .Fn) blk: { _ = tok_it.next(); break :blk true; } else false; (if (macro_fn) - transMacroFnDefine(c, &tok_it, checked_name, begin_loc) + transMacroFnDefine(c, &tok_it, mangled_name, begin_loc) else - transMacroDefine(c, &tok_it, checked_name, begin_loc)) catch |err| switch (err) { + transMacroDefine(c, &tok_it, mangled_name, begin_loc)) catch |err| switch (err) { error.ParseError => continue, error.OutOfMemory => |e| return e, }; @@ -4189,12 +4414,8 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u ); } - const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: { - try block_scope.variables.push(.{ .name = param_tok.bytes, .alias = alias }); - break :blk alias; - } else param_tok.bytes; - - const param_name_tok = try appendIdentifier(c, checked_name); + const mangled_name = try block_scope.makeMangledName(c, param_tok.bytes); + const param_name_tok = try appendIdentifier(c, mangled_name); _ = try appendToken(c, .Colon, ":"); const token_index = try appendToken(c, .Keyword_var, "var"); @@ -4234,7 +4455,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u _ = try appendToken(c, .RParen, ")"); const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); - type_of.rparen_token = try appendToken(c, .LParen, ")"); + type_of.rparen_token = try appendToken(c, .RParen, ")"); const fn_proto = try c.a().create(ast.Node.FnProto); fn_proto.* = .{ @@ -4279,7 +4500,33 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u const ParseError = Error || error{ParseError}; fn parseCExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node { - return parseCPrefixOpExpr(c, it, source_loc, scope); + const node = try parseCPrefixOpExpr(c, it, source_loc, scope); + switch (it.next().?.id) { + .QuestionMark => { + // must come immediately after expr + _ = try appendToken(c, .RParen, ")"); + const if_node = try transCreateNodeIf(c); + if_node.condition = node; + if_node.body = try parseCPrimaryExpr(c, it, source_loc, scope); + if (it.next().?.id != .Colon) { + try failDecl( + c, + source_loc, + it.list.at(0).*.bytes, + "unable to translate C expr: expected ':'", + .{}, + ); + return error.ParseError; + } + if_node.@"else" = try transCreateNodeElse(c); + if_node.@"else".?.body = try parseCPrimaryExpr(c, it, source_loc, scope); + return &if_node.base; + }, + else => { + _ = it.prev(); + return node; + }, + } } fn parseCNumLit(c: *Context, tok: *CToken, source_loc: ZigClangSourceLocation) ParseError!*ast.Node { @@ -4349,8 +4596,8 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC return parseCNumLit(c, tok, source_loc); }, .Identifier => { - const name = if (scope.getAlias(tok.bytes)) |a| a else tok.bytes; - return transCreateNodeIdentifier(c, name); + const mangled_name = scope.getAlias(tok.bytes); + return transCreateNodeIdentifier(c, mangled_name); }, .LParen => { const inner_node = try parseCExpr(c, it, source_loc, scope); @@ -4391,8 +4638,8 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); try type_id_1.params.push(&type_of_1.base); try type_of_1.params.push(node_to_cast); - type_of_1.rparen_token = try appendToken(c, .LParen, ")"); - type_id_1.rparen_token = try appendToken(c, .LParen, ")"); + type_of_1.rparen_token = try appendToken(c, .RParen, ")"); + type_id_1.rparen_token = try appendToken(c, .RParen, ")"); const cmp_1 = try c.a().create(ast.Node.InfixOp); cmp_1.* = .{ @@ -4402,12 +4649,12 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC .rhs = try transCreateNodeEnumLiteral(c, "Pointer"), }; if_1.condition = &cmp_1.base; - _ = try appendToken(c, .LParen, ")"); + _ = try appendToken(c, .RParen, ")"); const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast"); try ptr_cast.params.push(inner_node); try ptr_cast.params.push(node_to_cast); - ptr_cast.rparen_token = try appendToken(c, .LParen, ")"); + ptr_cast.rparen_token = try appendToken(c, .RParen, ")"); if_1.body = &ptr_cast.base; const else_1 = try transCreateNodeElse(c); @@ -4418,8 +4665,8 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); try type_id_2.params.push(&type_of_2.base); try type_of_2.params.push(node_to_cast); - type_of_2.rparen_token = try appendToken(c, .LParen, ")"); - type_id_2.rparen_token = try appendToken(c, .LParen, ")"); + type_of_2.rparen_token = try appendToken(c, .RParen, ")"); + type_id_2.rparen_token = try appendToken(c, .RParen, ")"); const cmp_2 = try c.a().create(ast.Node.InfixOp); cmp_2.* = .{ @@ -4430,12 +4677,12 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC }; if_2.condition = &cmp_2.base; else_1.body = &if_2.base; - _ = try appendToken(c, .LParen, ")"); + _ = try appendToken(c, .RParen, ")"); const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr"); try int_to_ptr.params.push(inner_node); try int_to_ptr.params.push(node_to_cast); - int_to_ptr.rparen_token = try appendToken(c, .LParen, ")"); + int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); if_2.body = &int_to_ptr.base; const else_2 = try transCreateNodeElse(c); @@ -4444,7 +4691,7 @@ fn parseCPrimaryExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: ZigC const as = try transCreateNodeBuiltinFnCall(c, "@as"); try as.params.push(inner_node); try as.params.push(node_to_cast); - as.rparen_token = try appendToken(c, .LParen, ")"); + as.rparen_token = try appendToken(c, .RParen, ")"); else_2.body = &as.base; return &if_1.base; @@ -4524,7 +4771,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig }, .Shl => { const op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<"); - const rhs = try parseCExpr(c, it, source_loc, scope); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); const bitshift_node = try c.a().create(ast.Node.InfixOp); bitshift_node.* = .{ .op_token = op_token, @@ -4534,9 +4781,21 @@ fn parseCSuffixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig }; node = &bitshift_node.base; }, + .Shr => { + const op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const bitshift_node = try c.a().create(ast.Node.InfixOp); + bitshift_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BitShiftRight, + .rhs = rhs, + }; + node = &bitshift_node.base; + }, .Pipe => { const op_token = try appendToken(c, .Pipe, "|"); - const rhs = try parseCExpr(c, it, source_loc, scope); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); const or_node = try c.a().create(ast.Node.InfixOp); or_node.* = .{ .op_token = op_token, @@ -4546,9 +4805,117 @@ fn parseCSuffixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig }; node = &or_node.base; }, + .Ampersand => { + const op_token = try appendToken(c, .Ampersand, "&"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const bitand_node = try c.a().create(ast.Node.InfixOp); + bitand_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BitAnd, + .rhs = rhs, + }; + node = &bitand_node.base; + }, + .Plus => { + const op_token = try appendToken(c, .Plus, "+"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const add_node = try c.a().create(ast.Node.InfixOp); + add_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .Add, + .rhs = rhs, + }; + node = &add_node.base; + }, + .Minus => { + const op_token = try appendToken(c, .Minus, "-"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const sub_node = try c.a().create(ast.Node.InfixOp); + sub_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .Sub, + .rhs = rhs, + }; + node = &sub_node.base; + }, + .And => { + const op_token = try appendToken(c, .Keyword_and, "and"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const and_node = try c.a().create(ast.Node.InfixOp); + and_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BoolAnd, + .rhs = rhs, + }; + node = &and_node.base; + }, + .Or => { + const op_token = try appendToken(c, .Keyword_or, "or"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const or_node = try c.a().create(ast.Node.InfixOp); + or_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .BoolOr, + .rhs = rhs, + }; + node = &or_node.base; + }, + .Gt => { + const op_token = try appendToken(c, .AngleBracketRight, ">"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const and_node = try c.a().create(ast.Node.InfixOp); + and_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .GreaterThan, + .rhs = rhs, + }; + node = &and_node.base; + }, + .Gte => { + const op_token = try appendToken(c, .AngleBracketRightEqual, ">="); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const and_node = try c.a().create(ast.Node.InfixOp); + and_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .GreaterOrEqual, + .rhs = rhs, + }; + node = &and_node.base; + }, + .Lt => { + const op_token = try appendToken(c, .AngleBracketLeft, "<"); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const and_node = try c.a().create(ast.Node.InfixOp); + and_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .LessThan, + .rhs = rhs, + }; + node = &and_node.base; + }, + .Lte => { + const op_token = try appendToken(c, .AngleBracketLeftEqual, "<="); + const rhs = try parseCPrefixOpExpr(c, it, source_loc, scope); + const and_node = try c.a().create(ast.Node.InfixOp); + and_node.* = .{ + .op_token = op_token, + .lhs = node, + .op = .LessOrEqual, + .rhs = rhs, + }; + node = &and_node.base; + }, .LBrace => { const arr_node = try transCreateNodeArrayAccess(c, node); - arr_node.op.ArrayAccess = try parseCExpr(c, it, source_loc, scope); + arr_node.op.ArrayAccess = try parseCPrefixOpExpr(c, it, source_loc, scope); arr_node.rtoken = try appendToken(c, .RBrace, "]"); node = &arr_node.base; if (it.next().?.id != .RBrace) { @@ -4565,7 +4932,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig .LParen => { const call_node = try transCreateNodeFnCall(c, node); while (true) { - const arg = try parseCExpr(c, it, source_loc, scope); + const arg = try parseCPrefixOpExpr(c, it, source_loc, scope); try call_node.op.Call.params.push(arg); const next = it.next().?; if (next.id == .Comma) @@ -4586,26 +4953,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig call_node.rtoken = try appendToken(c, .RParen, ")"); node = &call_node.base; }, - .QuestionMark => { - // must come immediately after expr - _ = try appendToken(c, .RParen, ")"); - const if_node = try transCreateNodeIf(c); - if_node.condition = node; - if_node.body = try parseCPrimaryExpr(c, it, source_loc, scope); - if (it.next().?.id != .Colon) { - try failDecl( - c, - source_loc, - it.list.at(0).*.bytes, - "unable to translate C expr: expected ':'", - .{}, - ); - return error.ParseError; - } - if_node.@"else" = try transCreateNodeElse(c); - if_node.@"else".?.body = try parseCPrimaryExpr(c, it, source_loc, scope); - node = &if_node.base; - }, else => { _ = it.prev(); return node; @@ -4646,7 +4993,11 @@ fn parseCPrefixOpExpr(c: *Context, it: *ctok.TokenList.Iterator, source_loc: Zig fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { const tok = c.tree.tokens.at(token); - return c.source_buffer.toSlice()[tok.start..tok.end]; + const slice = c.source_buffer.toSlice()[tok.start..tok.end]; + return if (mem.startsWith(u8, slice, "@\"")) + slice[2 .. slice.len - 1] + else + slice; } fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp deleted file mode 100644 index 55fde190031c..000000000000 --- a/src/c_tokenizer.cpp +++ /dev/null @@ -1,840 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "c_tokenizer.hpp" -#include - -#define WHITESPACE_EXCEPT_N \ - ' ': \ - case '\t': \ - case '\v': \ - case '\f' - -#define DIGIT_NON_ZERO \ - '1': \ - case '2': \ - case '3': \ - case '4': \ - case '5': \ - case '6': \ - case '7': \ - case '8': \ - case '9' - -#define DIGIT \ - '0': \ - case DIGIT_NON_ZERO - -#define ALPHA \ - 'a': \ - case 'b': \ - case 'c': \ - case 'd': \ - case 'e': \ - case 'f': \ - case 'g': \ - case 'h': \ - case 'i': \ - case 'j': \ - case 'k': \ - case 'l': \ - case 'm': \ - case 'n': \ - case 'o': \ - case 'p': \ - case 'q': \ - case 'r': \ - case 's': \ - case 't': \ - case 'u': \ - case 'v': \ - case 'w': \ - case 'x': \ - case 'y': \ - case 'z': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'E': \ - case 'F': \ - case 'G': \ - case 'H': \ - case 'I': \ - case 'J': \ - case 'K': \ - case 'L': \ - case 'M': \ - case 'N': \ - case 'O': \ - case 'P': \ - case 'Q': \ - case 'R': \ - case 'S': \ - case 'T': \ - case 'U': \ - case 'V': \ - case 'W': \ - case 'X': \ - case 'Y': \ - case 'Z' - -#define IDENT_START \ - ALPHA: \ - case '_' - -#define IDENT \ - IDENT_START: \ - case DIGIT - -#define LINE_ENDING \ - '\r': \ - case '\n' - -static void begin_token(CTokenize *ctok, CTokId id) { - assert(ctok->cur_tok == nullptr); - ctok->tokens.add_one(); - ctok->cur_tok = &ctok->tokens.last(); - ctok->cur_tok->id = id; - - switch (id) { - case CTokIdStrLit: - memset(&ctok->cur_tok->data.str_lit, 0, sizeof(Buf)); - buf_resize(&ctok->cur_tok->data.str_lit, 0); - break; - case CTokIdSymbol: - memset(&ctok->cur_tok->data.symbol, 0, sizeof(Buf)); - buf_resize(&ctok->cur_tok->data.symbol, 0); - break; - case CTokIdNumLitInt: - ctok->cur_tok->data.num_lit_int.x = 0; - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixNone; - break; - case CTokIdCharLit: - case CTokIdNumLitFloat: - case CTokIdMinus: - case CTokIdLParen: - case CTokIdRParen: - case CTokIdEOF: - case CTokIdDot: - case CTokIdAsterisk: - case CTokIdBang: - case CTokIdTilde: - case CTokIdShl: - case CTokIdLt: - break; - } -} - -static void end_token(CTokenize *ctok) { - ctok->cur_tok = nullptr; -} - -static void mark_error(CTokenize *ctok) { - ctok->error = true; -} - -static void add_char(CTokenize *ctok, uint8_t c) { - assert(ctok->cur_tok); - if (ctok->cur_tok->id == CTokIdCharLit) { - ctok->cur_tok->data.char_lit = c; - ctok->state = CTokStateExpectEndQuot; - } else if (ctok->cur_tok->id == CTokIdStrLit) { - buf_append_char(&ctok->cur_tok->data.str_lit, c); - ctok->state = CTokStateString; - } else { - zig_unreachable(); - } -} - -static void hex_digit(CTokenize *ctok, uint8_t value) { - // TODO @mul_with_overflow - ctok->cur_tok->data.num_lit_int.x *= 16; - // TODO @add_with_overflow - ctok->cur_tok->data.num_lit_int.x += value; - - static const uint8_t hex_digit[] = "0123456789abcdef"; - buf_append_char(&ctok->buf, hex_digit[value]); -} - -static void end_float(CTokenize *ctok) { - // TODO detect errors, overflow, and underflow - double value = strtod(buf_ptr(&ctok->buf), nullptr); - - ctok->cur_tok->data.num_lit_float = value; - - end_token(ctok); - ctok->state = CTokStateStart; - -} - -void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { - ctok->tokens.resize(0); - ctok->state = CTokStateStart; - ctok->error = false; - ctok->cur_tok = nullptr; - - buf_resize(&ctok->buf, 0); - - for (; *c; c += 1) { - switch (ctok->state) { - case CTokStateStart: - switch (*c) { - case WHITESPACE_EXCEPT_N: - break; - case '\'': - ctok->state = CTokStateExpectChar; - begin_token(ctok, CTokIdCharLit); - break; - case '\"': - ctok->state = CTokStateString; - begin_token(ctok, CTokIdStrLit); - break; - case '/': - ctok->state = CTokStateOpenComment; - break; - case '\\': - ctok->state = CTokStateBackslash; - break; - case LINE_ENDING: - goto found_end_of_macro; - case IDENT_START: - ctok->state = CTokStateIdentifier; - begin_token(ctok, CTokIdSymbol); - buf_append_char(&ctok->cur_tok->data.symbol, *c); - break; - case DIGIT_NON_ZERO: - ctok->state = CTokStateDecimal; - begin_token(ctok, CTokIdNumLitInt); - ctok->cur_tok->data.num_lit_int.x = *c - '0'; - buf_resize(&ctok->buf, 0); - buf_append_char(&ctok->buf, *c); - break; - case '0': - ctok->state = CTokStateGotZero; - begin_token(ctok, CTokIdNumLitInt); - ctok->cur_tok->data.num_lit_int.x = 0; - buf_resize(&ctok->buf, 0); - buf_append_char(&ctok->buf, '0'); - break; - case '.': - begin_token(ctok, CTokIdDot); - end_token(ctok); - break; - case '<': - begin_token(ctok, CTokIdLt); - ctok->state = CTokStateGotLt; - break; - case '(': - begin_token(ctok, CTokIdLParen); - end_token(ctok); - break; - case ')': - begin_token(ctok, CTokIdRParen); - end_token(ctok); - break; - case '*': - begin_token(ctok, CTokIdAsterisk); - end_token(ctok); - break; - case '-': - begin_token(ctok, CTokIdMinus); - end_token(ctok); - break; - case '!': - begin_token(ctok, CTokIdBang); - end_token(ctok); - break; - case '~': - begin_token(ctok, CTokIdTilde); - end_token(ctok); - break; - default: - return mark_error(ctok); - } - break; - case CTokStateGotLt: - switch (*c) { - case '<': - ctok->cur_tok->id = CTokIdShl; - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateFloat: - switch (*c) { - case '.': - break; - case 'e': - case 'E': - buf_append_char(&ctok->buf, 'e'); - ctok->state = CTokStateExpSign; - break; - case 'f': - case 'F': - case 'l': - case 'L': - end_float(ctok); - break; - case DIGIT: - buf_append_char(&ctok->buf, *c); - break; - default: - c -= 1; - end_float(ctok); - continue; - } - break; - case CTokStateExpSign: - switch (*c) { - case '+': - case '-': - ctok->state = CTokStateFloatExpFirst; - buf_append_char(&ctok->buf, *c); - break; - case DIGIT: - ctok->state = CTokStateFloatExp; - buf_append_char(&ctok->buf, *c); - break; - default: - return mark_error(ctok); - } - break; - case CTokStateFloatExpFirst: - switch (*c) { - case DIGIT: - buf_append_char(&ctok->buf, *c); - ctok->state = CTokStateFloatExp; - break; - default: - return mark_error(ctok); - } - break; - case CTokStateFloatExp: - switch (*c) { - case DIGIT: - buf_append_char(&ctok->buf, *c); - break; - case 'f': - case 'F': - case 'l': - case 'L': - end_float(ctok); - break; - default: - c -= 1; - end_float(ctok); - continue; - } - break; - case CTokStateDecimal: - switch (*c) { - case DIGIT: - buf_append_char(&ctok->buf, *c); - - // TODO @mul_with_overflow - ctok->cur_tok->data.num_lit_int.x *= 10; - // TODO @add_with_overflow - ctok->cur_tok->data.num_lit_int.x += *c - '0'; - break; - case '\'': - break; - case 'u': - case 'U': - ctok->state = CTokStateNumLitIntSuffixU; - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixU; - break; - case 'l': - case 'L': - ctok->state = CTokStateNumLitIntSuffixL; - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixL; - break; - case '.': - buf_append_char(&ctok->buf, '.'); - ctok->cur_tok->id = CTokIdNumLitFloat; - ctok->state = CTokStateFloat; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateGotZero: - switch (*c) { - case 'x': - case 'X': - ctok->state = CTokStateHex; - break; - case '.': - ctok->state = CTokStateFloat; - ctok->cur_tok->id = CTokIdNumLitFloat; - buf_append_char(&ctok->buf, '.'); - break; - case 'l': - case 'L': - case 'u': - case 'U': - c -= 1; - ctok->state = CTokStateDecimal; - continue; - default: - c -= 1; - ctok->state = CTokStateOctal; - continue; - } - break; - case CTokStateOctal: - switch (*c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - // TODO @mul_with_overflow - ctok->cur_tok->data.num_lit_int.x *= 8; - // TODO @add_with_overflow - ctok->cur_tok->data.num_lit_int.x += *c - '0'; - break; - case '8': - case '9': - return mark_error(ctok); - case '\'': - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateHex: - switch (*c) { - case '0': - hex_digit(ctok, 0); - break; - case '1': - hex_digit(ctok, 1); - break; - case '2': - hex_digit(ctok, 2); - break; - case '3': - hex_digit(ctok, 3); - break; - case '4': - hex_digit(ctok, 4); - break; - case '5': - hex_digit(ctok, 5); - break; - case '6': - hex_digit(ctok, 6); - break; - case '7': - hex_digit(ctok, 7); - break; - case '8': - hex_digit(ctok, 8); - break; - case '9': - hex_digit(ctok, 9); - break; - case 'a': - case 'A': - hex_digit(ctok, 10); - break; - case 'b': - case 'B': - hex_digit(ctok, 11); - break; - case 'c': - case 'C': - hex_digit(ctok, 12); - break; - case 'd': - case 'D': - hex_digit(ctok, 13); - break; - case 'e': - case 'E': - hex_digit(ctok, 14); - break; - case 'f': - case 'F': - hex_digit(ctok, 15); - break; - case 'p': - case 'P': - ctok->cur_tok->id = CTokIdNumLitFloat; - ctok->state = CTokStateExpSign; - break; - case 'u': - case 'U': - // marks the number literal as unsigned - ctok->state = CTokStateNumLitIntSuffixU; - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixU; - break; - case 'l': - case 'L': - // marks the number literal as long - ctok->state = CTokStateNumLitIntSuffixL; - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixL; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateNumLitIntSuffixU: - switch (*c) { - case 'l': - case 'L': - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixLU; - ctok->state = CTokStateNumLitIntSuffixUL; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateNumLitIntSuffixL: - switch (*c) { - case 'l': - case 'L': - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixLL; - ctok->state = CTokStateNumLitIntSuffixLL; - break; - case 'u': - case 'U': - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixLU; - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateNumLitIntSuffixLL: - switch (*c) { - case 'u': - case 'U': - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixLLU; - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateNumLitIntSuffixUL: - switch (*c) { - case 'l': - case 'L': - ctok->cur_tok->data.num_lit_int.suffix = CNumLitSuffixLLU; - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateIdentifier: - switch (*c) { - case IDENT: - buf_append_char(&ctok->cur_tok->data.symbol, *c); - break; - default: - c -= 1; - end_token(ctok); - ctok->state = CTokStateStart; - continue; - } - break; - case CTokStateString: - switch (*c) { - case '\\': - ctok->state = CTokStateCharEscape; - break; - case '\"': - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - buf_append_char(&ctok->cur_tok->data.str_lit, *c); - } - break; - case CTokStateExpectChar: - switch (*c) { - case '\\': - ctok->state = CTokStateCharEscape; - break; - case '\'': - return mark_error(ctok); - default: - ctok->cur_tok->data.char_lit = *c; - ctok->state = CTokStateExpectEndQuot; - } - break; - case CTokStateCharEscape: - switch (*c) { - case '\'': - case '"': - case '?': - case '\\': - add_char(ctok, *c); - break; - case 'a': - add_char(ctok, '\a'); - break; - case 'b': - add_char(ctok, '\b'); - break; - case 'f': - add_char(ctok, '\f'); - break; - case 'n': - add_char(ctok, '\n'); - break; - case 'r': - add_char(ctok, '\r'); - break; - case 't': - add_char(ctok, '\t'); - break; - case 'v': - add_char(ctok, '\v'); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - ctok->state = CTokStateStrOctal; - ctok->cur_char = (uint8_t)(*c - '0'); - ctok->octal_index = 1; - break; - case 'x': - ctok->state = CTokStateStrHex; - ctok->cur_char = 0; - break; - case 'u': - zig_panic("TODO unicode"); - break; - case 'U': - zig_panic("TODO Unicode"); - break; - default: - return mark_error(ctok); - } - break; - case CTokStateStrHex: { - uint8_t value = 0; - switch (*c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - value = *c - '0'; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - value = (*c - 'a') + 10; - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - value = (*c - 'A') + 10; - break; - default: - c -= 1; - add_char(ctok, ctok->cur_char); - continue; - } - // TODO @mul_with_overflow - if (((long)ctok->cur_char) * 16 >= 256) { - zig_panic("TODO str hex mul overflow"); - } - ctok->cur_char = (uint8_t)(ctok->cur_char * (uint8_t)16); - // TODO @add_with_overflow - if (((long)ctok->cur_char) + (long)(value) >= 256) { - zig_panic("TODO str hex add overflow"); - } - ctok->cur_char = (uint8_t)(ctok->cur_char + value); - break; - } - case CTokStateStrOctal: - switch (*c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - // TODO @mul_with_overflow - if (((long)ctok->cur_char) * 8 >= 256) { - zig_panic("TODO"); - } - ctok->cur_char = (uint8_t)(ctok->cur_char * (uint8_t)8); - // TODO @add_with_overflow - if (((long)ctok->cur_char) + (long)(*c - '0') >= 256) { - zig_panic("TODO"); - } - ctok->cur_char = (uint8_t)(ctok->cur_char + (uint8_t)(*c - '0')); - ctok->octal_index += 1; - if (ctok->octal_index == 3) { - add_char(ctok, ctok->cur_char); - } - break; - default: - c -= 1; - add_char(ctok, ctok->cur_char); - continue; - } - break; - case CTokStateExpectEndQuot: - switch (*c) { - case '\'': - end_token(ctok); - ctok->state = CTokStateStart; - break; - default: - return mark_error(ctok); - } - break; - case CTokStateOpenComment: - switch (*c) { - case '/': - ctok->state = CTokStateLineComment; - break; - case '*': - ctok->state = CTokStateComment; - break; - default: - return mark_error(ctok); - } - break; - case CTokStateLineComment: - if (*c == '\n') { - ctok->state = CTokStateStart; - goto found_end_of_macro; - } - break; - case CTokStateComment: - switch (*c) { - case '*': - ctok->state = CTokStateCommentStar; - break; - default: - break; - } - break; - case CTokStateCommentStar: - switch (*c) { - case '/': - ctok->state = CTokStateStart; - break; - case '*': - break; - default: - ctok->state = CTokStateComment; - break; - } - break; - case CTokStateBackslash: - switch (*c) { - case '\n': - ctok->state = CTokStateStart; - break; - default: - return mark_error(ctok); - } - break; - } - } -found_end_of_macro: - - switch (ctok->state) { - case CTokStateStart: - break; - case CTokStateIdentifier: - case CTokStateDecimal: - case CTokStateHex: - case CTokStateOctal: - case CTokStateGotZero: - case CTokStateNumLitIntSuffixU: - case CTokStateNumLitIntSuffixL: - case CTokStateNumLitIntSuffixUL: - case CTokStateNumLitIntSuffixLL: - case CTokStateGotLt: - end_token(ctok); - break; - case CTokStateFloat: - case CTokStateFloatExp: - end_float(ctok); - break; - case CTokStateExpectChar: - case CTokStateExpectEndQuot: - case CTokStateOpenComment: - case CTokStateLineComment: - case CTokStateComment: - case CTokStateCommentStar: - case CTokStateCharEscape: - case CTokStateBackslash: - case CTokStateString: - case CTokStateExpSign: - case CTokStateFloatExpFirst: - case CTokStateStrHex: - case CTokStateStrOctal: - return mark_error(ctok); - } - - assert(ctok->cur_tok == nullptr); - - begin_token(ctok, CTokIdEOF); - end_token(ctok); -} diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp deleted file mode 100644 index eaca09098f8a..000000000000 --- a/src/c_tokenizer.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - - -#ifndef ZIG_C_TOKENIZER_HPP -#define ZIG_C_TOKENIZER_HPP - -#include "buffer.hpp" - -enum CTokId { - CTokIdCharLit, - CTokIdStrLit, - CTokIdNumLitInt, - CTokIdNumLitFloat, - CTokIdSymbol, - CTokIdMinus, - CTokIdLParen, - CTokIdRParen, - CTokIdEOF, - CTokIdDot, - CTokIdAsterisk, - CTokIdBang, - CTokIdTilde, - CTokIdShl, - CTokIdLt, -}; - -enum CNumLitSuffix { - CNumLitSuffixNone, - CNumLitSuffixL, - CNumLitSuffixU, - CNumLitSuffixLU, - CNumLitSuffixLL, - CNumLitSuffixLLU, -}; - -struct CNumLitInt { - uint64_t x; - CNumLitSuffix suffix; -}; - -struct CTok { - enum CTokId id; - union { - uint8_t char_lit; - Buf str_lit; - CNumLitInt num_lit_int; - double num_lit_float; - Buf symbol; - } data; -}; - -enum CTokState { - CTokStateStart, - CTokStateExpectChar, - CTokStateCharEscape, - CTokStateExpectEndQuot, - CTokStateOpenComment, - CTokStateLineComment, - CTokStateComment, - CTokStateCommentStar, - CTokStateBackslash, - CTokStateString, - CTokStateIdentifier, - CTokStateDecimal, - CTokStateOctal, - CTokStateGotZero, - CTokStateHex, - CTokStateFloat, - CTokStateExpSign, - CTokStateFloatExp, - CTokStateFloatExpFirst, - CTokStateStrHex, - CTokStateStrOctal, - CTokStateNumLitIntSuffixU, - CTokStateNumLitIntSuffixL, - CTokStateNumLitIntSuffixLL, - CTokStateNumLitIntSuffixUL, - CTokStateGotLt, -}; - -struct CTokenize { - ZigList tokens; - CTokState state; - bool error; - CTok *cur_tok; - Buf buf; - uint8_t cur_char; - int octal_index; -}; - -void tokenize_c_macro(CTokenize *ctok, const uint8_t *c); - -#endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 320d5c75d536..734fc3be2bde 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -15,7 +15,6 @@ #include "hash_map.hpp" #include "ir.hpp" #include "os.hpp" -#include "translate_c.hpp" #include "target.hpp" #include "util.hpp" #include "zig_llvm.h" @@ -9104,7 +9103,7 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa } -void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_userland_implementation) { +void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file) { Error err; Buf *src_basename = buf_alloc(); Buf *src_dirname = buf_alloc(); @@ -9117,10 +9116,6 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us init(g); - TranslateMode trans_mode = buf_ends_with_str(full_path, ".h") ? - TranslateModeImport : TranslateModeTranslate; - - ZigList clang_argv = {0}; add_cc_args(g, clang_argv, nullptr, true); @@ -9140,15 +9135,9 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us Stage2ErrorMsg *errors_ptr; size_t errors_len; Stage2Ast *ast; - AstNode *root_node; - if (use_userland_implementation) { - err = stage2_translate_c(&ast, &errors_ptr, &errors_len, - &clang_argv.at(0), &clang_argv.last(), resources_path); - } else { - err = parse_h_file(g, &root_node, &errors_ptr, &errors_len, &clang_argv.at(0), &clang_argv.last(), - trans_mode, resources_path); - } + err = stage2_translate_c(&ast, &errors_ptr, &errors_len, + &clang_argv.at(0), &clang_argv.last(), resources_path); if (err == ErrorCCompileErrors && errors_len > 0) { for (size_t i = 0; i < errors_len; i += 1) { @@ -9172,12 +9161,7 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us exit(1); } - - if (use_userland_implementation) { - stage2_render_ast(ast, out_file); - } else { - ast_render(out_file, root_node, 4); - } + stage2_render_ast(ast, out_file); } static void update_test_functions_builtin_decl(CodeGen *g) { diff --git a/src/codegen.hpp b/src/codegen.hpp index 6dd914f9a33d..4f06d4b65df7 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -54,7 +54,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c void codegen_add_assembly(CodeGen *g, Buf *path); void codegen_add_object(CodeGen *g, Buf *object_path); -void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_userland_implementation); +void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file); Buf *codegen_generate_builtin_source(CodeGen *g); diff --git a/src/ir.cpp b/src/ir.cpp index 7cc182934109..e52f4fbbe090 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13,7 +13,6 @@ #include "os.hpp" #include "range_set.hpp" #include "softfloat.hpp" -#include "translate_c.hpp" #include "util.hpp" #include @@ -23758,14 +23757,14 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct clang_argv.append(nullptr); // to make the [start...end] argument work - AstNode *root_node; Stage2ErrorMsg *errors_ptr; size_t errors_len; + Stage2Ast *ast; const char *resources_path = buf_ptr(ira->codegen->zig_c_headers_dir); - if ((err = parse_h_file(ira->codegen, &root_node, &errors_ptr, &errors_len, - &clang_argv.at(0), &clang_argv.last(), TranslateModeImport, resources_path))) + if ((err = stage2_translate_c(&ast, &errors_ptr, &errors_len, + &clang_argv.at(0), &clang_argv.last(), resources_path))) { if (err != ErrorCCompileErrors) { ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err))); @@ -23816,7 +23815,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct buf_sprintf("C import failed: unable to open output file: %s", strerror(errno))); return ira->codegen->invalid_instruction; } - ast_render(out_file, root_node, 4); + stage2_render_ast(ast, out_file); if (fclose(out_file) != 0) { ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to write to output file: %s", strerror(errno))); diff --git a/src/main.cpp b/src/main.cpp index 2cda18f7a0d9..43a89b4efe5a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -243,7 +243,6 @@ enum Cmd { CmdTargets, CmdTest, CmdTranslateC, - CmdTranslateCUserland, CmdVersion, CmdZen, CmdLibC, @@ -960,8 +959,6 @@ int main(int argc, char **argv) { cmd = CmdLibC; } else if (strcmp(arg, "translate-c") == 0) { cmd = CmdTranslateC; - } else if (strcmp(arg, "translate-c-2") == 0) { - cmd = CmdTranslateCUserland; } else if (strcmp(arg, "test") == 0) { cmd = CmdTest; out_type = OutTypeExe; @@ -978,7 +975,6 @@ int main(int argc, char **argv) { case CmdBuild: case CmdRun: case CmdTranslateC: - case CmdTranslateCUserland: case CmdTest: case CmdLibC: if (!in_file) { @@ -1112,7 +1108,6 @@ int main(int argc, char **argv) { case CmdRun: case CmdBuild: case CmdTranslateC: - case CmdTranslateCUserland: case CmdTest: { if (cmd == CmdBuild && !in_file && objects.length == 0 && @@ -1124,7 +1119,7 @@ int main(int argc, char **argv) { " * --object argument\n" " * --c-source argument\n"); return print_error_usage(arg0); - } else if ((cmd == CmdTranslateC || cmd == CmdTranslateCUserland || + } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { fprintf(stderr, "Expected source file argument.\n"); @@ -1136,7 +1131,7 @@ int main(int argc, char **argv) { assert(cmd != CmdBuild || out_type != OutTypeUnknown); - bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC || cmd == CmdTranslateCUserland); + bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); if (cmd == CmdRun) { out_name = "run"; @@ -1170,8 +1165,7 @@ int main(int argc, char **argv) { return print_error_usage(arg0); } - Buf *zig_root_source_file = (cmd == CmdTranslateC || cmd == CmdTranslateCUserland) ? - nullptr : in_file_buf; + Buf *zig_root_source_file = cmd == CmdTranslateC ? nullptr : in_file_buf; if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); @@ -1336,8 +1330,8 @@ int main(int argc, char **argv) { } else { zig_unreachable(); } - } else if (cmd == CmdTranslateC || cmd == CmdTranslateCUserland) { - codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland); + } else if (cmd == CmdTranslateC) { + codegen_translate_c(g, in_file_buf, stdout); if (timing_info) codegen_print_timing_report(g, stderr); return main_exit(root_progress_node, EXIT_SUCCESS); diff --git a/src/translate_c.cpp b/src/translate_c.cpp deleted file mode 100644 index 5b79bfe989d0..000000000000 --- a/src/translate_c.cpp +++ /dev/null @@ -1,5156 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ -#include "all_types.hpp" -#include "analyze.hpp" -#include "c_tokenizer.hpp" -#include "error.hpp" -#include "ir.hpp" -#include "os.hpp" -#include "translate_c.hpp" -#include "parser.hpp" -#include "zig_clang.h" - -#include - -struct Alias { - Buf *new_name; - Buf *canon_name; -}; - -enum TransScopeId { - TransScopeIdSwitch, - TransScopeIdVar, - TransScopeIdBlock, - TransScopeIdRoot, - TransScopeIdWhile, -}; - -struct TransScope { - TransScopeId id; - TransScope *parent; -}; - -struct TransScopeSwitch { - TransScope base; - AstNode *switch_node; - uint32_t case_index; - bool found_default; - Buf *end_label_name; -}; - -struct TransScopeVar { - TransScope base; - Buf *c_name; - Buf *zig_name; -}; - -struct TransScopeBlock { - TransScope base; - AstNode *node; -}; - -struct TransScopeRoot { - TransScope base; -}; - -struct TransScopeWhile { - TransScope base; - AstNode *node; -}; - -struct Context { - AstNode *root; - bool want_export; - HashMap decl_table; - HashMap macro_table; - HashMap global_table; - ZigClangSourceManager *source_manager; - ZigList aliases; - bool warnings_on; - - CodeGen *codegen; - ZigClangASTContext *ctx; - - TransScopeRoot *global_scope; - HashMap ptr_params; -}; - -enum ResultUsed { - ResultUsedNo, - ResultUsedYes, -}; - -enum TransLRValue { - TransLValue, - TransRValue, -}; - -static TransScopeRoot *trans_scope_root_create(Context *c); -static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); -static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); -static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); -static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope); - -static TransScopeBlock *trans_scope_block_find(TransScope *scope); - -static AstNode *resolve_record_decl(Context *c, const ZigClangRecordDecl *record_decl); -static AstNode *resolve_enum_decl(Context *c, const ZigClangEnumDecl *enum_decl); -static AstNode *resolve_typedef_decl(Context *c, const ZigClangTypedefNameDecl *typedef_decl); - -static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *stmt, - ResultUsed result_used, TransLRValue lrval, - AstNode **out_node, TransScope **out_child_scope, - TransScope **out_node_scope); -static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node); -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval); -static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc); -static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc); -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangExpr *expr, TransLRValue lrval); -static AstNode *trans_ap_value(Context *c, const ZigClangAPValue *ap_value, ZigClangQualType qt, - ZigClangSourceLocation source_loc); -static bool c_is_unsigned_integer(Context *c, ZigClangQualType qt); - - -ATTRIBUTE_PRINTF(3, 4) -static void emit_warning(Context *c, ZigClangSourceLocation sl, const char *format, ...) { - if (!c->warnings_on) { - return; - } - - va_list ap; - va_start(ap, format); - Buf *msg = buf_vprintf(format, ap); - va_end(ap); - - const char *filename_bytes = ZigClangSourceManager_getFilename(c->source_manager, - ZigClangSourceManager_getSpellingLoc(c->source_manager, sl)); - Buf *path; - if (filename_bytes) { - path = buf_create_from_str(filename_bytes); - } else { - path = buf_sprintf("(no file)"); - } - unsigned line = ZigClangSourceManager_getSpellingLineNumber(c->source_manager, sl); - unsigned column = ZigClangSourceManager_getSpellingColumnNumber(c->source_manager, sl); - fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); -} - -static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { - Alias *alias = c->aliases.add_one(); - alias->new_name = new_name; - alias->canon_name = canon_name; -} - -static Buf *trans_lookup_zig_symbol(Context *c, TransScope *scope, Buf *c_symbol_name) { - while (scope != nullptr) { - if (scope->id == TransScopeIdVar) { - TransScopeVar *var_scope = (TransScopeVar *)scope; - if (buf_eql_buf(var_scope->c_name, c_symbol_name)) { - return var_scope->zig_name; - } - } - scope = scope->parent; - } - return c_symbol_name; -} - -static AstNode * trans_create_node(Context *c, NodeType id) { - AstNode *node = allocate(1); - node->type = id; - // TODO line/column. mapping to C file?? - return node; -} - -static AstNode *trans_create_node_break(Context *c, Buf *label_name, AstNode *value_node) { - AstNode *node = trans_create_node(c, NodeTypeBreak); - node->data.break_expr.name = label_name; - node->data.break_expr.expr = value_node; - return node; -} - -static AstNode *trans_create_node_return(Context *c, AstNode *value_node) { - AstNode *node = trans_create_node(c, NodeTypeReturnExpr); - node->data.return_expr.kind = ReturnKindUnconditional; - node->data.return_expr.expr = value_node; - return node; -} - -static AstNode *trans_create_node_if(Context *c, AstNode *cond_node, AstNode *then_node, AstNode *else_node) { - AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); - node->data.if_bool_expr.condition = cond_node; - node->data.if_bool_expr.then_block = then_node; - node->data.if_bool_expr.else_node = else_node; - return node; -} - -static AstNode *trans_create_node_float_lit(Context *c, double value) { - AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); - node->data.float_literal.bigfloat = allocate(1); - bigfloat_init_64(node->data.float_literal.bigfloat, value); - return node; -} - -static AstNode *trans_create_node_symbol(Context *c, Buf *name) { - AstNode *node = trans_create_node(c, NodeTypeSymbol); - node->data.symbol_expr.symbol = name; - return node; -} - -static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { - return trans_create_node_symbol(c, buf_create_from_str(name)); -} - -static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { - AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); - node->data.fn_call_expr.modifier = CallModifierBuiltin; - return node; -} - -static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { - return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); -} - -static AstNode *trans_create_node_opaque(Context *c) { - return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); -} - -static AstNode *trans_create_node_cast(Context *c, AstNode *dest_type, AstNode *operand) { - AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, buf_create_from_str("as")); - node->data.fn_call_expr.modifier = CallModifierBuiltin; - node->data.fn_call_expr.params.append(dest_type); - node->data.fn_call_expr.params.append(operand); - return node; -} - -static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { - AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; - node->data.fn_call_expr.params.append(arg1); - return node; -} - -static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { - AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); - if (container->type == NodeTypeSymbol) { - assert(container->data.symbol_expr.symbol != nullptr); - } - node->data.field_access_expr.struct_expr = container; - node->data.field_access_expr.field_name = field_name; - return node; -} - -static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { - return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); -} - -static AstNode *trans_create_node_ptr_deref(Context *c, AstNode *child_node) { - AstNode *node = trans_create_node(c, NodeTypePtrDeref); - node->data.ptr_deref_expr.target = child_node; - return node; -} - -static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { - AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); - node->data.prefix_op_expr.prefix_op = op; - node->data.prefix_op_expr.primary_expr = child_node; - return node; -} - -static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child_node) { - AstNode *node = trans_create_node(c, NodeTypeUnwrapOptional); - node->data.unwrap_optional.expr = child_node; - return node; -} - -static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.op1 = lhs_node; - node->data.bin_op_expr.bin_op = op; - node->data.bin_op_expr.op2 = rhs_node; - return node; -} - -static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNode *node) { - if (result_used == ResultUsedYes) return node; - return trans_create_node_bin_op(c, - trans_create_node_symbol_str(c, "_"), - BinOpTypeAssign, - node); -} - -static TokenId ptr_len_to_token_id(PtrLen ptr_len) { - switch (ptr_len) { - case PtrLenSingle: - return TokenIdStar; - case PtrLenUnknown: - return TokenIdLBracket; - case PtrLenC: - return TokenIdSymbol; - } - zig_unreachable(); -} - -static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) { - AstNode *node = trans_create_node(c, NodeTypePointerType); - node->data.pointer_type.star_token = allocate(1); - node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len); - node->data.pointer_type.is_const = is_const; - node->data.pointer_type.is_volatile = is_volatile; - node->data.pointer_type.op_expr = child_node; - return node; -} - -static AstNode *trans_create_node_addr_of(Context *c, AstNode *child_node) { - AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); - node->data.prefix_op_expr.prefix_op = PrefixOpAddrOf; - node->data.prefix_op_expr.primary_expr = child_node; - return node; -} - -static AstNode *trans_create_node_bool(Context *c, bool value) { - AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral); - bool_node->data.bool_literal.value = value; - return bool_node; -} - -static AstNode *trans_create_node_str_lit(Context *c, Buf *buf) { - AstNode *node = trans_create_node(c, NodeTypeStringLiteral); - node->data.string_literal.buf = buf; - return node; -} - -static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { - AstNode *node = trans_create_node(c, NodeTypeIntLiteral); - node->data.int_literal.bigint = allocate(1); - bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); - return node; -} - -static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { - return trans_create_node_unsigned_negative(c, x, false); -} - -static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, - const char *type_name) -{ - AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); - return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); -} - -static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { - AstNode *node = trans_create_node(c, NodeTypeArrayType); - node->data.array_type.size = size_node; - node->data.array_type.child_type = child_type_node; - return node; -} - -static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, - AstNode *type_node, AstNode *init_node) -{ - AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); - node->data.variable_declaration.visib_mod = visib_mod; - node->data.variable_declaration.symbol = var_name; - node->data.variable_declaration.is_const = is_const; - node->data.variable_declaration.type = type_node; - node->data.variable_declaration.expr = init_node; - return node; -} - -static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, - AstNode *init_node) -{ - return trans_create_node_var_decl(c, VisibModPub, is_const, var_name, type_node, init_node); -} - -static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, - AstNode *init_node) -{ - return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); -} - -static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) { - AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); - AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); - fn_proto->data.fn_proto.visib_mod = VisibModPub; - fn_proto->data.fn_proto.name = fn_name; - fn_proto->data.fn_proto.fn_inline = FnInlineAlways; - fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? - - fn_def->data.fn_def.fn_proto = fn_proto; - fn_proto->data.fn_proto.fn_def_node = fn_def; - - AstNode *unwrap_node = trans_create_node_unwrap_null(c, ref_node); - AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); - fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; - - for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { - AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); - Buf *param_name = src_param_node->data.param_decl.name; - if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - - AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); - dest_param_node->data.param_decl.name = param_name; - dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; - dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; - fn_proto->data.fn_proto.params.append(dest_param_node); - - fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); - - } - - AstNode *block = trans_create_node(c, NodeTypeBlock); - block->data.block.statements.resize(1); - block->data.block.statements.items[0] = trans_create_node_return(c, fn_call_node); - - fn_def->data.fn_def.body = block; - return fn_def; -} - -static AstNode *trans_create_node_grouped_expr(Context *c, AstNode *child) { - AstNode *node = trans_create_node(c, NodeTypeGroupedExpr); - node->data.grouped_expr = child; - return node; -} - -static AstNode *get_global(Context *c, Buf *name) { - { - auto entry = c->global_table.maybe_get(name); - if (entry) { - return entry->value; - } - } - { - auto entry = c->macro_table.maybe_get(name); - if (entry) - return entry->value; - } - ZigType *type; - if (get_primitive_type(c->codegen, name, &type) != ErrorPrimitiveTypeNotFound) { - return trans_create_node_symbol(c, name); - } - return nullptr; -} - -static void add_top_level_decl(Context *c, Buf *name, AstNode *node) { - c->global_table.put(name, node); - c->root->data.container_decl.decls.append(node); -} - -static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { - bool is_const = true; - AstNode *type_node = nullptr; - AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); - add_top_level_decl(c, var_name, node); - return node; -} - -static AstNode *trans_create_node_apint(Context *c, const ZigClangAPSInt *aps_int) { - AstNode *node = trans_create_node(c, NodeTypeIntLiteral); - node->data.int_literal.bigint = allocate(1); - bool is_negative = ZigClangAPSInt_isSigned(aps_int) && ZigClangAPSInt_isNegative(aps_int); - if (!is_negative) { - bigint_init_data(node->data.int_literal.bigint, - ZigClangAPSInt_getRawData(aps_int), - ZigClangAPSInt_getNumWords(aps_int), - false); - return node; - } - const ZigClangAPSInt *negated = ZigClangAPSInt_negate(aps_int); - bigint_init_data(node->data.int_literal.bigint, ZigClangAPSInt_getRawData(negated), - ZigClangAPSInt_getNumWords(negated), true); - ZigClangAPSInt_free(negated); - return node; -} - -static AstNode *trans_create_node_apfloat(Context *c, const ZigClangAPFloat *ap_float) { - uint8_t buf[128]; - size_t written = ZigClangAPFloat_convertToHexString(ap_float, (char *)buf, 0, false, - ZigClangAPFloat_roundingMode_NearestTiesToEven); - AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); - node->data.float_literal.bigfloat = allocate(1); - if (bigfloat_init_buf(node->data.float_literal.bigfloat, buf, written)) { - node->data.float_literal.overflow = true; - } - return node; -} - -static const ZigClangType *qual_type_canon(ZigClangQualType qt) { - ZigClangQualType canon = ZigClangQualType_getCanonicalType(qt); - return ZigClangQualType_getTypePtr(canon); -} - -static ZigClangQualType get_expr_qual_type(Context *c, const ZigClangExpr *expr) { - // String literals in C are `char *` but they should really be `const char *`. - if (ZigClangExpr_getStmtClass(expr) == ZigClangStmt_ImplicitCastExprClass) { - const ZigClangImplicitCastExpr *cast_expr = reinterpret_cast(expr); - if (ZigClangImplicitCastExpr_getCastKind(cast_expr) == ZigClangCK_ArrayToPointerDecay) { - const ZigClangExpr *sub_expr = ZigClangImplicitCastExpr_getSubExpr(cast_expr); - if (ZigClangExpr_getStmtClass(sub_expr) == ZigClangStmt_StringLiteralClass) { - ZigClangQualType array_qt = ZigClangExpr_getType(sub_expr); - const ZigClangArrayType *array_type = reinterpret_cast( - ZigClangQualType_getTypePtr(array_qt)); - ZigClangQualType pointee_qt = ZigClangArrayType_getElementType(array_type); - ZigClangQualType_addConst(&pointee_qt); - return ZigClangASTContext_getPointerType(c->ctx, pointee_qt); - } - } - } - return ZigClangExpr_getType(expr); -} - -static ZigClangQualType get_expr_qual_type_before_implicit_cast(Context *c, const ZigClangExpr *expr) { - if (ZigClangExpr_getStmtClass(expr) == ZigClangStmt_ImplicitCastExprClass) { - const ZigClangImplicitCastExpr *cast_expr = reinterpret_cast(expr); - return get_expr_qual_type(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr)); - } - return ZigClangExpr_getType(expr); -} - -static AstNode *get_expr_type(Context *c, const ZigClangExpr *expr) { - return trans_qual_type(c, get_expr_qual_type(c, expr), ZigClangExpr_getBeginLoc(expr)); -} - -static bool is_c_void_type(AstNode *node) { - return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); -} - -static bool qual_type_is_ptr(ZigClangQualType qt) { - const ZigClangType *ty = qual_type_canon(qt); - return ZigClangType_getTypeClass(ty) == ZigClangType_Pointer; -} - -static const ZigClangFunctionProtoType *qual_type_get_fn_proto(ZigClangQualType qt, bool *is_ptr) { - const ZigClangType *ty = qual_type_canon(qt); - *is_ptr = false; - - if (ZigClangType_getTypeClass(ty) == ZigClangType_Pointer) { - *is_ptr = true; - ZigClangQualType child_qt = ZigClangType_getPointeeType(ty); - ty = ZigClangQualType_getTypePtr(child_qt); - } - - if (ZigClangType_getTypeClass(ty) == ZigClangType_FunctionProto) { - return reinterpret_cast(ty); - } - - return nullptr; -} - -static bool qual_type_is_fn_ptr(ZigClangQualType qt) { - bool is_ptr; - if (qual_type_get_fn_proto(qt, &is_ptr)) { - return is_ptr; - } - - return false; -} - -static uint32_t qual_type_int_bit_width(Context *c, const ZigClangQualType qt, ZigClangSourceLocation source_loc) { - const ZigClangType *ty = ZigClangQualType_getTypePtr(qt); - switch (ZigClangType_getTypeClass(ty)) { - case ZigClangType_Builtin: - { - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(ty); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeChar_U: - case ZigClangBuiltinTypeUChar: - case ZigClangBuiltinTypeChar_S: - case ZigClangBuiltinTypeSChar: - return 8; - case ZigClangBuiltinTypeUInt128: - case ZigClangBuiltinTypeInt128: - return 128; - default: - return 0; - } - zig_unreachable(); - } - case ZigClangType_Typedef: - { - const ZigClangTypedefType *typedef_ty = reinterpret_cast(ty); - const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - const char *type_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)typedef_decl); - if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { - return 8; - } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { - return 16; - } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { - return 32; - } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { - return 64; - } else { - return 0; - } - } - default: - return 0; - } - zig_unreachable(); -} - - -static AstNode *qual_type_to_log2_int_ref(Context *c, const ZigClangQualType qt, - ZigClangSourceLocation source_loc) -{ - uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); - if (int_bit_width != 0) { - // we can perform the log2 now. - uint64_t cast_bit_width = log2_u64(int_bit_width); - return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); - } - - AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); - -// @import("std").math.Log2Int(c_long); -// -// FnCall -// FieldAccess -// FieldAccess -// FnCall (.builtin = true) -// Symbol "import" -// ZigClangStringLiteral "std" -// Symbol "math" -// Symbol "Log2Int" -// zig_type_node - - AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); - import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("std"))); - AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); - AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); - AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); - - return log2int_fn_call; -} - -static bool qual_type_child_is_fn_proto(ZigClangQualType qt) { - const ZigClangType *ty = ZigClangQualType_getTypePtr(qt); - if (ZigClangType_getTypeClass(ty) == ZigClangType_Paren) { - const ZigClangParenType *paren_type = reinterpret_cast(ty); - ZigClangQualType inner_type = ZigClangParenType_getInnerType(paren_type); - if (ZigClangQualType_getTypeClass(inner_type) == ZigClangType_FunctionProto) { - return true; - } - } else if (ZigClangType_getTypeClass(ty) == ZigClangType_Attributed) { - const ZigClangAttributedType *attr_type = reinterpret_cast(ty); - return qual_type_child_is_fn_proto(ZigClangAttributedType_getEquivalentType(attr_type)); - } - return false; -} - -static AstNode* trans_c_ptr_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type, - ZigClangQualType src_type, AstNode *expr) -{ - const ZigClangType *ty = ZigClangQualType_getTypePtr(dest_type); - const ZigClangQualType child_type = ZigClangType_getPointeeType(ty); - - AstNode *dest_type_node = trans_type(c, ty, source_location); - AstNode *child_type_node = trans_qual_type(c, child_type, source_location); - - // Implicit downcasting from higher to lower alignment values is forbidden, - // use @alignCast to side-step this problem - AstNode *ptrcast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); - ptrcast_node->data.fn_call_expr.params.append(dest_type_node); - - if (ZigClangType_isVoidType(qual_type_canon(child_type))) { - // void has 1-byte alignment - ptrcast_node->data.fn_call_expr.params.append(expr); - } else { - AstNode *alignof_node = trans_create_node_builtin_fn_call_str(c, "alignOf"); - alignof_node->data.fn_call_expr.params.append(child_type_node); - AstNode *aligncast_node = trans_create_node_builtin_fn_call_str(c, "alignCast"); - aligncast_node->data.fn_call_expr.params.append(alignof_node); - aligncast_node->data.fn_call_expr.params.append(expr); - - ptrcast_node->data.fn_call_expr.params.append(aligncast_node); - } - - return ptrcast_node; -} - -static AstNode* trans_c_cast(Context *c, ZigClangSourceLocation source_location, ZigClangQualType dest_type, - ZigClangQualType src_type, AstNode *expr) -{ - // The only way void pointer casts are valid C code, is if - // the value of the expression is ignored. We therefore just - // return the expr, and let the system that ignores values - // translate this correctly. - if (ZigClangType_isVoidType(qual_type_canon(dest_type))) { - return expr; - } - if (ZigClangQualType_eq(dest_type, src_type)) { - return expr; - } - if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) { - return trans_c_ptr_cast(c, source_location, dest_type, src_type, expr); - } - if (c_is_unsigned_integer(c, dest_type) && qual_type_is_ptr(src_type)) { - AstNode *addr_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); - addr_node->data.fn_call_expr.params.append(expr); - return trans_create_node_cast(c, trans_qual_type(c, dest_type, source_location), addr_node); - } - if (c_is_unsigned_integer(c, src_type) && qual_type_is_ptr(dest_type)) { - AstNode *ptr_node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); - ptr_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location)); - ptr_node->data.fn_call_expr.params.append(expr); - return ptr_node; - } - // TODO: maybe widen to increase size - // TODO: maybe bitcast to change sign - // TODO: maybe truncate to reduce size - return trans_create_node_cast(c, trans_qual_type(c, dest_type, source_location), expr); -} - -static bool c_is_signed_integer(Context *c, ZigClangQualType qt) { - const ZigClangType *c_type = qual_type_canon(qt); - if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) - return false; - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(c_type); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeSChar: - case ZigClangBuiltinTypeShort: - case ZigClangBuiltinTypeInt: - case ZigClangBuiltinTypeLong: - case ZigClangBuiltinTypeLongLong: - case ZigClangBuiltinTypeInt128: - case ZigClangBuiltinTypeWChar_S: - return true; - default: - return false; - } -} - -static bool c_is_unsigned_integer(Context *c, ZigClangQualType qt) { - const ZigClangType *c_type = qual_type_canon(qt); - if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) - return false; - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(c_type); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeChar_U: - case ZigClangBuiltinTypeUChar: - case ZigClangBuiltinTypeChar_S: - case ZigClangBuiltinTypeUShort: - case ZigClangBuiltinTypeUInt: - case ZigClangBuiltinTypeULong: - case ZigClangBuiltinTypeULongLong: - case ZigClangBuiltinTypeUInt128: - case ZigClangBuiltinTypeWChar_U: - return true; - default: - return false; - } -} - -static bool c_is_builtin_type(Context *c, ZigClangQualType qt, ZigClangBuiltinTypeKind kind) { - const ZigClangType *c_type = qual_type_canon(qt); - if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) - return false; - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(c_type); - return ZigClangBuiltinType_getKind(builtin_ty) == kind; -} - -static bool c_is_float(Context *c, ZigClangQualType qt) { - const ZigClangType *c_type = ZigClangQualType_getTypePtr(qt); - if (ZigClangType_getTypeClass(c_type) != ZigClangType_Builtin) - return false; - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(c_type); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeHalf: - case ZigClangBuiltinTypeFloat: - case ZigClangBuiltinTypeDouble: - case ZigClangBuiltinTypeFloat128: - case ZigClangBuiltinTypeLongDouble: - return true; - default: - return false; - } -} - -static bool qual_type_has_wrapping_overflow(Context *c, ZigClangQualType qt) { - if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { - // float and signed integer overflow is undefined behavior. - return false; - } else { - // unsigned integer overflow wraps around. - return true; - } -} - -static bool type_is_function(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { - switch (ZigClangType_getTypeClass(ty)) { - case ZigClangType_FunctionProto: - case ZigClangType_FunctionNoProto: - return true; - case ZigClangType_Elaborated: { - const ZigClangElaboratedType *elaborated_ty = reinterpret_cast(ty); - ZigClangQualType qt = ZigClangElaboratedType_getNamedType(elaborated_ty); - return type_is_function(c, ZigClangQualType_getTypePtr(qt), source_loc); - } - case ZigClangType_Typedef: { - const ZigClangTypedefType *typedef_ty = reinterpret_cast(ty); - const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - ZigClangQualType underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); - return type_is_function(c, ZigClangQualType_getTypePtr(underlying_type), source_loc); - } - default: - return false; - } -} - -static bool type_is_opaque(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { - switch (ZigClangType_getTypeClass(ty)) { - case ZigClangType_Builtin: { - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(ty); - return ZigClangBuiltinType_getKind(builtin_ty) == ZigClangBuiltinTypeVoid; - } - case ZigClangType_Record: { - const ZigClangRecordType *record_ty = reinterpret_cast(ty); - const ZigClangRecordDecl *record_decl = ZigClangRecordType_getDecl(record_ty); - const ZigClangRecordDecl *record_def = ZigClangRecordDecl_getDefinition(record_decl); - if (record_def == nullptr) { - return true; - } - for (ZigClangRecordDecl_field_iterator it = ZigClangRecordDecl_field_begin(record_def), - it_end = ZigClangRecordDecl_field_end(record_def); - ZigClangRecordDecl_field_iterator_neq(it, it_end); - it = ZigClangRecordDecl_field_iterator_next(it)) - { - const ZigClangFieldDecl *field_decl = ZigClangRecordDecl_field_iterator_deref(it); - - if (ZigClangFieldDecl_isBitField(field_decl)) { - return true; - } - } - return false; - } - case ZigClangType_Elaborated: { - const ZigClangElaboratedType *elaborated_ty = reinterpret_cast(ty); - ZigClangQualType qt = ZigClangElaboratedType_getNamedType(elaborated_ty); - return type_is_opaque(c, ZigClangQualType_getTypePtr(qt), source_loc); - } - case ZigClangType_Typedef: { - const ZigClangTypedefType *typedef_ty = reinterpret_cast(ty); - const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - ZigClangQualType underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); - return type_is_opaque(c, ZigClangQualType_getTypePtr(underlying_type), source_loc); - } - default: - return false; - } -} - -static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { - switch (ZigClangType_getTypeClass(ty)) { - case ZigClangType_Builtin: - { - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(ty); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeVoid: - return trans_create_node_symbol_str(c, "c_void"); - case ZigClangBuiltinTypeBool: - return trans_create_node_symbol_str(c, "bool"); - case ZigClangBuiltinTypeChar_U: - case ZigClangBuiltinTypeUChar: - case ZigClangBuiltinTypeChar_S: - case ZigClangBuiltinTypeChar8: - return trans_create_node_symbol_str(c, "u8"); - case ZigClangBuiltinTypeSChar: - return trans_create_node_symbol_str(c, "i8"); - case ZigClangBuiltinTypeUShort: - return trans_create_node_symbol_str(c, "c_ushort"); - case ZigClangBuiltinTypeUInt: - return trans_create_node_symbol_str(c, "c_uint"); - case ZigClangBuiltinTypeULong: - return trans_create_node_symbol_str(c, "c_ulong"); - case ZigClangBuiltinTypeULongLong: - return trans_create_node_symbol_str(c, "c_ulonglong"); - case ZigClangBuiltinTypeShort: - return trans_create_node_symbol_str(c, "c_short"); - case ZigClangBuiltinTypeInt: - return trans_create_node_symbol_str(c, "c_int"); - case ZigClangBuiltinTypeLong: - return trans_create_node_symbol_str(c, "c_long"); - case ZigClangBuiltinTypeLongLong: - return trans_create_node_symbol_str(c, "c_longlong"); - case ZigClangBuiltinTypeUInt128: - return trans_create_node_symbol_str(c, "u128"); - case ZigClangBuiltinTypeInt128: - return trans_create_node_symbol_str(c, "i128"); - case ZigClangBuiltinTypeFloat: - return trans_create_node_symbol_str(c, "f32"); - case ZigClangBuiltinTypeDouble: - return trans_create_node_symbol_str(c, "f64"); - case ZigClangBuiltinTypeFloat128: - return trans_create_node_symbol_str(c, "f128"); - case ZigClangBuiltinTypeFloat16: - return trans_create_node_symbol_str(c, "f16"); - case ZigClangBuiltinTypeLongDouble: - return trans_create_node_symbol_str(c, "c_longdouble"); - case ZigClangBuiltinTypeWChar_U: - case ZigClangBuiltinTypeChar16: - case ZigClangBuiltinTypeChar32: - case ZigClangBuiltinTypeWChar_S: - case ZigClangBuiltinTypeHalf: - case ZigClangBuiltinTypeNullPtr: - case ZigClangBuiltinTypeObjCId: - case ZigClangBuiltinTypeObjCClass: - case ZigClangBuiltinTypeObjCSel: - case ZigClangBuiltinTypeOMPArraySection: - case ZigClangBuiltinTypeDependent: - case ZigClangBuiltinTypeOverload: - case ZigClangBuiltinTypeBoundMember: - case ZigClangBuiltinTypePseudoObject: - case ZigClangBuiltinTypeUnknownAny: - case ZigClangBuiltinTypeBuiltinFn: - case ZigClangBuiltinTypeARCUnbridgedCast: - case ZigClangBuiltinTypeShortAccum: - case ZigClangBuiltinTypeAccum: - case ZigClangBuiltinTypeLongAccum: - case ZigClangBuiltinTypeUShortAccum: - case ZigClangBuiltinTypeUAccum: - case ZigClangBuiltinTypeULongAccum: - - case ZigClangBuiltinTypeOCLImage1dRO: - case ZigClangBuiltinTypeOCLImage1dArrayRO: - case ZigClangBuiltinTypeOCLImage1dBufferRO: - case ZigClangBuiltinTypeOCLImage2dRO: - case ZigClangBuiltinTypeOCLImage2dArrayRO: - case ZigClangBuiltinTypeOCLImage2dDepthRO: - case ZigClangBuiltinTypeOCLImage2dArrayDepthRO: - case ZigClangBuiltinTypeOCLImage2dMSAARO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAARO: - case ZigClangBuiltinTypeOCLImage2dMSAADepthRO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO: - case ZigClangBuiltinTypeOCLImage3dRO: - case ZigClangBuiltinTypeOCLImage1dWO: - case ZigClangBuiltinTypeOCLImage1dArrayWO: - case ZigClangBuiltinTypeOCLImage1dBufferWO: - case ZigClangBuiltinTypeOCLImage2dWO: - case ZigClangBuiltinTypeOCLImage2dArrayWO: - case ZigClangBuiltinTypeOCLImage2dDepthWO: - case ZigClangBuiltinTypeOCLImage2dArrayDepthWO: - case ZigClangBuiltinTypeOCLImage2dMSAAWO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAAWO: - case ZigClangBuiltinTypeOCLImage2dMSAADepthWO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO: - case ZigClangBuiltinTypeOCLImage3dWO: - case ZigClangBuiltinTypeOCLImage1dRW: - case ZigClangBuiltinTypeOCLImage1dArrayRW: - case ZigClangBuiltinTypeOCLImage1dBufferRW: - case ZigClangBuiltinTypeOCLImage2dRW: - case ZigClangBuiltinTypeOCLImage2dArrayRW: - case ZigClangBuiltinTypeOCLImage2dDepthRW: - case ZigClangBuiltinTypeOCLImage2dArrayDepthRW: - case ZigClangBuiltinTypeOCLImage2dMSAARW: - case ZigClangBuiltinTypeOCLImage2dArrayMSAARW: - case ZigClangBuiltinTypeOCLImage2dMSAADepthRW: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW: - case ZigClangBuiltinTypeOCLImage3dRW: - case ZigClangBuiltinTypeOCLSampler: - case ZigClangBuiltinTypeOCLEvent: - case ZigClangBuiltinTypeOCLClkEvent: - case ZigClangBuiltinTypeOCLQueue: - case ZigClangBuiltinTypeOCLReserveID: - case ZigClangBuiltinTypeShortFract: - case ZigClangBuiltinTypeFract: - case ZigClangBuiltinTypeLongFract: - case ZigClangBuiltinTypeUShortFract: - case ZigClangBuiltinTypeUFract: - case ZigClangBuiltinTypeULongFract: - case ZigClangBuiltinTypeSatShortAccum: - case ZigClangBuiltinTypeSatAccum: - case ZigClangBuiltinTypeSatLongAccum: - case ZigClangBuiltinTypeSatUShortAccum: - case ZigClangBuiltinTypeSatUAccum: - case ZigClangBuiltinTypeSatULongAccum: - case ZigClangBuiltinTypeSatShortFract: - case ZigClangBuiltinTypeSatFract: - case ZigClangBuiltinTypeSatLongFract: - case ZigClangBuiltinTypeSatUShortFract: - case ZigClangBuiltinTypeSatUFract: - case ZigClangBuiltinTypeSatULongFract: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin: - emit_warning(c, source_loc, "unsupported builtin type"); - return nullptr; - } - break; - } - case ZigClangType_Pointer: - { - ZigClangQualType child_qt = ZigClangType_getPointeeType(ty); - AstNode *child_node = trans_qual_type(c, child_qt, source_loc); - if (child_node == nullptr) { - emit_warning(c, source_loc, "pointer to unsupported type"); - return nullptr; - } - - if (qual_type_child_is_fn_proto(child_qt)) { - return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); - } - - if (type_is_function(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { - return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); - } else if (type_is_opaque(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { - AstNode *pointer_node = trans_create_node_ptr_type(c, - ZigClangQualType_isConstQualified(child_qt), - ZigClangQualType_isVolatileQualified(child_qt), - child_node, PtrLenSingle); - return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); - } else { - return trans_create_node_ptr_type(c, - ZigClangQualType_isConstQualified(child_qt), - ZigClangQualType_isVolatileQualified(child_qt), - child_node, PtrLenC); - } - } - case ZigClangType_Typedef: - { - const ZigClangTypedefType *typedef_ty = reinterpret_cast(ty); - const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - return resolve_typedef_decl(c, typedef_decl); - } - case ZigClangType_Elaborated: - { - const ZigClangElaboratedType *elaborated_ty = reinterpret_cast(ty); - switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) { - case ZigClangETK_Struct: - case ZigClangETK_Enum: - case ZigClangETK_Union: - return trans_qual_type(c, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc); - case ZigClangETK_Interface: - case ZigClangETK_Class: - case ZigClangETK_Typename: - case ZigClangETK_None: - emit_warning(c, source_loc, "unsupported elaborated type"); - return nullptr; - } - } - case ZigClangType_FunctionProto: - case ZigClangType_FunctionNoProto: - { - const ZigClangFunctionType *fn_ty = reinterpret_cast(ty); - - AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); - switch (ZigClangFunctionType_getCallConv(fn_ty)) { - case ZigClangCallingConv_C: // __attribute__((cdecl)) - proto_node->data.fn_proto.cc = CallingConventionC; - proto_node->data.fn_proto.is_extern = true; - break; - case ZigClangCallingConv_X86StdCall: // __attribute__((stdcall)) - proto_node->data.fn_proto.cc = CallingConventionStdcall; - break; - case ZigClangCallingConv_X86FastCall: // __attribute__((fastcall)) - emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); - return nullptr; - case ZigClangCallingConv_X86ThisCall: // __attribute__((thiscall)) - emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); - return nullptr; - case ZigClangCallingConv_X86VectorCall: // __attribute__((vectorcall)) - emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); - return nullptr; - case ZigClangCallingConv_X86Pascal: // __attribute__((pascal)) - emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); - return nullptr; - case ZigClangCallingConv_Win64: // __attribute__((ms_abi)) - emit_warning(c, source_loc, "unsupported calling convention: win64"); - return nullptr; - case ZigClangCallingConv_X86_64SysV: // __attribute__((sysv_abi)) - emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); - return nullptr; - case ZigClangCallingConv_X86RegCall: - emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); - return nullptr; - case ZigClangCallingConv_AAPCS: // __attribute__((pcs("aapcs"))) - emit_warning(c, source_loc, "unsupported calling convention: aapcs"); - return nullptr; - case ZigClangCallingConv_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) - emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); - return nullptr; - case ZigClangCallingConv_IntelOclBicc: // __attribute__((intel_ocl_bicc)) - emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); - return nullptr; - case ZigClangCallingConv_SpirFunction: // default for OpenCL functions on SPIR target - emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); - return nullptr; - case ZigClangCallingConv_OpenCLKernel: - emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); - return nullptr; - case ZigClangCallingConv_Swift: - emit_warning(c, source_loc, "unsupported calling convention: Swift"); - return nullptr; - case ZigClangCallingConv_PreserveMost: - emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); - return nullptr; - case ZigClangCallingConv_PreserveAll: - emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); - return nullptr; - case ZigClangCallingConv_AArch64VectorCall: - emit_warning(c, source_loc, "unsupported calling convention: AArch64VectorCall"); - return nullptr; - } - - if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) { - proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); - } else { - proto_node->data.fn_proto.return_type = trans_qual_type(c, - ZigClangFunctionType_getReturnType(fn_ty), source_loc); - if (proto_node->data.fn_proto.return_type == nullptr) { - emit_warning(c, source_loc, "unsupported function proto return type"); - return nullptr; - } - // convert c_void to actual void (only for return type) - // we do want to look at the AstNode instead of ZigClangQualType, because - // if they do something like: - // typedef Foo void; - // void foo(void) -> Foo; - // we want to keep the return type AST node. - if (is_c_void_type(proto_node->data.fn_proto.return_type)) { - proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "void"); - } - } - - //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); - const char *fn_name = nullptr; - if (fn_name != nullptr) { - proto_node->data.fn_proto.name = buf_create_from_str(fn_name); - } - - if (ZigClangType_getTypeClass(ty) == ZigClangType_FunctionNoProto) { - return proto_node; - } - - const ZigClangFunctionProtoType *fn_proto_ty = reinterpret_cast(ty); - - proto_node->data.fn_proto.is_var_args = ZigClangFunctionProtoType_isVariadic(fn_proto_ty); - size_t param_count = ZigClangFunctionProtoType_getNumParams(fn_proto_ty); - - for (size_t i = 0; i < param_count; i += 1) { - ZigClangQualType qt = ZigClangFunctionProtoType_getParamType(fn_proto_ty, i); - AstNode *param_type_node = trans_qual_type(c, qt, source_loc); - - if (param_type_node == nullptr) { - emit_warning(c, source_loc, "unresolved function proto parameter type"); - return nullptr; - } - - AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); - //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); - const char *param_name = nullptr; - if (param_name != nullptr) { - param_node->data.param_decl.name = buf_create_from_str(param_name); - } - param_node->data.param_decl.is_noalias = ZigClangQualType_isRestrictQualified(qt); - param_node->data.param_decl.type = param_type_node; - proto_node->data.fn_proto.params.append(param_node); - } - // TODO check for always_inline attribute - // TODO check for align attribute - - return proto_node; - } - case ZigClangType_Record: - { - const ZigClangRecordType *record_ty = reinterpret_cast(ty); - return resolve_record_decl(c, ZigClangRecordType_getDecl(record_ty)); - } - case ZigClangType_Enum: - { - const ZigClangEnumType *enum_ty = reinterpret_cast(ty); - return resolve_enum_decl(c, ZigClangEnumType_getDecl(enum_ty)); - } - case ZigClangType_ConstantArray: - { - const ZigClangConstantArrayType *const_arr_ty = reinterpret_cast(ty); - AstNode *child_type_node = trans_qual_type(c, - ZigClangConstantArrayType_getElementType(const_arr_ty), source_loc); - if (child_type_node == nullptr) { - emit_warning(c, source_loc, "unresolved array element type"); - return nullptr; - } - const ZigClangAPInt *size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); - uint64_t size = ZigClangAPInt_getLimitedValue(size_ap_int, UINT64_MAX); - AstNode *size_node = trans_create_node_unsigned(c, size); - return trans_create_node_array_type(c, size_node, child_type_node); - } - case ZigClangType_Paren: - { - const ZigClangParenType *paren_ty = reinterpret_cast(ty); - return trans_qual_type(c, ZigClangParenType_getInnerType(paren_ty), source_loc); - } - case ZigClangType_Decayed: - { - const ZigClangDecayedType *decayed_ty = reinterpret_cast(ty); - return trans_qual_type(c, ZigClangDecayedType_getDecayedType(decayed_ty), source_loc); - } - case ZigClangType_Attributed: - { - const ZigClangAttributedType *attributed_ty = reinterpret_cast(ty); - return trans_qual_type(c, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); - } - case ZigClangType_MacroQualified: - { - const ZigClangMacroQualifiedType *macroqualified_ty = reinterpret_cast(ty); - return trans_qual_type(c, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc); - } - case ZigClangType_IncompleteArray: - { - const ZigClangIncompleteArrayType *incomplete_array_ty = reinterpret_cast(ty); - ZigClangQualType child_qt = ZigClangIncompleteArrayType_getElementType(incomplete_array_ty); - AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc); - if (child_type_node == nullptr) { - emit_warning(c, source_loc, "unresolved array element type"); - return nullptr; - } - AstNode *pointer_node = trans_create_node_ptr_type(c, - ZigClangQualType_isConstQualified(child_qt), - ZigClangQualType_isVolatileQualified(child_qt), - child_type_node, PtrLenC); - return pointer_node; - } - case ZigClangType_BlockPointer: - case ZigClangType_LValueReference: - case ZigClangType_RValueReference: - case ZigClangType_MemberPointer: - case ZigClangType_VariableArray: - case ZigClangType_DependentSizedArray: - case ZigClangType_DependentSizedExtVector: - case ZigClangType_Vector: - case ZigClangType_ExtVector: - case ZigClangType_UnresolvedUsing: - case ZigClangType_Adjusted: - case ZigClangType_TypeOfExpr: - case ZigClangType_TypeOf: - case ZigClangType_Decltype: - case ZigClangType_UnaryTransform: - case ZigClangType_TemplateTypeParm: - case ZigClangType_SubstTemplateTypeParm: - case ZigClangType_SubstTemplateTypeParmPack: - case ZigClangType_TemplateSpecialization: - case ZigClangType_Auto: - case ZigClangType_InjectedClassName: - case ZigClangType_DependentName: - case ZigClangType_DependentTemplateSpecialization: - case ZigClangType_PackExpansion: - case ZigClangType_ObjCObject: - case ZigClangType_ObjCInterface: - case ZigClangType_Complex: - case ZigClangType_ObjCObjectPointer: - case ZigClangType_Atomic: - case ZigClangType_Pipe: - case ZigClangType_ObjCTypeParam: - case ZigClangType_DeducedTemplateSpecialization: - case ZigClangType_DependentAddressSpace: - case ZigClangType_DependentVector: - emit_warning(c, source_loc, "unsupported type: '%s'", ZigClangType_getTypeClassName(ty)); - return nullptr; - } - zig_unreachable(); -} - -static AstNode *trans_qual_type(Context *c, ZigClangQualType qt, ZigClangSourceLocation source_loc) { - return trans_type(c, ZigClangQualType_getTypePtr(qt), source_loc); -} - -static int trans_compound_stmt_inline(Context *c, TransScope *scope, const ZigClangCompoundStmt *stmt, - AstNode *block_node, TransScope **out_node_scope) -{ - assert(block_node->type == NodeTypeBlock); - for (ZigClangCompoundStmt_const_body_iterator it = ZigClangCompoundStmt_body_begin(stmt), - end_it = ZigClangCompoundStmt_body_end(stmt); it != end_it; ++it) - { - AstNode *child_node; - scope = trans_stmt(c, scope, *it, &child_node); - if (scope == nullptr) - return ErrorUnexpected; - if (child_node != nullptr) - block_node->data.block.statements.append(child_node); - } - if (out_node_scope != nullptr) { - *out_node_scope = scope; - } - return ErrorNone; -} - -static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const ZigClangCompoundStmt *stmt, - TransScope **out_node_scope) -{ - TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope); - if (trans_compound_stmt_inline(c, &child_scope_block->base, stmt, child_scope_block->node, out_node_scope)) - return nullptr; - return child_scope_block->node; -} - -static AstNode *trans_stmt_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangStmtExpr *stmt, TransScope **out_node_scope) -{ - AstNode *block = trans_compound_stmt(c, scope, ZigClangStmtExpr_getSubStmt(stmt), out_node_scope); - if (block == nullptr) - return block; - assert(block->type == NodeTypeBlock); - if (block->data.block.statements.length == 0) - return block; - - Buf *label = buf_create_from_str("x"); - block->data.block.name = label; - AstNode *return_expr = block->data.block.statements.pop(); - if (return_expr->type == NodeTypeBinOpExpr && - return_expr->data.bin_op_expr.bin_op == BinOpTypeAssign && - return_expr->data.bin_op_expr.op1->type == NodeTypeSymbol) - { - Buf *symbol_buf = return_expr->data.bin_op_expr.op1->data.symbol_expr.symbol; - if (strcmp("_", buf_ptr(symbol_buf)) == 0) - return_expr = return_expr->data.bin_op_expr.op2; - } - block->data.block.statements.append(trans_create_node_break(c, label, return_expr)); - return maybe_suppress_result(c, result_used, block); -} - -static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ZigClangReturnStmt *stmt) { - const ZigClangExpr *value_expr = ZigClangReturnStmt_getRetValue(stmt); - if (value_expr == nullptr) { - return trans_create_node(c, NodeTypeReturnExpr); - } else { - AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); - return_node->data.return_expr.expr = trans_expr(c, ResultUsedYes, scope, value_expr, TransRValue); - if (return_node->data.return_expr.expr == nullptr) - return nullptr; - return return_node; - } -} - -static AstNode *trans_integer_literal(Context *c, ResultUsed result_used, const ZigClangIntegerLiteral *stmt) { - ZigClangExprEvalResult result; - if (!ZigClangIntegerLiteral_EvaluateAsInt(stmt, &result, c->ctx)) { - emit_warning(c, ZigClangExpr_getBeginLoc((ZigClangExpr*)stmt), "invalid integer literal"); - return nullptr; - } - AstNode *node = trans_create_node_apint(c, ZigClangAPValue_getInt(&result.Val)); - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_floating_literal(Context *c, ResultUsed result_used, const ZigClangFloatingLiteral *stmt) { - ZigClangAPFloat *result; - if (!ZigClangExpr_EvaluateAsFloat((const ZigClangExpr *)stmt, &result, c->ctx)) { - emit_warning(c, ZigClangExpr_getBeginLoc((ZigClangExpr*)stmt), "invalid floating literal"); - return nullptr; - } - AstNode *node = trans_create_node_apfloat(c, result); - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_character_literal(Context *c, ResultUsed result_used, const ZigClangCharacterLiteral *stmt) { - switch (ZigClangCharacterLiteral_getKind(stmt)) { - case ZigClangCharacterLiteral_CharacterKind_Ascii: - { - unsigned val = ZigClangCharacterLiteral_getValue(stmt); - // C has a somewhat obscure feature called multi-character character - // constant - if (val > 255) - return trans_create_node_unsigned(c, val); - } - // fallthrough - case ZigClangCharacterLiteral_CharacterKind_UTF8: - { - AstNode *node = trans_create_node(c, NodeTypeCharLiteral); - node->data.char_literal.value = ZigClangCharacterLiteral_getValue(stmt); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangCharacterLiteral_CharacterKind_UTF16: - emit_warning(c, ZigClangCharacterLiteral_getBeginLoc(stmt), "TODO support UTF16 character literals"); - return nullptr; - case ZigClangCharacterLiteral_CharacterKind_UTF32: - emit_warning(c, ZigClangCharacterLiteral_getBeginLoc(stmt), "TODO support UTF32 character literals"); - return nullptr; - case ZigClangCharacterLiteral_CharacterKind_Wide: - emit_warning(c, ZigClangCharacterLiteral_getBeginLoc(stmt), "TODO support wide character literals"); - return nullptr; - } - zig_unreachable(); -} - -static AstNode *trans_constant_expr(Context *c, ResultUsed result_used, const ZigClangConstantExpr *expr) { - const ZigClangExpr *as_expr = reinterpret_cast(expr); - ZigClangExprEvalResult result; - if (!ZigClangExpr_EvaluateAsConstantExpr((const ZigClangExpr *)expr, &result, - ZigClangExpr_EvaluateForCodeGen, c->ctx)) - { - emit_warning(c, ZigClangExpr_getBeginLoc(as_expr), "invalid constant expression"); - return nullptr; - } - AstNode *node = trans_ap_value(c, &result.Val, ZigClangExpr_getType(as_expr), - ZigClangExpr_getBeginLoc(as_expr)); - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangConditionalOperator *stmt) -{ - AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); - - const ZigClangExpr *cond_expr = ZigClangConditionalOperator_getCond(stmt); - const ZigClangExpr *true_expr = ZigClangConditionalOperator_getTrueExpr(stmt); - const ZigClangExpr *false_expr = ZigClangConditionalOperator_getFalseExpr(stmt); - - node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue); - if (node->data.if_bool_expr.condition == nullptr) - return nullptr; - - node->data.if_bool_expr.then_block = trans_expr(c, result_used, scope, true_expr, TransRValue); - if (node->data.if_bool_expr.then_block == nullptr) - return nullptr; - - node->data.if_bool_expr.else_node = trans_expr(c, result_used, scope, false_expr, TransRValue); - if (node->data.if_bool_expr.else_node == nullptr) - return nullptr; - - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_create_bin_op(Context *c, TransScope *scope, const ZigClangExpr *lhs, - BinOpType bin_op, const ZigClangExpr *rhs) -{ - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.bin_op = bin_op; - - node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransRValue); - if (node->data.bin_op_expr.op1 == nullptr) - return nullptr; - - node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue); - if (node->data.bin_op_expr.op2 == nullptr) - return nullptr; - - return node; -} - -static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, const ZigClangExpr *lhs, - BinOpType bin_op, const ZigClangExpr *rhs) -{ - assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr); - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.bin_op = bin_op; - - node->data.bin_op_expr.op1 = trans_bool_expr(c, ResultUsedYes, scope, lhs, TransRValue); - if (node->data.bin_op_expr.op1 == nullptr) - return nullptr; - - node->data.bin_op_expr.op2 = trans_bool_expr(c, ResultUsedYes, scope, rhs, TransRValue); - if (node->data.bin_op_expr.op2 == nullptr) - return nullptr; - - return node; -} - -static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangExpr *lhs, const ZigClangExpr *rhs) -{ - if (result_used == ResultUsedNo) { - // common case - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.bin_op = BinOpTypeAssign; - - node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransLValue); - if (node->data.bin_op_expr.op1 == nullptr) - return nullptr; - - node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue); - if (node->data.bin_op_expr.op2 == nullptr) - return nullptr; - - return node; - } else { - // worst case - // c: lhs = rhs - // zig: (x: { - // zig: const _tmp = rhs; - // zig: lhs = _tmp; - // zig: break :x _tmp - // zig: }) - - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - child_scope->node->data.block.name = label_name; - - // const _tmp = rhs; - AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue); - if (rhs_node == nullptr) return nullptr; - // TODO: avoid name collisions with generated variable names - Buf* tmp_var_name = buf_create_from_str("_tmp"); - AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node); - child_scope->node->data.block.statements.append(tmp_var_decl); - - // lhs = _tmp; - AstNode *lhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, lhs, TransLValue); - if (lhs_node == nullptr) return nullptr; - child_scope->node->data.block.statements.append( - trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, - trans_create_node_symbol(c, tmp_var_name))); - - // break :x _tmp - AstNode *tmp_symbol_node = trans_create_node_symbol(c, tmp_var_name); - child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, tmp_symbol_node)); - - return trans_create_node_grouped_expr(c, child_scope->node); - } -} - -static AstNode *trans_create_shift_op(Context *c, TransScope *scope, ZigClangQualType result_type, - const ZigClangExpr *lhs_expr, BinOpType bin_op, const ZigClangExpr *rhs_expr) -{ - ZigClangSourceLocation rhs_location = ZigClangExpr_getBeginLoc(rhs_expr); - AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); - // lhs >> u5(rh) - - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, lhs_expr, TransLValue); - if (lhs == nullptr) return nullptr; - - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, rhs_expr, TransRValue); - if (rhs == nullptr) return nullptr; - AstNode *coerced_rhs = trans_create_node_cast(c, rhs_type, rhs); - - return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); -} - -static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangBinaryOperator *stmt) -{ - switch (ZigClangBinaryOperator_getOpcode(stmt)) { - case ZigClangBO_PtrMemD: - emit_warning(c, ZigClangBinaryOperator_getBeginLoc(stmt), "TODO handle more C binary operators: BO_PtrMemD"); - return nullptr; - case ZigClangBO_PtrMemI: - emit_warning(c, ZigClangBinaryOperator_getBeginLoc(stmt), "TODO handle more C binary operators: BO_PtrMemI"); - return nullptr; - case ZigClangBO_Cmp: - emit_warning(c, ZigClangBinaryOperator_getBeginLoc(stmt), "TODO handle more C binary operators: BO_Cmp"); - return nullptr; - case ZigClangBO_Mul: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), - qual_type_has_wrapping_overflow(c, ZigClangBinaryOperator_getType(stmt)) ? BinOpTypeMultWrap : BinOpTypeMult, - ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Div: - if (qual_type_has_wrapping_overflow(c, ZigClangBinaryOperator_getType(stmt))) { - // unsigned/float division uses the operator - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeDiv, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } else { - // signed integer division uses @divTrunc - AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, ZigClangBinaryOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - fn_call->data.fn_call_expr.params.append(lhs); - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, ZigClangBinaryOperator_getRHS(stmt), TransLValue); - if (rhs == nullptr) return nullptr; - fn_call->data.fn_call_expr.params.append(rhs); - return maybe_suppress_result(c, result_used, fn_call); - } - case ZigClangBO_Rem: - if (qual_type_has_wrapping_overflow(c, ZigClangBinaryOperator_getType(stmt))) { - // unsigned/float division uses the operator - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeMod, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } else { - // signed integer division uses @rem - AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, ZigClangBinaryOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - fn_call->data.fn_call_expr.params.append(lhs); - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, ZigClangBinaryOperator_getRHS(stmt), TransLValue); - if (rhs == nullptr) return nullptr; - fn_call->data.fn_call_expr.params.append(rhs); - return maybe_suppress_result(c, result_used, fn_call); - } - case ZigClangBO_Add: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), - qual_type_has_wrapping_overflow(c, ZigClangBinaryOperator_getType(stmt)) ? BinOpTypeAddWrap : BinOpTypeAdd, - ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Sub: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), - qual_type_has_wrapping_overflow(c, ZigClangBinaryOperator_getType(stmt)) ? BinOpTypeSubWrap : BinOpTypeSub, - ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Shl: { - AstNode *node = trans_create_shift_op(c, scope, ZigClangBinaryOperator_getType(stmt), ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBitShiftLeft, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Shr: { - AstNode *node = trans_create_shift_op(c, scope, ZigClangBinaryOperator_getType(stmt), ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBitShiftRight, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_LT: { - AstNode *node =trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpLessThan, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_GT: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpGreaterThan, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_LE: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpLessOrEq, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_GE: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpGreaterOrEq, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_EQ: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpEq, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_NE: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeCmpNotEq, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_And: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBinAnd, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Xor: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBinXor, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Or: { - AstNode *node = trans_create_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBinOr, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_LAnd: { - AstNode *node = trans_create_bool_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBoolAnd, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_LOr: { - AstNode *node = trans_create_bool_bin_op(c, scope, ZigClangBinaryOperator_getLHS(stmt), BinOpTypeBoolOr, ZigClangBinaryOperator_getRHS(stmt)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangBO_Assign: - return trans_create_assign(c, result_used, scope, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)); - case ZigClangBO_Comma: - { - TransScopeBlock *scope_block = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - scope_block->node->data.block.name = label_name; - - AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, ZigClangBinaryOperator_getLHS(stmt), TransRValue); - if (lhs == nullptr) - return nullptr; - scope_block->node->data.block.statements.append(lhs); - - AstNode *rhs = trans_expr(c, ResultUsedYes, &scope_block->base, ZigClangBinaryOperator_getRHS(stmt), TransRValue); - if (rhs == nullptr) - return nullptr; - - rhs = trans_create_node_break(c, label_name, rhs); - scope_block->node->data.block.statements.append(rhs); - return maybe_suppress_result(c, result_used, scope_block->node); - } - case ZigClangBO_MulAssign: - case ZigClangBO_DivAssign: - case ZigClangBO_RemAssign: - case ZigClangBO_AddAssign: - case ZigClangBO_SubAssign: - case ZigClangBO_ShlAssign: - case ZigClangBO_ShrAssign: - case ZigClangBO_AndAssign: - case ZigClangBO_XorAssign: - case ZigClangBO_OrAssign: - zig_unreachable(); - } - - zig_unreachable(); -} - -static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangCompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) -{ - ZigClangSourceLocation rhs_location = ZigClangExpr_getBeginLoc(ZigClangCompoundAssignOperator_getRHS(stmt)); - ZigClangQualType computation_lhs_type = ZigClangCompoundAssignOperator_getComputationLHSType(stmt); - AstNode *rhs_type = qual_type_to_log2_int_ref(c, computation_lhs_type, rhs_location); - ZigClangQualType computation_result_type = ZigClangCompoundAssignOperator_getComputationResultType(stmt); - - bool use_intermediate_casts = ZigClangQualType_getTypePtr(computation_lhs_type) != - ZigClangQualType_getTypePtr(computation_result_type); - if (!use_intermediate_casts && result_used == ResultUsedNo) { - // simple common case, where the C and Zig are identical: - // lhs >>= rhs - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, ZigClangCompoundAssignOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, ZigClangCompoundAssignOperator_getRHS(stmt), TransRValue); - if (rhs == nullptr) return nullptr; - AstNode *coerced_rhs = trans_create_node_cast(c, rhs_type, rhs); - - return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); - } else { - // need more complexity. worst case, this looks like this: - // c: lhs >>= rhs - // zig: (x: { - // zig: const _ref = &lhs; - // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); - // zig: break :x *_ref - // zig: }) - // where u5 is the appropriate type - - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - child_scope->node->data.block.name = label_name; - - // const _ref = &lhs; - AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, - ZigClangCompoundAssignOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs); - // TODO: avoid name collisions with generated variable names - Buf* tmp_var_name = buf_create_from_str("_ref"); - AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); - child_scope->node->data.block.statements.append(tmp_var_decl); - - // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); - - AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, ZigClangCompoundAssignOperator_getRHS(stmt), TransRValue); - if (rhs == nullptr) return nullptr; - AstNode *coerced_rhs = trans_create_node_cast(c, rhs_type, rhs); - - // operation_type(*_ref) - AstNode *operation_type_cast = trans_c_cast(c, rhs_location, - computation_lhs_type, - ZigClangExpr_getType(ZigClangCompoundAssignOperator_getLHS(stmt)), - trans_create_node_ptr_deref(c, trans_create_node_symbol(c, tmp_var_name))); - - // result_type(... >> u5(rhs)) - AstNode *result_type_cast = trans_c_cast(c, rhs_location, - computation_result_type, - computation_lhs_type, - trans_create_node_bin_op(c, - operation_type_cast, - bin_op, - coerced_rhs)); - - // *_ref = ... - AstNode *assign_statement = trans_create_node_bin_op(c, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, tmp_var_name)), - BinOpTypeAssign, result_type_cast); - - child_scope->node->data.block.statements.append(assign_statement); - - if (result_used == ResultUsedYes) { - // break :x *_ref - child_scope->node->data.block.statements.append( - trans_create_node_break(c, label_name, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, tmp_var_name)))); - } - - return trans_create_node_grouped_expr(c, child_scope->node); - } -} - -static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangCompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) -{ - if (result_used == ResultUsedNo) { - // simple common case, where the C and Zig are identical: - // lhs += rhs - AstNode *lhs = trans_expr(c, ResultUsedYes, scope, ZigClangCompoundAssignOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - AstNode *rhs = trans_expr(c, ResultUsedYes, scope, ZigClangCompoundAssignOperator_getRHS(stmt), TransRValue); - if (rhs == nullptr) return nullptr; - return trans_create_node_bin_op(c, lhs, assign_op, rhs); - } else { - // need more complexity. worst case, this looks like this: - // c: lhs += rhs - // zig: (x: { - // zig: const _ref = &lhs; - // zig: *_ref = *_ref + rhs; - // zig: break :x *_ref - // zig: }) - - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - child_scope->node->data.block.name = label_name; - - // const _ref = &lhs; - AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, - ZigClangCompoundAssignOperator_getLHS(stmt), TransLValue); - if (lhs == nullptr) return nullptr; - AstNode *addr_of_lhs = trans_create_node_addr_of(c, lhs); - // TODO: avoid name collisions with generated variable names - Buf* tmp_var_name = buf_create_from_str("_ref"); - AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); - child_scope->node->data.block.statements.append(tmp_var_decl); - - // *_ref = *_ref + rhs; - - AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, - ZigClangCompoundAssignOperator_getRHS(stmt), TransRValue); - if (rhs == nullptr) return nullptr; - - AstNode *assign_statement = trans_create_node_bin_op(c, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, tmp_var_name)), - BinOpTypeAssign, - trans_create_node_bin_op(c, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, tmp_var_name)), - bin_op, - rhs)); - child_scope->node->data.block.statements.append(assign_statement); - - // break :x *_ref - child_scope->node->data.block.statements.append( - trans_create_node_break(c, label_name, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, tmp_var_name)))); - - return trans_create_node_grouped_expr(c, child_scope->node); - } -} - - -static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangCompoundAssignOperator *stmt) -{ - switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) { - case ZigClangBO_MulAssign: - if (qual_type_has_wrapping_overflow(c, ZigClangCompoundAssignOperator_getType(stmt))) - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); - else - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult); - case ZigClangBO_DivAssign: - emit_warning(c, ZigClangCompoundAssignOperator_getBeginLoc(stmt), "TODO handle more C compound assign operators: BO_DivAssign"); - return nullptr; - case ZigClangBO_RemAssign: - emit_warning(c, ZigClangCompoundAssignOperator_getBeginLoc(stmt), "TODO handle more C compound assign operators: BO_RemAssign"); - return nullptr; - case ZigClangBO_Cmp: - emit_warning(c, ZigClangCompoundAssignOperator_getBeginLoc(stmt), "TODO handle more C compound assign operators: BO_Cmp"); - return nullptr; - case ZigClangBO_AddAssign: - if (qual_type_has_wrapping_overflow(c, ZigClangCompoundAssignOperator_getType(stmt))) - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); - else - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); - case ZigClangBO_SubAssign: - if (qual_type_has_wrapping_overflow(c, ZigClangCompoundAssignOperator_getType(stmt))) - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); - else - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub); - case ZigClangBO_ShlAssign: - return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); - case ZigClangBO_ShrAssign: - return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); - case ZigClangBO_AndAssign: - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); - case ZigClangBO_XorAssign: - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); - case ZigClangBO_OrAssign: - return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); - case ZigClangBO_PtrMemD: - case ZigClangBO_PtrMemI: - case ZigClangBO_Assign: - case ZigClangBO_Mul: - case ZigClangBO_Div: - case ZigClangBO_Rem: - case ZigClangBO_Add: - case ZigClangBO_Sub: - case ZigClangBO_Shl: - case ZigClangBO_Shr: - case ZigClangBO_LT: - case ZigClangBO_GT: - case ZigClangBO_LE: - case ZigClangBO_GE: - case ZigClangBO_EQ: - case ZigClangBO_NE: - case ZigClangBO_And: - case ZigClangBO_Xor: - case ZigClangBO_Or: - case ZigClangBO_LAnd: - case ZigClangBO_LOr: - case ZigClangBO_Comma: - zig_unreachable(); - } - - zig_unreachable(); -} - -static AstNode *trans_implicit_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangImplicitCastExpr *stmt) -{ - switch (ZigClangImplicitCastExpr_getCastKind(stmt)) { - case ZigClangCK_LValueToRValue: - return trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - case ZigClangCK_IntegralCast: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - AstNode *node = trans_c_cast(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), - ZigClangExpr_getType(reinterpret_cast(stmt)), - ZigClangExpr_getType(ZigClangImplicitCastExpr_getSubExpr(stmt)), - target_node); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangCK_FunctionToPointerDecay: - case ZigClangCK_ArrayToPointerDecay: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - return maybe_suppress_result(c, result_used, target_node); - } - case ZigClangCK_BitCast: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - - const ZigClangQualType dest_type = get_expr_qual_type(c, reinterpret_cast(stmt)); - const ZigClangQualType src_type = get_expr_qual_type(c, ZigClangImplicitCastExpr_getSubExpr(stmt)); - - return trans_c_cast(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), - dest_type, src_type, target_node); - } - case ZigClangCK_NullToPointer: - return trans_create_node(c, NodeTypeNullLiteral); - case ZigClangCK_NoOp: - return trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - case ZigClangCK_Dependent: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_Dependent"); - return nullptr; - case ZigClangCK_LValueBitCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_LValueBitCast"); - return nullptr; - case ZigClangCK_BaseToDerived: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_BaseToDerived"); - return nullptr; - case ZigClangCK_DerivedToBase: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_DerivedToBase"); - return nullptr; - case ZigClangCK_UncheckedDerivedToBase: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_UncheckedDerivedToBase"); - return nullptr; - case ZigClangCK_Dynamic: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_Dynamic"); - return nullptr; - case ZigClangCK_ToUnion: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_ToUnion"); - return nullptr; - case ZigClangCK_NullToMemberPointer: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_NullToMemberPointer"); - return nullptr; - case ZigClangCK_BaseToDerivedMemberPointer: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); - return nullptr; - case ZigClangCK_DerivedToBaseMemberPointer: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); - return nullptr; - case ZigClangCK_MemberPointerToBoolean: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_MemberPointerToBoolean"); - return nullptr; - case ZigClangCK_ReinterpretMemberPointer: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_ReinterpretMemberPointer"); - return nullptr; - case ZigClangCK_UserDefinedConversion: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C translation cast CK_UserDefinedConversion"); - return nullptr; - case ZigClangCK_ConstructorConversion: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ConstructorConversion"); - return nullptr; - case ZigClangCK_PointerToBoolean: - { - const ZigClangExpr *expr = ZigClangImplicitCastExpr_getSubExpr(stmt); - AstNode *val = trans_expr(c, ResultUsedYes, scope, expr, TransRValue); - if (val == nullptr) - return nullptr; - - AstNode *val_ptr = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); - val_ptr->data.fn_call_expr.params.append(val); - - AstNode *zero = trans_create_node_unsigned(c, 0); - - // Translate as @ptrToInt((&val) != 0) - return trans_create_node_bin_op(c, val_ptr, BinOpTypeCmpNotEq, zero); - } - case ZigClangCK_ToVoid: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ToVoid"); - return nullptr; - case ZigClangCK_VectorSplat: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_VectorSplat"); - return nullptr; - case ZigClangCK_IntegralToBoolean: - { - const ZigClangExpr *expr = ZigClangImplicitCastExpr_getSubExpr(stmt); - - bool expr_val; - if (ZigClangExpr_EvaluateAsBooleanCondition(expr, &expr_val, c->ctx, false)) { - return trans_create_node_bool(c, expr_val); - } - - AstNode *val = trans_expr(c, ResultUsedYes, scope, expr, TransRValue); - if (val == nullptr) - return nullptr; - - AstNode *zero = trans_create_node_unsigned(c, 0); - - // Translate as val != 0 - return trans_create_node_bin_op(c, val, BinOpTypeCmpNotEq, zero); - } - case ZigClangCK_PointerToIntegral: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - - AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); - if (dest_type_node == nullptr) - return nullptr; - - AstNode *val_node = trans_create_node_builtin_fn_call_str(c, "ptrToInt"); - val_node->data.fn_call_expr.params.append(target_node); - // @ptrToInt always returns a usize - AstNode *node = trans_create_node_builtin_fn_call_str(c, "intCast"); - node->data.fn_call_expr.params.append(dest_type_node); - node->data.fn_call_expr.params.append(val_node); - - return maybe_suppress_result(c, result_used, node); - } - case ZigClangCK_IntegralToPointer: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - - AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); - if (dest_type_node == nullptr) - return nullptr; - - AstNode *node = trans_create_node_builtin_fn_call_str(c, "intToPtr"); - node->data.fn_call_expr.params.append(dest_type_node); - node->data.fn_call_expr.params.append(target_node); - - return maybe_suppress_result(c, result_used, node); - } - case ZigClangCK_IntegralToFloating: - case ZigClangCK_FloatingToIntegral: - { - AstNode *target_node = trans_expr(c, ResultUsedYes, scope, ZigClangImplicitCastExpr_getSubExpr(stmt), TransRValue); - if (target_node == nullptr) - return nullptr; - - AstNode *dest_type_node = get_expr_type(c, (const ZigClangExpr *)stmt); - if (dest_type_node == nullptr) - return nullptr; - - char const *fn = (ZigClangImplicitCastExpr_getCastKind(stmt) == ZigClangCK_IntegralToFloating) ? - "intToFloat" : "floatToInt"; - AstNode *node = trans_create_node_builtin_fn_call_str(c, fn); - node->data.fn_call_expr.params.append(dest_type_node); - node->data.fn_call_expr.params.append(target_node); - - return maybe_suppress_result(c, result_used, node); - } - case ZigClangCK_FixedPointCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FixedPointCast"); - return nullptr; - case ZigClangCK_FixedPointToBoolean: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FixedPointToBoolean"); - return nullptr; - case ZigClangCK_FloatingToBoolean: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingToBoolean"); - return nullptr; - case ZigClangCK_BooleanToSignedIntegral: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_BooleanToSignedIntegral"); - return nullptr; - case ZigClangCK_FloatingCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingCast"); - return nullptr; - case ZigClangCK_CPointerToObjCPointerCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_CPointerToObjCPointerCast"); - return nullptr; - case ZigClangCK_BlockPointerToObjCPointerCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_BlockPointerToObjCPointerCast"); - return nullptr; - case ZigClangCK_AnyPointerToBlockPointerCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_AnyPointerToBlockPointerCast"); - return nullptr; - case ZigClangCK_ObjCObjectLValueCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ObjCObjectLValueCast"); - return nullptr; - case ZigClangCK_FloatingRealToComplex: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingRealToComplex"); - return nullptr; - case ZigClangCK_FloatingComplexToReal: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingComplexToReal"); - return nullptr; - case ZigClangCK_FloatingComplexToBoolean: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingComplexToBoolean"); - return nullptr; - case ZigClangCK_FloatingComplexCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingComplexCast"); - return nullptr; - case ZigClangCK_FloatingComplexToIntegralComplex: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FloatingComplexToIntegralComplex"); - return nullptr; - case ZigClangCK_IntegralRealToComplex: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralRealToComplex"); - return nullptr; - case ZigClangCK_IntegralComplexToReal: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralComplexToReal"); - return nullptr; - case ZigClangCK_IntegralComplexToBoolean: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralComplexToBoolean"); - return nullptr; - case ZigClangCK_IntegralComplexCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralComplexCast"); - return nullptr; - case ZigClangCK_IntegralComplexToFloatingComplex: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralComplexToFloatingComplex"); - return nullptr; - case ZigClangCK_ARCProduceObject: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ARCProduceObject"); - return nullptr; - case ZigClangCK_ARCConsumeObject: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ARCConsumeObject"); - return nullptr; - case ZigClangCK_ARCReclaimReturnedObject: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ARCReclaimReturnedObject"); - return nullptr; - case ZigClangCK_ARCExtendBlockObject: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ARCExtendBlockObject"); - return nullptr; - case ZigClangCK_AtomicToNonAtomic: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_AtomicToNonAtomic"); - return nullptr; - case ZigClangCK_NonAtomicToAtomic: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_NonAtomicToAtomic"); - return nullptr; - case ZigClangCK_CopyAndAutoreleaseBlockObject: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_CopyAndAutoreleaseBlockObject"); - return nullptr; - case ZigClangCK_BuiltinFnToFnPtr: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_BuiltinFnToFnPtr"); - return nullptr; - case ZigClangCK_ZeroToOCLOpaqueType: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_ZeroToOCLOpaqueType"); - return nullptr; - case ZigClangCK_AddressSpaceConversion: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_AddressSpaceConversion"); - return nullptr; - case ZigClangCK_IntToOCLSampler: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntToOCLSampler"); - return nullptr; - case ZigClangCK_LValueToRValueBitCast: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_LValueToRValueBitCast"); - return nullptr; - case ZigClangCK_FixedPointToIntegral: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_FixedPointToIntegral"); - return nullptr; - case ZigClangCK_IntegralToFixedPoint: - emit_warning(c, ZigClangImplicitCastExpr_getBeginLoc(stmt), "TODO handle C CK_IntegralToFixedPointral"); - return nullptr; - } - zig_unreachable(); -} - -static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const ZigClangDeclRefExpr *stmt, TransLRValue lrval) { - const ZigClangValueDecl *value_decl = ZigClangDeclRefExpr_getDecl(stmt); - Buf *c_symbol_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)value_decl)); - Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name); - if (lrval == TransLValue) { - c->ptr_params.put(zig_symbol_name, true); - } - return trans_create_node_symbol(c, zig_symbol_name); -} - -static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangUnaryOperator *stmt, BinOpType assign_op) -{ - const ZigClangExpr *op_expr = ZigClangUnaryOperator_getSubExpr(stmt); - - if (result_used == ResultUsedNo) { - // common case - // c: expr++ - // zig: expr += 1 - return trans_create_node_bin_op(c, - trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue), - assign_op, - trans_create_node_unsigned(c, 1)); - } - // worst case - // c: expr++ - // zig: (x: { - // zig: const _ref = &expr; - // zig: const _tmp = *_ref; - // zig: *_ref += 1; - // zig: break :x _tmp - // zig: }) - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - child_scope->node->data.block.name = label_name; - - // const _ref = &expr; - AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); - if (expr == nullptr) return nullptr; - AstNode *addr_of_expr = trans_create_node_addr_of(c, expr); - // TODO: avoid name collisions with generated variable names - Buf* ref_var_name = buf_create_from_str("_ref"); - AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); - child_scope->node->data.block.statements.append(ref_var_decl); - - // const _tmp = *_ref; - Buf* tmp_var_name = buf_create_from_str("_tmp"); - AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, ref_var_name))); - child_scope->node->data.block.statements.append(tmp_var_decl); - - // *_ref += 1; - AstNode *assign_statement = trans_create_node_bin_op(c, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, ref_var_name)), - assign_op, - trans_create_node_unsigned(c, 1)); - child_scope->node->data.block.statements.append(assign_statement); - - // break :x _tmp - child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, trans_create_node_symbol(c, tmp_var_name))); - - return trans_create_node_grouped_expr(c, child_scope->node); -} - -static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangUnaryOperator *stmt, BinOpType assign_op) -{ - const ZigClangExpr *op_expr = ZigClangUnaryOperator_getSubExpr(stmt); - - if (result_used == ResultUsedNo) { - // common case - // c: ++expr - // zig: expr += 1 - return trans_create_node_bin_op(c, - trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue), - assign_op, - trans_create_node_unsigned(c, 1)); - } - // worst case - // c: ++expr - // zig: (x: { - // zig: const _ref = &expr; - // zig: *_ref += 1; - // zig: break :x *_ref - // zig: }) - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - Buf *label_name = buf_create_from_str("x"); - child_scope->node->data.block.name = label_name; - - // const _ref = &expr; - AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); - if (expr == nullptr) return nullptr; - AstNode *addr_of_expr = trans_create_node_addr_of(c, expr); - // TODO: avoid name collisions with generated variable names - Buf* ref_var_name = buf_create_from_str("_ref"); - AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); - child_scope->node->data.block.statements.append(ref_var_decl); - - // *_ref += 1; - AstNode *assign_statement = trans_create_node_bin_op(c, - trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, ref_var_name)), - assign_op, - trans_create_node_unsigned(c, 1)); - child_scope->node->data.block.statements.append(assign_statement); - - // break :x *_ref - AstNode *deref_expr = trans_create_node_ptr_deref(c, - trans_create_node_symbol(c, ref_var_name)); - child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, deref_expr)); - - return trans_create_node_grouped_expr(c, child_scope->node); -} - -static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangUnaryOperator *stmt) -{ - switch (ZigClangUnaryOperator_getOpcode(stmt)) { - case ZigClangUO_PostInc: - if (qual_type_has_wrapping_overflow(c, ZigClangUnaryOperator_getType(stmt))) - return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); - else - return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); - case ZigClangUO_PostDec: - if (qual_type_has_wrapping_overflow(c, ZigClangUnaryOperator_getType(stmt))) - return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); - else - return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); - case ZigClangUO_PreInc: - if (qual_type_has_wrapping_overflow(c, ZigClangUnaryOperator_getType(stmt))) - return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); - else - return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); - case ZigClangUO_PreDec: - if (qual_type_has_wrapping_overflow(c, ZigClangUnaryOperator_getType(stmt))) - return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); - else - return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); - case ZigClangUO_AddrOf: - { - AstNode *value_node = trans_expr(c, result_used, scope, ZigClangUnaryOperator_getSubExpr(stmt), TransLValue); - if (value_node == nullptr) - return value_node; - return trans_create_node_addr_of(c, value_node); - } - case ZigClangUO_Deref: - { - AstNode *value_node = trans_expr(c, result_used, scope, ZigClangUnaryOperator_getSubExpr(stmt), TransRValue); - if (value_node == nullptr) - return nullptr; - bool is_fn_ptr = qual_type_is_fn_ptr(ZigClangExpr_getType(ZigClangUnaryOperator_getSubExpr(stmt))); - if (is_fn_ptr) - return value_node; - AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node); - return trans_create_node_ptr_deref(c, unwrapped); - } - case ZigClangUO_Plus: - emit_warning(c, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Plus"); - return nullptr; - case ZigClangUO_Minus: - { - const ZigClangExpr *op_expr = ZigClangUnaryOperator_getSubExpr(stmt); - if (!qual_type_has_wrapping_overflow(c, ZigClangExpr_getType(op_expr))) { - AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); - node->data.prefix_op_expr.prefix_op = PrefixOpNegation; - - node->data.prefix_op_expr.primary_expr = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); - if (node->data.prefix_op_expr.primary_expr == nullptr) - return nullptr; - - return node; - } else if (c_is_unsigned_integer(c, ZigClangExpr_getType(op_expr))) { - // we gotta emit 0 -% x - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); - - node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); - if (node->data.bin_op_expr.op2 == nullptr) - return nullptr; - - node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; - return node; - } else { - emit_warning(c, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer"); - return nullptr; - } - } - case ZigClangUO_Not: - { - const ZigClangExpr *op_expr = ZigClangUnaryOperator_getSubExpr(stmt); - AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); - if (sub_node == nullptr) - return nullptr; - - return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); - } - case ZigClangUO_LNot: - { - const ZigClangExpr *op_expr = ZigClangUnaryOperator_getSubExpr(stmt); - AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue); - if (sub_node == nullptr) - return nullptr; - - return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); - } - case ZigClangUO_Real: - emit_warning(c, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Real"); - return nullptr; - case ZigClangUO_Imag: - emit_warning(c, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Imag"); - return nullptr; - case ZigClangUO_Extension: - return trans_expr(c, result_used, scope, ZigClangUnaryOperator_getSubExpr(stmt), TransLValue); - case ZigClangUO_Coawait: - emit_warning(c, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Coawait"); - return nullptr; - } - zig_unreachable(); -} - -static int trans_local_declaration(Context *c, TransScope *scope, const ZigClangDeclStmt *stmt, - AstNode **out_node, TransScope **out_scope) -{ - // declarations are added via the scope - *out_node = nullptr; - - TransScopeBlock *scope_block = trans_scope_block_find(scope); - assert(scope_block != nullptr); - - for (ZigClangDeclStmt_const_decl_iterator iter = ZigClangDeclStmt_decl_begin(stmt), - iter_end = ZigClangDeclStmt_decl_end(stmt); - iter != iter_end; ++iter) - { - ZigClangDecl *decl = *iter; - switch (ZigClangDecl_getKind(decl)) { - case ZigClangDeclVar: { - ZigClangVarDecl *var_decl = (ZigClangVarDecl *)decl; - ZigClangQualType qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); - AstNode *init_node = nullptr; - if (ZigClangVarDecl_hasInit(var_decl)) { - init_node = trans_expr(c, ResultUsedYes, scope, ZigClangVarDecl_getInit(var_decl), TransRValue); - if (init_node == nullptr) - return ErrorUnexpected; - - } else { - init_node = trans_create_node(c, NodeTypeUndefinedLiteral); - } - AstNode *type_node = trans_qual_type(c, qual_type, ZigClangDeclStmt_getBeginLoc(stmt)); - if (type_node == nullptr) - return ErrorUnexpected; - - Buf *c_symbol_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)var_decl)); - - TransScopeVar *var_scope = trans_scope_var_create(c, scope, c_symbol_name); - scope = &var_scope->base; - - AstNode *node = trans_create_node_var_decl_local(c, - ZigClangQualType_isConstQualified(qual_type), - var_scope->zig_name, type_node, init_node); - - scope_block->node->data.block.statements.append(node); - continue; - } - case ZigClangDeclAccessSpec: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle decl kind AccessSpec"); - return ErrorUnexpected; - case ZigClangDeclBlock: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Block"); - return ErrorUnexpected; - case ZigClangDeclCaptured: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Captured"); - return ErrorUnexpected; - case ZigClangDeclClassScopeFunctionSpecialization: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ClassScopeFunctionSpecialization"); - return ErrorUnexpected; - case ZigClangDeclEmpty: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Empty"); - return ErrorUnexpected; - case ZigClangDeclExport: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Export"); - return ErrorUnexpected; - case ZigClangDeclExternCContext: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ExternCContext"); - return ErrorUnexpected; - case ZigClangDeclFileScopeAsm: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C FileScopeAsm"); - return ErrorUnexpected; - case ZigClangDeclFriend: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Friend"); - return ErrorUnexpected; - case ZigClangDeclFriendTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C FriendTemplate"); - return ErrorUnexpected; - case ZigClangDeclImport: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Import"); - return ErrorUnexpected; - case ZigClangDeclLinkageSpec: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C LinkageSpec"); - return ErrorUnexpected; - case ZigClangDeclLabel: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Label"); - return ErrorUnexpected; - case ZigClangDeclNamespace: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Namespace"); - return ErrorUnexpected; - case ZigClangDeclNamespaceAlias: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C NamespaceAlias"); - return ErrorUnexpected; - case ZigClangDeclObjCCompatibleAlias: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCCompatibleAlias"); - return ErrorUnexpected; - case ZigClangDeclObjCCategory: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCCategory"); - return ErrorUnexpected; - case ZigClangDeclObjCCategoryImpl: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCCategoryImpl"); - return ErrorUnexpected; - case ZigClangDeclObjCImplementation: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCImplementation"); - return ErrorUnexpected; - case ZigClangDeclObjCInterface: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCInterface"); - return ErrorUnexpected; - case ZigClangDeclObjCProtocol: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCProtocol"); - return ErrorUnexpected; - case ZigClangDeclObjCMethod: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCMethod"); - return ErrorUnexpected; - case ZigClangDeclObjCProperty: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCProperty"); - return ErrorUnexpected; - case ZigClangDeclBuiltinTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C BuiltinTemplate"); - return ErrorUnexpected; - case ZigClangDeclClassTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ClassTemplate"); - return ErrorUnexpected; - case ZigClangDeclFunctionTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C FunctionTemplate"); - return ErrorUnexpected; - case ZigClangDeclTypeAliasTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C TypeAliasTemplate"); - return ErrorUnexpected; - case ZigClangDeclVarTemplate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C VarTemplate"); - return ErrorUnexpected; - case ZigClangDeclTemplateTemplateParm: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C TemplateTemplateParm"); - return ErrorUnexpected; - case ZigClangDeclEnum: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Enum"); - return ErrorUnexpected; - case ZigClangDeclRecord: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Record"); - return ErrorUnexpected; - case ZigClangDeclCXXRecord: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXRecord"); - return ErrorUnexpected; - case ZigClangDeclClassTemplateSpecialization: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ClassTemplateSpecialization"); - return ErrorUnexpected; - case ZigClangDeclClassTemplatePartialSpecialization: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ClassTemplatePartialSpecialization"); - return ErrorUnexpected; - case ZigClangDeclTemplateTypeParm: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C TemplateTypeParm"); - return ErrorUnexpected; - case ZigClangDeclObjCTypeParam: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCTypeParam"); - return ErrorUnexpected; - case ZigClangDeclTypeAlias: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C TypeAlias"); - return ErrorUnexpected; - case ZigClangDeclTypedef: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Typedef"); - return ErrorUnexpected; - case ZigClangDeclUnresolvedUsingTypename: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C UnresolvedUsingTypename"); - return ErrorUnexpected; - case ZigClangDeclUsing: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Using"); - return ErrorUnexpected; - case ZigClangDeclUsingDirective: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C UsingDirective"); - return ErrorUnexpected; - case ZigClangDeclUsingPack: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C UsingPack"); - return ErrorUnexpected; - case ZigClangDeclUsingShadow: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C UsingShadow"); - return ErrorUnexpected; - case ZigClangDeclConstructorUsingShadow: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ConstructorUsingShadow"); - return ErrorUnexpected; - case ZigClangDeclBinding: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Binding"); - return ErrorUnexpected; - case ZigClangDeclField: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Field"); - return ErrorUnexpected; - case ZigClangDeclObjCAtDefsField: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCAtDefsField"); - return ErrorUnexpected; - case ZigClangDeclObjCIvar: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCIvar"); - return ErrorUnexpected; - case ZigClangDeclFunction: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Function"); - return ErrorUnexpected; - case ZigClangDeclCXXDeductionGuide: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXDeductionGuide"); - return ErrorUnexpected; - case ZigClangDeclCXXMethod: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXMethod"); - return ErrorUnexpected; - case ZigClangDeclCXXConstructor: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXConstructor"); - return ErrorUnexpected; - case ZigClangDeclCXXConversion: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXConversion"); - return ErrorUnexpected; - case ZigClangDeclCXXDestructor: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C CXXDestructor"); - return ErrorUnexpected; - case ZigClangDeclMSProperty: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C MSProperty"); - return ErrorUnexpected; - case ZigClangDeclNonTypeTemplateParm: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C NonTypeTemplateParm"); - return ErrorUnexpected; - case ZigClangDeclDecomposition: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Decomposition"); - return ErrorUnexpected; - case ZigClangDeclImplicitParam: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ImplicitParam"); - return ErrorUnexpected; - case ZigClangDeclOMPCapturedExpr: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPCapturedExpr"); - return ErrorUnexpected; - case ZigClangDeclParmVar: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ParmVar"); - return ErrorUnexpected; - case ZigClangDeclVarTemplateSpecialization: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C VarTemplateSpecialization"); - return ErrorUnexpected; - case ZigClangDeclVarTemplatePartialSpecialization: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C VarTemplatePartialSpecialization"); - return ErrorUnexpected; - case ZigClangDeclEnumConstant: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C EnumConstant"); - return ErrorUnexpected; - case ZigClangDeclIndirectField: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C IndirectField"); - return ErrorUnexpected; - case ZigClangDeclOMPDeclareReduction: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPDeclareReduction"); - return ErrorUnexpected; - case ZigClangDeclUnresolvedUsingValue: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C UnresolvedUsingValue"); - return ErrorUnexpected; - case ZigClangDeclOMPRequires: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPRequires"); - return ErrorUnexpected; - case ZigClangDeclOMPThreadPrivate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPThreadPrivate"); - return ErrorUnexpected; - case ZigClangDeclObjCPropertyImpl: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C ObjCPropertyImpl"); - return ErrorUnexpected; - case ZigClangDeclPragmaComment: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C PragmaComment"); - return ErrorUnexpected; - case ZigClangDeclPragmaDetectMismatch: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C PragmaDetectMismatch"); - return ErrorUnexpected; - case ZigClangDeclStaticAssert: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C StaticAssert"); - return ErrorUnexpected; - case ZigClangDeclTranslationUnit: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C TranslationUnit"); - return ErrorUnexpected; - case ZigClangDeclConcept: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C Concept"); - return ErrorUnexpected; - case ZigClangDeclOMPDeclareMapper: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPDeclareMapper"); - return ErrorUnexpected; - case ZigClangDeclOMPAllocate: - emit_warning(c, ZigClangDeclStmt_getBeginLoc(stmt), "TODO handle C OMPAllocate"); - return ErrorUnexpected; - } - zig_unreachable(); - } - - *out_scope = scope; - return ErrorNone; -} - -static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type) { - AstNode *tag_type = trans_create_node_builtin_fn_call_str(c, "TagType"); - tag_type->data.fn_call_expr.params.append(enum_type); - - // @TagType(Enum)(0) - AstNode *zero = trans_create_node_unsigned_negative(c, 0, false); - AstNode *casted_zero = trans_create_node_cast(c, tag_type, zero); - - // @bitCast(Enum, @TagType(Enum)(0)) - AstNode *bitcast = trans_create_node_builtin_fn_call_str(c, "bitCast"); - bitcast->data.fn_call_expr.params.append(enum_type); - bitcast->data.fn_call_expr.params.append(casted_zero); - - return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast); -} - -static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, TransLRValue lrval) { - AstNode *res = trans_expr(c, result_used, scope, expr, lrval); - if (res == nullptr) - return nullptr; - - switch (res->type) { - case NodeTypeBinOpExpr: - switch (res->data.bin_op_expr.bin_op) { - case BinOpTypeBoolOr: - case BinOpTypeBoolAnd: - case BinOpTypeCmpEq: - case BinOpTypeCmpNotEq: - case BinOpTypeCmpLessThan: - case BinOpTypeCmpGreaterThan: - case BinOpTypeCmpLessOrEq: - case BinOpTypeCmpGreaterOrEq: - return res; - default: - break; - } - - case NodeTypePrefixOpExpr: - switch (res->data.prefix_op_expr.prefix_op) { - case PrefixOpBoolNot: - return res; - default: - break; - } - - case NodeTypeBoolLiteral: - return res; - - default: - break; - } - - - const ZigClangType *ty = ZigClangQualType_getTypePtr(get_expr_qual_type_before_implicit_cast(c, expr)); - auto classs = ZigClangType_getTypeClass(ty); - switch (classs) { - case ZigClangType_Builtin: - { - const ZigClangBuiltinType *builtin_ty = reinterpret_cast(ty); - switch (ZigClangBuiltinType_getKind(builtin_ty)) { - case ZigClangBuiltinTypeBool: - case ZigClangBuiltinTypeChar_U: - case ZigClangBuiltinTypeUChar: - case ZigClangBuiltinTypeChar_S: - case ZigClangBuiltinTypeSChar: - case ZigClangBuiltinTypeUShort: - case ZigClangBuiltinTypeUInt: - case ZigClangBuiltinTypeULong: - case ZigClangBuiltinTypeULongLong: - case ZigClangBuiltinTypeShort: - case ZigClangBuiltinTypeInt: - case ZigClangBuiltinTypeLong: - case ZigClangBuiltinTypeLongLong: - case ZigClangBuiltinTypeUInt128: - case ZigClangBuiltinTypeInt128: - case ZigClangBuiltinTypeFloat: - case ZigClangBuiltinTypeDouble: - case ZigClangBuiltinTypeFloat128: - case ZigClangBuiltinTypeLongDouble: - case ZigClangBuiltinTypeWChar_U: - case ZigClangBuiltinTypeChar8: - case ZigClangBuiltinTypeChar16: - case ZigClangBuiltinTypeChar32: - case ZigClangBuiltinTypeWChar_S: - case ZigClangBuiltinTypeFloat16: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); - case ZigClangBuiltinTypeNullPtr: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, - trans_create_node(c, NodeTypeNullLiteral)); - - case ZigClangBuiltinTypeVoid: - case ZigClangBuiltinTypeHalf: - case ZigClangBuiltinTypeObjCId: - case ZigClangBuiltinTypeObjCClass: - case ZigClangBuiltinTypeObjCSel: - case ZigClangBuiltinTypeOMPArraySection: - case ZigClangBuiltinTypeDependent: - case ZigClangBuiltinTypeOverload: - case ZigClangBuiltinTypeBoundMember: - case ZigClangBuiltinTypePseudoObject: - case ZigClangBuiltinTypeUnknownAny: - case ZigClangBuiltinTypeBuiltinFn: - case ZigClangBuiltinTypeARCUnbridgedCast: - case ZigClangBuiltinTypeOCLImage1dRO: - case ZigClangBuiltinTypeOCLImage1dArrayRO: - case ZigClangBuiltinTypeOCLImage1dBufferRO: - case ZigClangBuiltinTypeOCLImage2dRO: - case ZigClangBuiltinTypeOCLImage2dArrayRO: - case ZigClangBuiltinTypeOCLImage2dDepthRO: - case ZigClangBuiltinTypeOCLImage2dArrayDepthRO: - case ZigClangBuiltinTypeOCLImage2dMSAARO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAARO: - case ZigClangBuiltinTypeOCLImage2dMSAADepthRO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRO: - case ZigClangBuiltinTypeOCLImage3dRO: - case ZigClangBuiltinTypeOCLImage1dWO: - case ZigClangBuiltinTypeOCLImage1dArrayWO: - case ZigClangBuiltinTypeOCLImage1dBufferWO: - case ZigClangBuiltinTypeOCLImage2dWO: - case ZigClangBuiltinTypeOCLImage2dArrayWO: - case ZigClangBuiltinTypeOCLImage2dDepthWO: - case ZigClangBuiltinTypeOCLImage2dArrayDepthWO: - case ZigClangBuiltinTypeOCLImage2dMSAAWO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAAWO: - case ZigClangBuiltinTypeOCLImage2dMSAADepthWO: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthWO: - case ZigClangBuiltinTypeOCLImage3dWO: - case ZigClangBuiltinTypeOCLImage1dRW: - case ZigClangBuiltinTypeOCLImage1dArrayRW: - case ZigClangBuiltinTypeOCLImage1dBufferRW: - case ZigClangBuiltinTypeOCLImage2dRW: - case ZigClangBuiltinTypeOCLImage2dArrayRW: - case ZigClangBuiltinTypeOCLImage2dDepthRW: - case ZigClangBuiltinTypeOCLImage2dArrayDepthRW: - case ZigClangBuiltinTypeOCLImage2dMSAARW: - case ZigClangBuiltinTypeOCLImage2dArrayMSAARW: - case ZigClangBuiltinTypeOCLImage2dMSAADepthRW: - case ZigClangBuiltinTypeOCLImage2dArrayMSAADepthRW: - case ZigClangBuiltinTypeOCLImage3dRW: - case ZigClangBuiltinTypeOCLSampler: - case ZigClangBuiltinTypeOCLEvent: - case ZigClangBuiltinTypeOCLClkEvent: - case ZigClangBuiltinTypeOCLQueue: - case ZigClangBuiltinTypeOCLReserveID: - case ZigClangBuiltinTypeShortAccum: - case ZigClangBuiltinTypeAccum: - case ZigClangBuiltinTypeLongAccum: - case ZigClangBuiltinTypeUShortAccum: - case ZigClangBuiltinTypeUAccum: - case ZigClangBuiltinTypeULongAccum: - case ZigClangBuiltinTypeShortFract: - case ZigClangBuiltinTypeFract: - case ZigClangBuiltinTypeLongFract: - case ZigClangBuiltinTypeUShortFract: - case ZigClangBuiltinTypeUFract: - case ZigClangBuiltinTypeULongFract: - case ZigClangBuiltinTypeSatShortAccum: - case ZigClangBuiltinTypeSatAccum: - case ZigClangBuiltinTypeSatLongAccum: - case ZigClangBuiltinTypeSatUShortAccum: - case ZigClangBuiltinTypeSatUAccum: - case ZigClangBuiltinTypeSatULongAccum: - case ZigClangBuiltinTypeSatShortFract: - case ZigClangBuiltinTypeSatFract: - case ZigClangBuiltinTypeSatLongFract: - case ZigClangBuiltinTypeSatUShortFract: - case ZigClangBuiltinTypeSatUFract: - case ZigClangBuiltinTypeSatULongFract: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCMcePayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImePayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefPayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicPayload: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCMceResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCRefResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCSicResult: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultSingleRefStreamout: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeResultDualRefStreamout: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeSingleRefStreamin: - case ZigClangBuiltinTypeOCLIntelSubgroupAVCImeDualRefStreamin: - return res; - } - break; - } - case ZigClangType_Pointer: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); - - case ZigClangType_Typedef: - { - const ZigClangTypedefType *typedef_ty = reinterpret_cast(ty); - const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - auto existing_entry = c->decl_table.maybe_get((void*)ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)); - if (existing_entry) { - return existing_entry->value; - } - - return res; - } - - case ZigClangType_Enum: - { - const ZigClangEnumType *enum_ty = reinterpret_cast(ty); - AstNode *enum_type = resolve_enum_decl(c, ZigClangEnumType_getDecl(enum_ty)); - return to_enum_zero_cmp(c, res, enum_type); - } - - case ZigClangType_Elaborated: - { - const ZigClangElaboratedType *elaborated_ty = reinterpret_cast(ty); - switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) { - case ZigClangETK_Enum: { - AstNode *enum_type = trans_qual_type(c, ZigClangElaboratedType_getNamedType(elaborated_ty), - ZigClangExpr_getBeginLoc(expr)); - return to_enum_zero_cmp(c, res, enum_type); - } - case ZigClangETK_Struct: - case ZigClangETK_Union: - case ZigClangETK_Interface: - case ZigClangETK_Class: - case ZigClangETK_Typename: - case ZigClangETK_None: - return res; - } - } - - case ZigClangType_FunctionProto: - case ZigClangType_Record: - case ZigClangType_ConstantArray: - case ZigClangType_Paren: - case ZigClangType_Decayed: - case ZigClangType_Attributed: - case ZigClangType_IncompleteArray: - case ZigClangType_BlockPointer: - case ZigClangType_LValueReference: - case ZigClangType_RValueReference: - case ZigClangType_MemberPointer: - case ZigClangType_VariableArray: - case ZigClangType_DependentSizedArray: - case ZigClangType_DependentSizedExtVector: - case ZigClangType_Vector: - case ZigClangType_ExtVector: - case ZigClangType_FunctionNoProto: - case ZigClangType_UnresolvedUsing: - case ZigClangType_Adjusted: - case ZigClangType_TypeOfExpr: - case ZigClangType_TypeOf: - case ZigClangType_Decltype: - case ZigClangType_UnaryTransform: - case ZigClangType_TemplateTypeParm: - case ZigClangType_SubstTemplateTypeParm: - case ZigClangType_SubstTemplateTypeParmPack: - case ZigClangType_TemplateSpecialization: - case ZigClangType_Auto: - case ZigClangType_InjectedClassName: - case ZigClangType_DependentName: - case ZigClangType_DependentTemplateSpecialization: - case ZigClangType_PackExpansion: - case ZigClangType_ObjCObject: - case ZigClangType_ObjCInterface: - case ZigClangType_Complex: - case ZigClangType_ObjCObjectPointer: - case ZigClangType_Atomic: - case ZigClangType_Pipe: - case ZigClangType_ObjCTypeParam: - case ZigClangType_DeducedTemplateSpecialization: - case ZigClangType_DependentAddressSpace: - case ZigClangType_DependentVector: - case ZigClangType_MacroQualified: - return res; - } - zig_unreachable(); -} - -static AstNode *trans_while_loop(Context *c, TransScope *scope, const ZigClangWhileStmt *stmt) { - TransScopeWhile *while_scope = trans_scope_while_create(c, scope); - - while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, - ZigClangWhileStmt_getCond(stmt), TransRValue); - if (while_scope->node->data.while_expr.condition == nullptr) - return nullptr; - - TransScope *body_scope = trans_stmt(c, &while_scope->base, ZigClangWhileStmt_getBody(stmt), - &while_scope->node->data.while_expr.body); - if (body_scope == nullptr) - return nullptr; - - return while_scope->node; -} - -static AstNode *trans_if_statement(Context *c, TransScope *scope, const ZigClangIfStmt *stmt) { - // if (c) t - // if (c) t else e - AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); - - TransScope *then_scope = trans_stmt(c, scope, ZigClangIfStmt_getThen(stmt), &if_node->data.if_bool_expr.then_block); - if (then_scope == nullptr) - return nullptr; - - if (ZigClangIfStmt_getElse(stmt) != nullptr) { - TransScope *else_scope = trans_stmt(c, scope, ZigClangIfStmt_getElse(stmt), &if_node->data.if_bool_expr.else_node); - if (else_scope == nullptr) - return nullptr; - } - - if_node->data.if_bool_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, ZigClangIfStmt_getCond(stmt), - TransRValue); - if (if_node->data.if_bool_expr.condition == nullptr) - return nullptr; - - return if_node; -} - -static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangCallExpr *stmt) { - AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); - - AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, ZigClangCallExpr_getCallee(stmt), TransRValue); - if (callee_raw_node == nullptr) - return nullptr; - - bool is_ptr = false; - const ZigClangFunctionProtoType *fn_ty = qual_type_get_fn_proto( - ZigClangExpr_getType(ZigClangCallExpr_getCallee(stmt)), &is_ptr); - AstNode *callee_node = nullptr; - if (is_ptr && fn_ty) { - if (ZigClangExpr_getStmtClass(ZigClangCallExpr_getCallee(stmt)) == ZigClangStmt_ImplicitCastExprClass) { - const ZigClangImplicitCastExpr *implicit_cast = reinterpret_cast( - ZigClangCallExpr_getCallee(stmt)); - if (ZigClangImplicitCastExpr_getCastKind(implicit_cast) == ZigClangCK_FunctionToPointerDecay) { - const ZigClangExpr *subexpr = ZigClangImplicitCastExpr_getSubExpr(implicit_cast); - if (ZigClangExpr_getStmtClass(subexpr) == ZigClangStmt_DeclRefExprClass) { - const ZigClangDeclRefExpr *decl_ref = reinterpret_cast(subexpr); - const ZigClangNamedDecl *named_decl = ZigClangDeclRefExpr_getFoundDecl(decl_ref); - if (ZigClangDecl_getKind((const ZigClangDecl *)named_decl) == ZigClangDeclFunction) { - callee_node = callee_raw_node; - } - } - } - } - if (callee_node == nullptr) { - callee_node = trans_create_node_unwrap_null(c, callee_raw_node); - } - } else { - callee_node = callee_raw_node; - } - - node->data.fn_call_expr.fn_ref_expr = callee_node; - - unsigned num_args = ZigClangCallExpr_getNumArgs(stmt); - const ZigClangExpr * const* args = ZigClangCallExpr_getArgs(stmt); - for (unsigned i = 0; i < num_args; i += 1) { - AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue); - if (arg_node == nullptr) - return nullptr; - - node->data.fn_call_expr.params.append(arg_node); - } - - if (result_used == ResultUsedNo && fn_ty && - !ZigClangType_isVoidType(qual_type_canon(ZigClangFunctionProtoType_getReturnType(fn_ty)))) - { - node = trans_create_node_bin_op(c, trans_create_node_symbol_str(c, "_"), BinOpTypeAssign, node); - } - - return node; -} - -static AstNode *trans_member_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangMemberExpr *stmt) -{ - AstNode *container_node = trans_expr(c, ResultUsedYes, scope, ZigClangMemberExpr_getBase(stmt), TransRValue); - if (container_node == nullptr) - return nullptr; - - if (ZigClangMemberExpr_isArrow(stmt)) { - container_node = trans_create_node_ptr_deref(c, container_node); - } - - const char *name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)ZigClangMemberExpr_getMemberDecl(stmt)); - - AstNode *node = trans_create_node_field_access_str(c, container_node, name); - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_array_subscript_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangArraySubscriptExpr *stmt) -{ - AstNode *container_node = trans_expr(c, ResultUsedYes, scope, ZigClangArraySubscriptExpr_getBase(stmt), - TransRValue); - if (container_node == nullptr) - return nullptr; - - AstNode *idx_node = trans_expr(c, ResultUsedYes, scope, ZigClangArraySubscriptExpr_getIdx(stmt), TransRValue); - if (idx_node == nullptr) - return nullptr; - - - AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); - node->data.array_access_expr.array_ref_expr = container_node; - node->data.array_access_expr.subscript = idx_node; - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangCStyleCastExpr *stmt, TransLRValue lrvalue) -{ - AstNode *sub_expr_node = trans_expr(c, ResultUsedYes, scope, ZigClangCStyleCastExpr_getSubExpr(stmt), lrvalue); - if (sub_expr_node == nullptr) - return nullptr; - - AstNode *cast = trans_c_cast(c, ZigClangCStyleCastExpr_getBeginLoc(stmt), ZigClangCStyleCastExpr_getType(stmt), - ZigClangExpr_getType(ZigClangCStyleCastExpr_getSubExpr(stmt)), sub_expr_node); - if (cast == nullptr) - return nullptr; - - return maybe_suppress_result(c, result_used, cast); -} - -static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, ResultUsed result_used, - TransScope *scope, const ZigClangUnaryExprOrTypeTraitExpr *stmt) -{ - AstNode *type_node = trans_qual_type(c, ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(stmt), - ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt)); - if (type_node == nullptr) - return nullptr; - - AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); - node->data.fn_call_expr.params.append(type_node); - return maybe_suppress_result(c, result_used, node); -} - -static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const ZigClangDoStmt *stmt) { - TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope); - - while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); - - AstNode *body_node; - TransScope *child_scope; - if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == ZigClangStmt_CompoundStmtClass) { - // there's already a block in C, so we'll append our condition to it. - // c: do { - // c: a; - // c: b; - // c: } while(c); - // zig: while (true) { - // zig: a; - // zig: b; - // zig: if (!cond) break; - // zig: } - - // We call the low level function so that we can set child_scope to the scope of the generated block. - if (trans_stmt_extra(c, &while_scope->base, ZigClangDoStmt_getBody(stmt), ResultUsedNo, TransRValue, - &body_node, nullptr, &child_scope)) - { - return nullptr; - } - assert(body_node->type == NodeTypeBlock); - } else { - // the C statement is without a block, so we need to create a block to contain it. - // c: do - // c: a; - // c: while(c); - // zig: while (true) { - // zig: a; - // zig: if (!cond) break; - // zig: } - TransScopeBlock *child_block_scope = trans_scope_block_create(c, &while_scope->base); - body_node = child_block_scope->node; - AstNode *child_statement; - child_scope = trans_stmt(c, &child_block_scope->base, ZigClangDoStmt_getBody(stmt), &child_statement); - if (child_scope == nullptr) return nullptr; - if (child_statement != nullptr) { - body_node->data.block.statements.append(child_statement); - } - } - - // if (!cond) break; - AstNode *condition_node = trans_expr(c, ResultUsedYes, child_scope, ZigClangDoStmt_getCond(stmt), TransRValue); - if (condition_node == nullptr) return nullptr; - AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); - terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); - terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); - - assert(terminator_node != nullptr); - body_node->data.block.statements.append(terminator_node); - - while_scope->node->data.while_expr.body = body_node; - - return while_scope->node; -} - -static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ZigClangForStmt *stmt) { - AstNode *loop_block_node; - TransScopeWhile *while_scope; - TransScope *cond_scope; - const ZigClangStmt *init_stmt = ZigClangForStmt_getInit(stmt); - if (init_stmt == nullptr) { - while_scope = trans_scope_while_create(c, parent_scope); - loop_block_node = while_scope->node; - cond_scope = parent_scope; - } else { - TransScopeBlock *child_scope = trans_scope_block_create(c, parent_scope); - loop_block_node = child_scope->node; - - AstNode *vars_node; - cond_scope = trans_stmt(c, &child_scope->base, init_stmt, &vars_node); - if (cond_scope == nullptr) - return nullptr; - if (vars_node != nullptr) - child_scope->node->data.block.statements.append(vars_node); - - while_scope = trans_scope_while_create(c, cond_scope); - - child_scope->node->data.block.statements.append(while_scope->node); - } - - const ZigClangExpr *cond_expr = ZigClangForStmt_getCond(stmt); - if (cond_expr == nullptr) { - while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); - } else { - while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, - cond_expr, TransRValue); - - if (while_scope->node->data.while_expr.condition == nullptr) - return nullptr; - } - - const ZigClangExpr *inc_expr = ZigClangForStmt_getInc(stmt); - if (inc_expr != nullptr) { - AstNode *inc_node = trans_expr(c, ResultUsedNo, cond_scope, inc_expr, TransRValue); - if (inc_node == nullptr) - return nullptr; - while_scope->node->data.while_expr.continue_expr = inc_node; - } - - AstNode *body_statement; - TransScope *body_scope = trans_stmt(c, &while_scope->base, ZigClangForStmt_getBody(stmt), &body_statement); - if (body_scope == nullptr) - return nullptr; - - if (body_statement == nullptr) { - while_scope->node->data.while_expr.body = trans_create_node(c, NodeTypeBlock); - } else { - while_scope->node->data.while_expr.body = body_statement; - } - - return loop_block_node; -} - -static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const ZigClangSwitchStmt *stmt) { - TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope); - - TransScopeSwitch *switch_scope; - - const ZigClangDeclStmt *var_decl_stmt = ZigClangSwitchStmt_getConditionVariableDeclStmt(stmt); - if (var_decl_stmt == nullptr) { - switch_scope = trans_scope_switch_create(c, &block_scope->base); - } else { - AstNode *vars_node; - TransScope *var_scope = trans_stmt(c, &block_scope->base, (const ZigClangStmt *)var_decl_stmt, &vars_node); - if (var_scope == nullptr) - return nullptr; - if (vars_node != nullptr) - block_scope->node->data.block.statements.append(vars_node); - switch_scope = trans_scope_switch_create(c, var_scope); - } - block_scope->node->data.block.statements.append(switch_scope->switch_node); - - // TODO avoid name collisions - Buf *end_label_name = buf_create_from_str("__switch"); - switch_scope->end_label_name = end_label_name; - block_scope->node->data.block.name = end_label_name; - - const ZigClangExpr *cond_expr = ZigClangSwitchStmt_getCond(stmt); - assert(cond_expr != nullptr); - - AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); - if (expr_node == nullptr) - return nullptr; - switch_scope->switch_node->data.switch_expr.expr = expr_node; - - AstNode *body_node; - const ZigClangStmt *body_stmt = ZigClangSwitchStmt_getBody(stmt); - if (ZigClangStmt_getStmtClass(body_stmt) == ZigClangStmt_CompoundStmtClass) { - if (trans_compound_stmt_inline(c, &switch_scope->base, (const ZigClangCompoundStmt *)body_stmt, - block_scope->node, nullptr)) - { - return nullptr; - } - } else { - TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node); - if (body_scope == nullptr) - return nullptr; - if (body_node != nullptr) - block_scope->node->data.block.statements.append(body_node); - } - - if (!switch_scope->found_default && !ZigClangSwitchStmt_isAllEnumCasesCovered(stmt)) { - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - prong_node->data.switch_prong.expr = trans_create_node_break(c, end_label_name, nullptr); - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - } - - return block_scope->node; -} - -static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) { - while (scope != nullptr) { - if (scope->id == TransScopeIdSwitch) { - return (TransScopeSwitch *)scope; - } - scope = scope->parent; - } - return nullptr; -} - -static int trans_switch_case(Context *c, TransScope *parent_scope, const ZigClangCaseStmt *stmt, AstNode **out_node, - TransScope **out_scope) { - *out_node = nullptr; - - if (ZigClangCaseStmt_getRHS(stmt) != nullptr) { - emit_warning(c, ZigClangCaseStmt_getBeginLoc(stmt), "TODO support GNU switch case a ... b extension"); - return ErrorUnexpected; - } - - TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); - assert(switch_scope != nullptr); - - Buf *label_name = buf_sprintf("__case_%" PRIu32, switch_scope->case_index); - switch_scope->case_index += 1; - - { - // Add the prong - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, ZigClangCaseStmt_getLHS(stmt), - TransRValue); - if (item_node == nullptr) - return ErrorUnexpected; - prong_node->data.switch_prong.items.append(item_node); - prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr); - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - } - - TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); - - AstNode *case_block = trans_create_node(c, NodeTypeBlock); - case_block->data.block.name = label_name; - case_block->data.block.statements = scope_block->node->data.block.statements; - scope_block->node->data.block.statements = {0}; - scope_block->node->data.block.statements.append(case_block); - - AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, ZigClangCaseStmt_getSubStmt(stmt), &sub_stmt_node); - if (new_scope == nullptr) - return ErrorUnexpected; - if (sub_stmt_node != nullptr) - scope_block->node->data.block.statements.append(sub_stmt_node); - - *out_scope = new_scope; - return ErrorNone; -} - -static int trans_switch_default(Context *c, TransScope *parent_scope, const ZigClangDefaultStmt *stmt, - AstNode **out_node, TransScope **out_scope) -{ - *out_node = nullptr; - - TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); - assert(switch_scope != nullptr); - - Buf *label_name = buf_sprintf("__default"); - - { - // Add the prong - AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); - prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr); - switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); - switch_scope->found_default = true; - } - - TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); - - AstNode *case_block = trans_create_node(c, NodeTypeBlock); - case_block->data.block.name = label_name; - case_block->data.block.statements = scope_block->node->data.block.statements; - scope_block->node->data.block.statements = {0}; - scope_block->node->data.block.statements.append(case_block); - - AstNode *sub_stmt_node; - TransScope *new_scope = trans_stmt(c, parent_scope, ZigClangDefaultStmt_getSubStmt(stmt), &sub_stmt_node); - if (new_scope == nullptr) - return ErrorUnexpected; - if (sub_stmt_node != nullptr) - scope_block->node->data.block.statements.append(sub_stmt_node); - - *out_scope = new_scope; - return ErrorNone; -} - -static AstNode *trans_string_literal(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangStringLiteral *stmt) -{ - switch (ZigClangStringLiteral_getKind(stmt)) { - case ZigClangStringLiteral_StringKind_Ascii: - case ZigClangStringLiteral_StringKind_UTF8: { - size_t str_len; - const char *str_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &str_len); - AstNode *node = trans_create_node_str_lit(c, buf_create_from_mem(str_ptr, str_len)); - return maybe_suppress_result(c, result_used, node); - } - case ZigClangStringLiteral_StringKind_UTF16: - emit_warning(c, ZigClangStmt_getBeginLoc((const ZigClangStmt *)stmt), "TODO support UTF16 string literals"); - return nullptr; - case ZigClangStringLiteral_StringKind_UTF32: - emit_warning(c, ZigClangStmt_getBeginLoc((const ZigClangStmt *)stmt), "TODO support UTF32 string literals"); - return nullptr; - case ZigClangStringLiteral_StringKind_Wide: - emit_warning(c, ZigClangStmt_getBeginLoc((const ZigClangStmt *)stmt), "TODO support wide string literals"); - return nullptr; - } - zig_unreachable(); -} - -static AstNode *trans_break_stmt(Context *c, TransScope *scope, const ZigClangBreakStmt *stmt) { - TransScope *cur_scope = scope; - while (cur_scope != nullptr) { - if (cur_scope->id == TransScopeIdWhile) { - return trans_create_node(c, NodeTypeBreak); - } else if (cur_scope->id == TransScopeIdSwitch) { - TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope; - return trans_create_node_break(c, switch_scope->end_label_name, nullptr); - } - cur_scope = cur_scope->parent; - } - zig_unreachable(); -} - -static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ZigClangContinueStmt *stmt) { - return trans_create_node(c, NodeTypeContinue); -} - -static AstNode *trans_predefined_expr(Context *c, ResultUsed result_used, TransScope *scope, - const ZigClangPredefinedExpr *expr) -{ - return trans_string_literal(c, result_used, scope, ZigClangPredefinedExpr_getFunctionName(expr)); -} - -static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_scope, AstNode *result_node) { - if (result_node == nullptr) - return ErrorUnexpected; - *out_node = result_node; - if (out_scope != nullptr) - *out_scope = in_scope; - return ErrorNone; -} - -static int trans_stmt_extra(Context *c, TransScope *scope, const ZigClangStmt *stmt, - ResultUsed result_used, TransLRValue lrvalue, - AstNode **out_node, TransScope **out_child_scope, - TransScope **out_node_scope) -{ - ZigClangStmtClass sc = ZigClangStmt_getStmtClass(stmt); - switch (sc) { - case ZigClangStmt_ReturnStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_return_stmt(c, scope, (const ZigClangReturnStmt *)stmt)); - case ZigClangStmt_CompoundStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_compound_stmt(c, scope, (const ZigClangCompoundStmt *)stmt, out_node_scope)); - case ZigClangStmt_IntegerLiteralClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_integer_literal(c, result_used, (const ZigClangIntegerLiteral *)stmt)); - case ZigClangStmt_ConditionalOperatorClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_conditional_operator(c, result_used, scope, (const ZigClangConditionalOperator *)stmt)); - case ZigClangStmt_BinaryOperatorClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_binary_operator(c, result_used, scope, (const ZigClangBinaryOperator *)stmt)); - case ZigClangStmt_CompoundAssignOperatorClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_compound_assign_operator(c, result_used, scope, (const ZigClangCompoundAssignOperator *)stmt)); - case ZigClangStmt_ImplicitCastExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_implicit_cast_expr(c, result_used, scope, (const ZigClangImplicitCastExpr *)stmt)); - case ZigClangStmt_DeclRefExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_decl_ref_expr(c, scope, (const ZigClangDeclRefExpr *)stmt, lrvalue)); - case ZigClangStmt_UnaryOperatorClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_unary_operator(c, result_used, scope, (const ZigClangUnaryOperator *)stmt)); - case ZigClangStmt_DeclStmtClass: - return trans_local_declaration(c, scope, (const ZigClangDeclStmt *)stmt, out_node, out_child_scope); - case ZigClangStmt_DoStmtClass: - case ZigClangStmt_WhileStmtClass: { - AstNode *while_node = sc == ZigClangStmt_DoStmtClass - ? trans_do_loop(c, scope, (const ZigClangDoStmt *)stmt) - : trans_while_loop(c, scope, (const ZigClangWhileStmt *)stmt); - - if (while_node == nullptr) - return ErrorUnexpected; - - assert(while_node->type == NodeTypeWhileExpr); - if (while_node->data.while_expr.body == nullptr) - while_node->data.while_expr.body = trans_create_node(c, NodeTypeBlock); - - return wrap_stmt(out_node, out_child_scope, scope, while_node); - } - case ZigClangStmt_IfStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_if_statement(c, scope, (const ZigClangIfStmt *)stmt)); - case ZigClangStmt_CallExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_call_expr(c, result_used, scope, (const ZigClangCallExpr *)stmt)); - case ZigClangStmt_NullStmtClass: - *out_node = trans_create_node(c, NodeTypeBlock); - *out_child_scope = scope; - return ErrorNone; - case ZigClangStmt_MemberExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_member_expr(c, result_used, scope, (const ZigClangMemberExpr *)stmt)); - case ZigClangStmt_ArraySubscriptExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_array_subscript_expr(c, result_used, scope, (const ZigClangArraySubscriptExpr *)stmt)); - case ZigClangStmt_CStyleCastExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_c_style_cast_expr(c, result_used, scope, (const ZigClangCStyleCastExpr *)stmt, lrvalue)); - case ZigClangStmt_UnaryExprOrTypeTraitExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_unary_expr_or_type_trait_expr(c, result_used, scope, (const ZigClangUnaryExprOrTypeTraitExpr *)stmt)); - case ZigClangStmt_ForStmtClass: { - AstNode *node = trans_for_loop(c, scope, (const ZigClangForStmt *)stmt); - return wrap_stmt(out_node, out_child_scope, scope, node); - } - case ZigClangStmt_StringLiteralClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_string_literal(c, result_used, scope, (const ZigClangStringLiteral *)stmt)); - case ZigClangStmt_BreakStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_break_stmt(c, scope, (const ZigClangBreakStmt *)stmt)); - case ZigClangStmt_ContinueStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_continue_stmt(c, scope, (const ZigClangContinueStmt *)stmt)); - case ZigClangStmt_ParenExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_expr(c, result_used, scope, - ZigClangParenExpr_getSubExpr((const ZigClangParenExpr *)stmt), lrvalue)); - case ZigClangStmt_SwitchStmtClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_switch_stmt(c, scope, (const ZigClangSwitchStmt *)stmt)); - case ZigClangStmt_CaseStmtClass: - return trans_switch_case(c, scope, (const ZigClangCaseStmt *)stmt, out_node, out_child_scope); - case ZigClangStmt_DefaultStmtClass: - return trans_switch_default(c, scope, (const ZigClangDefaultStmt *)stmt, out_node, out_child_scope); - case ZigClangStmt_ConstantExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_constant_expr(c, result_used, (const ZigClangConstantExpr *)stmt)); - case ZigClangStmt_PredefinedExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_predefined_expr(c, result_used, scope, (const ZigClangPredefinedExpr *)stmt)); - case ZigClangStmt_StmtExprClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_stmt_expr(c, result_used, scope, (const ZigClangStmtExpr *)stmt, out_node_scope)); - case ZigClangStmt_NoStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C NoStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_GCCAsmStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GCCAsmStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_MSAsmStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSAsmStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_AttributedStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AttributedStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXCatchStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXCatchStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXForRangeStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXForRangeStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXTryStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTryStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CapturedStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CapturedStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CoreturnStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoreturnStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_CoroutineBodyStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoroutineBodyStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_BinaryConditionalOperatorClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C BinaryConditionalOperatorClass"); - return ErrorUnexpected; - case ZigClangStmt_AddrLabelExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AddrLabelExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ArrayInitIndexExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayInitIndexExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ArrayInitLoopExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayInitLoopExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ArrayTypeTraitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ArrayTypeTraitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_AsTypeExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AsTypeExprClass"); - return ErrorUnexpected; - case ZigClangStmt_AtomicExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C AtomicExprClass"); - return ErrorUnexpected; - case ZigClangStmt_BlockExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C BlockExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXBindTemporaryExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXBindTemporaryExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXBoolLiteralExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXBoolLiteralExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXConstructExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXConstructExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXTemporaryObjectExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTemporaryObjectExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXDefaultArgExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDefaultArgExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXDefaultInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDefaultInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXDeleteExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDeleteExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXDependentScopeMemberExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDependentScopeMemberExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXFoldExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXFoldExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXInheritedCtorInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXInheritedCtorInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXNewExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNewExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXNoexceptExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNoexceptExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXNullPtrLiteralExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXNullPtrLiteralExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXPseudoDestructorExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXPseudoDestructorExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXScalarValueInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXScalarValueInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXStdInitializerListExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXStdInitializerListExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXThisExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXThisExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXThrowExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXThrowExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXTypeidExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXTypeidExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXUnresolvedConstructExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXUnresolvedConstructExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXUuidofExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXUuidofExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CUDAKernelCallExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CUDAKernelCallExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXMemberCallExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXMemberCallExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXOperatorCallExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXOperatorCallExprClass"); - return ErrorUnexpected; - case ZigClangStmt_UserDefinedLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UserDefinedLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXFunctionalCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXFunctionalCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXConstCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXConstCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXDynamicCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXDynamicCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXReinterpretCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXReinterpretCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CXXStaticCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CXXStaticCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCBridgedCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBridgedCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CharacterLiteralClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_character_literal(c, result_used, (const ZigClangCharacterLiteral *)stmt)); - return ErrorUnexpected; - case ZigClangStmt_ChooseExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ChooseExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CompoundLiteralExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CompoundLiteralExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ConvertVectorExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ConvertVectorExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CoawaitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoawaitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_CoyieldExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C CoyieldExprClass"); - return ErrorUnexpected; - case ZigClangStmt_DependentCoawaitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DependentCoawaitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_DependentScopeDeclRefExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DependentScopeDeclRefExprClass"); - return ErrorUnexpected; - case ZigClangStmt_DesignatedInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DesignatedInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_DesignatedInitUpdateExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C DesignatedInitUpdateExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ExpressionTraitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExpressionTraitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ExtVectorElementExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExtVectorElementExprClass"); - return ErrorUnexpected; - case ZigClangStmt_FixedPointLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FixedPointLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_FloatingLiteralClass: - return wrap_stmt(out_node, out_child_scope, scope, - trans_floating_literal(c, result_used, (const ZigClangFloatingLiteral *)stmt)); - case ZigClangStmt_ExprWithCleanupsClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ExprWithCleanupsClass"); - return ErrorUnexpected; - case ZigClangStmt_FunctionParmPackExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C FunctionParmPackExprClass"); - return ErrorUnexpected; - case ZigClangStmt_GNUNullExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GNUNullExprClass"); - return ErrorUnexpected; - case ZigClangStmt_GenericSelectionExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GenericSelectionExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ImaginaryLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ImaginaryLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_ImplicitValueInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ImplicitValueInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_InitListExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C InitListExprClass"); - return ErrorUnexpected; - case ZigClangStmt_LambdaExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C LambdaExprClass"); - return ErrorUnexpected; - case ZigClangStmt_MSPropertyRefExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSPropertyRefExprClass"); - return ErrorUnexpected; - case ZigClangStmt_MSPropertySubscriptExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSPropertySubscriptExprClass"); - return ErrorUnexpected; - case ZigClangStmt_MaterializeTemporaryExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MaterializeTemporaryExprClass"); - return ErrorUnexpected; - case ZigClangStmt_NoInitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C NoInitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPArraySectionExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPArraySectionExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCArrayLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCArrayLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAvailabilityCheckExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAvailabilityCheckExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCBoolLiteralExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBoolLiteralExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCBoxedExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCBoxedExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCDictionaryLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCDictionaryLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCEncodeExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCEncodeExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCIndirectCopyRestoreExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIndirectCopyRestoreExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCIsaExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIsaExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCIvarRefExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCIvarRefExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCMessageExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCMessageExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCPropertyRefExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCPropertyRefExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCProtocolExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCProtocolExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCSelectorExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCSelectorExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCStringLiteralClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCStringLiteralClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCSubscriptRefExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCSubscriptRefExprClass"); - return ErrorUnexpected; - case ZigClangStmt_OffsetOfExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OffsetOfExprClass"); - return ErrorUnexpected; - case ZigClangStmt_OpaqueValueExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OpaqueValueExprClass"); - return ErrorUnexpected; - case ZigClangStmt_UnresolvedLookupExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UnresolvedLookupExprClass"); - return ErrorUnexpected; - case ZigClangStmt_UnresolvedMemberExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C UnresolvedMemberExprClass"); - return ErrorUnexpected; - case ZigClangStmt_PackExpansionExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C PackExpansionExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ParenListExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ParenListExprClass"); - return ErrorUnexpected; - case ZigClangStmt_PseudoObjectExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C PseudoObjectExprClass"); - return ErrorUnexpected; - case ZigClangStmt_ShuffleVectorExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ShuffleVectorExprClass"); - return ErrorUnexpected; - case ZigClangStmt_SizeOfPackExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SizeOfPackExprClass"); - return ErrorUnexpected; - case ZigClangStmt_SubstNonTypeTemplateParmExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SubstNonTypeTemplateParmExprClass"); - return ErrorUnexpected; - case ZigClangStmt_SubstNonTypeTemplateParmPackExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); - return ErrorUnexpected; - case ZigClangStmt_TypeTraitExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C TypeTraitExprClass"); - return ErrorUnexpected; - case ZigClangStmt_TypoExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C TypoExprClass"); - return ErrorUnexpected; - case ZigClangStmt_VAArgExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C VAArgExprClass"); - return ErrorUnexpected; - case ZigClangStmt_GotoStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C GotoStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_IndirectGotoStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C IndirectGotoStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_LabelStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C LabelStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_MSDependentExistsStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C MSDependentExistsStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPAtomicDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPAtomicDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPBarrierDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPBarrierDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPCancelDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCancelDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPCancellationPointDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCancellationPointDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPCriticalDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPCriticalDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPFlushDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPFlushDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPDistributeDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPDistributeParallelForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeParallelForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPDistributeParallelForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPDistributeSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPDistributeSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPParallelForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPParallelForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetParallelForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetTeamsDistributeDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetTeamsDistributeParallelForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetTeamsDistributeParallelForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetTeamsDistributeSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskLoopDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskLoopDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskLoopSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskLoopSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTeamsDistributeDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTeamsDistributeParallelForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTeamsDistributeParallelForSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTeamsDistributeSimdDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPMasterDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPMasterDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPOrderedDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPOrderedDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPParallelDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPParallelSectionsDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPParallelSectionsDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPSectionDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSectionDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPSectionsDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSectionsDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPSingleDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPSingleDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetDataDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetDataDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetEnterDataDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetEnterDataDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetExitDataDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetExitDataDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetParallelDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetParallelForDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetParallelForDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetTeamsDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetTeamsDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTargetUpdateDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTargetUpdateDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskgroupDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskgroupDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskwaitDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskwaitDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTaskyieldDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTaskyieldDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_OMPTeamsDirectiveClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C OMPTeamsDirectiveClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAtCatchStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtCatchStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAtFinallyStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtFinallyStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAtSynchronizedStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtSynchronizedStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAtThrowStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtThrowStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAtTryStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAtTryStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCAutoreleasePoolStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCAutoreleasePoolStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_ObjCForCollectionStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C ObjCForCollectionStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_SEHExceptStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHExceptStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_SEHFinallyStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHFinallyStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_SEHLeaveStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHLeaveStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_SEHTryStmtClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SEHTryStmtClass"); - return ErrorUnexpected; - case ZigClangStmt_BuiltinBitCastExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C BuiltinBitCastExprClass"); - return ErrorUnexpected; - case ZigClangStmt_SourceLocExprClass: - emit_warning(c, ZigClangStmt_getBeginLoc(stmt), "TODO handle C SourceLocExprClass"); - return ErrorUnexpected; - } - zig_unreachable(); -} - -// Returns null if there was an error -static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const ZigClangExpr *expr, - TransLRValue lrval) -{ - AstNode *result_node; - TransScope *result_scope; - if (trans_stmt_extra(c, scope, (const ZigClangStmt *)expr, result_used, lrval, &result_node, &result_scope, nullptr)) { - return nullptr; - } - return result_node; -} - -// Statements have no result and no concept of L or R value. -// Returns child scope, or null if there was an error -static TransScope *trans_stmt(Context *c, TransScope *scope, const ZigClangStmt *stmt, AstNode **out_node) { - TransScope *child_scope; - if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) { - return nullptr; - } - return child_scope; -} - -static void visit_fn_decl(Context *c, const ZigClangFunctionDecl *fn_decl) { - Buf *fn_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)fn_decl)); - - if (get_global(c, fn_name)) { - // we already saw this function - return; - } - - AstNode *proto_node = trans_qual_type(c, ZigClangFunctionDecl_getType(fn_decl), - ZigClangFunctionDecl_getLocation(fn_decl)); - if (proto_node == nullptr) { - emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), - "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); - return; - } - - proto_node->data.fn_proto.name = fn_name; - proto_node->data.fn_proto.is_extern = !ZigClangFunctionDecl_hasBody(fn_decl); - - ZigClangStorageClass sc = ZigClangFunctionDecl_getStorageClass(fn_decl); - if (sc == ZigClangStorageClass_None) { - proto_node->data.fn_proto.visib_mod = VisibModPub; - proto_node->data.fn_proto.is_export = ZigClangFunctionDecl_hasBody(fn_decl) ? c->want_export : false; - } else if (sc == ZigClangStorageClass_Extern || sc == ZigClangStorageClass_Static) { - proto_node->data.fn_proto.visib_mod = VisibModPub; - } else if (sc == ZigClangStorageClass_PrivateExtern) { - emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unsupported storage class: private extern"); - return; - } else { - emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unsupported storage class: unknown"); - return; - } - - TransScope *scope = &c->global_scope->base; - - for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(i); - const ZigClangParmVarDecl *param = ZigClangFunctionDecl_getParamDecl(fn_decl, i); - const char *name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)param); - - Buf *proto_param_name; - if (strlen(name) != 0) { - proto_param_name = buf_create_from_str(name); - } else { - proto_param_name = param_node->data.param_decl.name; - if (proto_param_name == nullptr) { - proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } - } - - TransScopeVar *scope_var = trans_scope_var_create(c, scope, proto_param_name); - scope = &scope_var->base; - - param_node->data.param_decl.name = scope_var->zig_name; - } - - if (!ZigClangFunctionDecl_hasBody(fn_decl)) { - // just a prototype - add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); - return; - } - - // actual function definition with body - c->ptr_params.clear(); - const ZigClangStmt *body = ZigClangFunctionDecl_getBody(fn_decl); - AstNode *actual_body_node; - TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node); - if (result_scope == nullptr) { - emit_warning(c, ZigClangFunctionDecl_getLocation(fn_decl), "unable to translate function"); - return; - } - assert(actual_body_node != nullptr); - assert(actual_body_node->type == NodeTypeBlock); - - // it worked - - AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); - - for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { - AstNode *param_node = proto_node->data.fn_proto.params.at(i); - Buf *good_name = param_node->data.param_decl.name; - - if (c->ptr_params.maybe_get(good_name) != nullptr) { - // TODO: avoid name collisions - Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); - param_node->data.param_decl.name = mangled_name; - - // var c_name = _mangled_name; - AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); - - body_node_with_param_inits->data.block.statements.append(parameter_init); - } - } - - for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { - body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); - } - - AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); - fn_def_node->data.fn_def.fn_proto = proto_node; - fn_def_node->data.fn_def.body = body_node_with_param_inits; - - proto_node->data.fn_proto.fn_def_node = fn_def_node; - add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); -} - -static AstNode *resolve_typdef_as_builtin(Context *c, const ZigClangTypedefNameDecl *typedef_decl, const char *primitive_name) { - AstNode *node = trans_create_node_symbol_str(c, primitive_name); - c->decl_table.put(typedef_decl, node); - return node; -} - -static AstNode *resolve_typedef_decl(Context *c, const ZigClangTypedefNameDecl *typedef_decl) { - auto existing_entry = c->decl_table.maybe_get((void*)ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)); - if (existing_entry) { - return existing_entry->value; - } - - ZigClangQualType child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); - Buf *type_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)typedef_decl)); - - if (buf_eql_str(type_name, "uint8_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "u8"); - } else if (buf_eql_str(type_name, "int8_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "i8"); - } else if (buf_eql_str(type_name, "uint16_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "u16"); - } else if (buf_eql_str(type_name, "int16_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "i16"); - } else if (buf_eql_str(type_name, "uint32_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "u32"); - } else if (buf_eql_str(type_name, "int32_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "i32"); - } else if (buf_eql_str(type_name, "uint64_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "u64"); - } else if (buf_eql_str(type_name, "int64_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "i64"); - } else if (buf_eql_str(type_name, "intptr_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "isize"); - } else if (buf_eql_str(type_name, "uintptr_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "usize"); - } else if (buf_eql_str(type_name, "ssize_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "isize"); - } else if (buf_eql_str(type_name, "size_t")) { - return resolve_typdef_as_builtin(c, typedef_decl, "usize"); - } - - // if the underlying type is anonymous, we can special case it to just - // use the name of this typedef - // TODO - - // trans_qual_type here might cause us to look at this typedef again so we put the item in the map first - AstNode *symbol_node = trans_create_node_symbol(c, type_name); - c->decl_table.put(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl), symbol_node); - - AstNode *type_node = trans_qual_type(c, child_qt, ZigClangTypedefNameDecl_getLocation(typedef_decl)); - if (type_node == nullptr) { - emit_warning(c, ZigClangTypedefNameDecl_getLocation(typedef_decl), - "typedef %s - unresolved child type", buf_ptr(type_name)); - c->decl_table.put(typedef_decl, nullptr); - // TODO add global var with type_name equal to @compileError("unable to resolve C type") - return nullptr; - } - add_global_var(c, type_name, type_node); - - return symbol_node; -} - -struct AstNode *demote_enum_to_opaque(Context *c, const ZigClangEnumDecl *enum_decl, Buf *full_type_name, - Buf *bare_name) -{ - AstNode *opaque_node = trans_create_node_opaque(c); - if (full_type_name == nullptr) { - c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), opaque_node); - return opaque_node; - } - AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - add_global_weak_alias(c, bare_name, full_type_name); - add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), symbol_node); - return symbol_node; -} - -static AstNode *resolve_enum_decl(Context *c, const ZigClangEnumDecl *enum_decl) { - auto existing_entry = c->decl_table.maybe_get(ZigClangEnumDecl_getCanonicalDecl(enum_decl)); - if (existing_entry) { - return existing_entry->value; - } - - const char *raw_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_decl); - bool is_anonymous = (raw_name[0] == 0); - Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); - Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); - - const ZigClangEnumDecl *enum_def = ZigClangEnumDecl_getDefinition(enum_decl); - if (!enum_def) { - return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); - } - - - bool pure_enum = true; - uint32_t field_count = 0; - for (ZigClangEnumDecl_enumerator_iterator it = ZigClangEnumDecl_enumerator_begin(enum_def), - it_end = ZigClangEnumDecl_enumerator_end(enum_def); - ZigClangEnumDecl_enumerator_iterator_neq(it, it_end); - it = ZigClangEnumDecl_enumerator_iterator_next(it), field_count += 1) - { - const ZigClangEnumConstantDecl *enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); - if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) { - pure_enum = false; - } - } - AstNode *tag_int_type = trans_qual_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), - ZigClangEnumDecl_getLocation(enum_decl)); - assert(tag_int_type); - - AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); - enum_node->data.container_decl.kind = ContainerKindEnum; - enum_node->data.container_decl.layout = ContainerLayoutExtern; - // TODO only emit this tag type if the enum tag type is not the default. - // I don't know what the default is, need to figure out how clang is deciding. - // it appears to at least be different across gcc/msvc - if (!c_is_builtin_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), ZigClangBuiltinTypeUInt) && - !c_is_builtin_type(c, ZigClangEnumDecl_getIntegerType(enum_decl), ZigClangBuiltinTypeInt)) - { - enum_node->data.container_decl.init_arg_expr = tag_int_type; - } - enum_node->data.container_decl.fields.resize(field_count); - uint32_t i = 0; - for (ZigClangEnumDecl_enumerator_iterator it = ZigClangEnumDecl_enumerator_begin(enum_def), - it_end = ZigClangEnumDecl_enumerator_end(enum_def); - ZigClangEnumDecl_enumerator_iterator_neq(it, it_end); - it = ZigClangEnumDecl_enumerator_iterator_next(it), i += 1) - { - const ZigClangEnumConstantDecl *enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); - - Buf *enum_val_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_const)); - Buf *field_name; - if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { - field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); - } else { - field_name = enum_val_name; - } - - AstNode *int_node = pure_enum && !is_anonymous ? - nullptr : trans_create_node_apint(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); - AstNode *field_node = trans_create_node(c, NodeTypeStructField); - field_node->data.struct_field.name = field_name; - field_node->data.struct_field.type = nullptr; - field_node->data.struct_field.value = int_node; - enum_node->data.container_decl.fields.items[i] = field_node; - - // in C each enum value is in the global namespace. so we put them there too. - // at this point we can rely on the enum emitting successfully - if (is_anonymous) { - Buf *enum_val_name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)enum_const)); - add_global_var(c, enum_val_name, int_node); - } else { - AstNode *field_access_node = trans_create_node_field_access(c, - trans_create_node_symbol(c, full_type_name), field_name); - add_global_var(c, enum_val_name, field_access_node); - } - } - - if (is_anonymous) { - c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), enum_node); - return enum_node; - } else { - AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - add_global_weak_alias(c, bare_name, full_type_name); - add_global_var(c, full_type_name, enum_node); - c->decl_table.put(ZigClangEnumDecl_getCanonicalDecl(enum_decl), symbol_node); - return enum_node; - } -} - -static AstNode *demote_struct_to_opaque(Context *c, const ZigClangRecordDecl *record_decl, - Buf *full_type_name, Buf *bare_name) -{ - AstNode *opaque_node = trans_create_node_opaque(c); - if (full_type_name == nullptr) { - c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), opaque_node); - return opaque_node; - } - AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); - add_global_weak_alias(c, bare_name, full_type_name); - add_global_var(c, full_type_name, opaque_node); - c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), symbol_node); - return symbol_node; -} - -static AstNode *resolve_record_decl(Context *c, const ZigClangRecordDecl *record_decl) { - auto existing_entry = c->decl_table.maybe_get(ZigClangRecordDecl_getCanonicalDecl(record_decl)); - if (existing_entry) { - return existing_entry->value; - } - - const char *raw_name = ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)record_decl); - const char *container_kind_name; - ContainerKind container_kind; - if (ZigClangRecordDecl_isUnion(record_decl)) { - container_kind_name = "union"; - container_kind = ContainerKindUnion; - } else if (ZigClangRecordDecl_isStruct(record_decl)) { - container_kind_name = "struct"; - container_kind = ContainerKindStruct; - } else { - emit_warning(c, ZigClangRecordDecl_getLocation(record_decl), - "skipping record %s, not a struct or union", raw_name); - c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), nullptr); - return nullptr; - } - - bool is_anonymous = ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) || raw_name[0] == 0; - Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); - Buf *full_type_name = (bare_name == nullptr) ? - nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); - - const ZigClangRecordDecl *record_def = ZigClangRecordDecl_getDefinition(record_decl); - if (record_def == nullptr) { - return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); - } - - // count fields and validate - uint32_t field_count = 0; - for (ZigClangRecordDecl_field_iterator it = ZigClangRecordDecl_field_begin(record_def), - it_end = ZigClangRecordDecl_field_end(record_def); - ZigClangRecordDecl_field_iterator_neq(it, it_end); - it = ZigClangRecordDecl_field_iterator_next(it), field_count += 1) - { - const ZigClangFieldDecl *field_decl = ZigClangRecordDecl_field_iterator_deref(it); - - if (ZigClangFieldDecl_isBitField(field_decl)) { - emit_warning(c, ZigClangFieldDecl_getLocation(field_decl), - "%s %s demoted to opaque type - has bitfield", container_kind_name, - is_anonymous ? "(anon)" : buf_ptr(bare_name)); - return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); - } - } - - AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); - struct_node->data.container_decl.kind = container_kind; - struct_node->data.container_decl.layout = ContainerLayoutExtern; - - // TODO handle attribute packed - - struct_node->data.container_decl.fields.resize(field_count); - - // must be before fields in case a circular reference happens - if (is_anonymous) { - c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), struct_node); - } else { - c->decl_table.put(ZigClangRecordDecl_getCanonicalDecl(record_decl), trans_create_node_symbol(c, full_type_name)); - } - - uint32_t i = 0; - for (ZigClangRecordDecl_field_iterator it = ZigClangRecordDecl_field_begin(record_def), - it_end = ZigClangRecordDecl_field_end(record_def); - ZigClangRecordDecl_field_iterator_neq(it, it_end); - it = ZigClangRecordDecl_field_iterator_next(it), i += 1) - { - const ZigClangFieldDecl *field_decl = ZigClangRecordDecl_field_iterator_deref(it); - - AstNode *field_node = trans_create_node(c, NodeTypeStructField); - field_node->data.struct_field.name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)field_decl)); - field_node->data.struct_field.type = trans_qual_type(c, ZigClangFieldDecl_getType(field_decl), - ZigClangFieldDecl_getLocation(field_decl)); - - if (field_node->data.struct_field.type == nullptr) { - emit_warning(c, ZigClangFieldDecl_getLocation(field_decl), - "%s %s demoted to opaque type - unresolved type", - container_kind_name, - is_anonymous ? "(anon)" : buf_ptr(bare_name)); - - return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); - } - - struct_node->data.container_decl.fields.items[i] = field_node; - } - - if (is_anonymous) { - return struct_node; - } else { - add_global_weak_alias(c, bare_name, full_type_name); - add_global_var(c, full_type_name, struct_node); - return trans_create_node_symbol(c, full_type_name); - } -} - -static AstNode *trans_ap_value(Context *c, const ZigClangAPValue *ap_value, ZigClangQualType qt, - ZigClangSourceLocation source_loc) -{ - switch (ZigClangAPValue_getKind(ap_value)) { - case ZigClangAPValueInt: - return trans_create_node_apint(c, ZigClangAPValue_getInt(ap_value)); - case ZigClangAPValueNone: - return trans_create_node(c, NodeTypeUndefinedLiteral); - case ZigClangAPValueArray: { - emit_warning(c, source_loc, "TODO add a test case for this code"); - - unsigned init_count = ZigClangAPValue_getArrayInitializedElts(ap_value); - unsigned all_count = ZigClangAPValue_getArraySize(ap_value); - unsigned leftover_count = all_count - init_count; - AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr); - AstNode *arr_type_node = trans_qual_type(c, qt, source_loc); - if (leftover_count != 0) { // We can't use the size of the final array for a partial initializer. - bigint_init_unsigned(arr_type_node->data.array_type.size->data.int_literal.bigint, init_count); - } - init_node->data.container_init_expr.type = arr_type_node; - init_node->data.container_init_expr.kind = ContainerInitKindArray; - - const ZigClangType *qt_type = ZigClangQualType_getTypePtr(qt); - ZigClangQualType child_qt = ZigClangArrayType_getElementType(ZigClangType_getAsArrayTypeUnsafe(qt_type)); - - for (size_t i = 0; i < init_count; i += 1) { - const ZigClangAPValue *elem_ap_val = ZigClangAPValue_getArrayInitializedElt(ap_value, i); - AstNode *elem_node = trans_ap_value(c, elem_ap_val, child_qt, source_loc); - if (elem_node == nullptr) - return nullptr; - init_node->data.container_init_expr.entries.append(elem_node); - } - if (leftover_count == 0) { - return init_node; - } - - const ZigClangAPValue *filler_ap_val = ZigClangAPValue_getArrayFiller(ap_value); - AstNode *filler_node = trans_ap_value(c, filler_ap_val, child_qt, source_loc); - if (filler_node == nullptr) - return nullptr; - - AstNode* filler_arr_type = trans_create_node(c, NodeTypeArrayType); - *filler_arr_type = *arr_type_node; - filler_arr_type->data.array_type.size = trans_create_node_unsigned(c, 1); - - AstNode *filler_arr_1 = trans_create_node(c, NodeTypeContainerInitExpr); - filler_arr_1->data.container_init_expr.type = filler_arr_type; - filler_arr_1->data.container_init_expr.kind = ContainerInitKindArray; - filler_arr_1->data.container_init_expr.entries.append(filler_node); - - AstNode *rhs_node; - if (leftover_count == 1) { - rhs_node = filler_arr_1; - } else { - AstNode *amt_node = trans_create_node_unsigned(c, leftover_count); - rhs_node = trans_create_node_bin_op(c, filler_arr_1, BinOpTypeArrayMult, amt_node); - } - - if (init_count == 0) { - return rhs_node; - } - - return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node); - } - case ZigClangAPValueLValue: { - const ZigClangAPValueLValueBase lval_base = ZigClangAPValue_getLValueBase(ap_value); - if (const ZigClangExpr *expr = ZigClangAPValueLValueBase_dyn_cast_Expr(lval_base)) { - return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue); - } - emit_warning(c, source_loc, "TODO handle initializer LValue ValueDecl"); - return nullptr; - } - case ZigClangAPValueFloat: - emit_warning(c, source_loc, "unsupported initializer value kind: Float"); - return nullptr; - case ZigClangAPValueComplexInt: - emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt"); - return nullptr; - case ZigClangAPValueComplexFloat: - emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat"); - return nullptr; - case ZigClangAPValueVector: - emit_warning(c, source_loc, "unsupported initializer value kind: Vector"); - return nullptr; - case ZigClangAPValueStruct: - emit_warning(c, source_loc, "unsupported initializer value kind: Struct"); - return nullptr; - case ZigClangAPValueUnion: - emit_warning(c, source_loc, "unsupported initializer value kind: Union"); - return nullptr; - case ZigClangAPValueMemberPointer: - emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer"); - return nullptr; - case ZigClangAPValueAddrLabelDiff: - emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff"); - return nullptr; - case ZigClangAPValueIndeterminate: - emit_warning(c, source_loc, "unsupported initializer value kind: Indeterminate"); - return nullptr; - case ZigClangAPValueFixedPoint: - emit_warning(c, source_loc, "unsupported initializer value kind: FixedPoint"); - return nullptr; - } - zig_unreachable(); -} - -static void visit_var_decl(Context *c, const ZigClangVarDecl *var_decl) { - Buf *name = buf_create_from_str(ZigClangDecl_getName_bytes_begin((const ZigClangDecl *)var_decl)); - - switch (ZigClangVarDecl_getTLSKind(var_decl)) { - case ZigClangVarDecl_TLSKind_None: - break; - case ZigClangVarDecl_TLSKind_Static: - emit_warning(c, ZigClangVarDecl_getLocation(var_decl), - "ignoring variable '%s' - static thread local storage", buf_ptr(name)); - return; - case ZigClangVarDecl_TLSKind_Dynamic: - emit_warning(c, ZigClangVarDecl_getLocation(var_decl), - "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); - return; - } - - ZigClangQualType qt = ZigClangVarDecl_getType(var_decl); - AstNode *var_type = trans_qual_type(c, qt, ZigClangVarDecl_getLocation(var_decl)); - if (var_type == nullptr) { - emit_warning(c, ZigClangVarDecl_getLocation(var_decl), "ignoring variable '%s' - unresolved type", buf_ptr(name)); - return; - } - - bool is_extern = ZigClangVarDecl_hasExternalStorage(var_decl); - bool is_static = ZigClangVarDecl_isFileVarDecl(var_decl); - bool is_const = ZigClangQualType_isConstQualified(qt); - - if (is_static && !is_extern) { - AstNode *init_node; - if (ZigClangVarDecl_hasInit(var_decl)) { - const ZigClangAPValue *ap_value = ZigClangVarDecl_evaluateValue(var_decl); - if (ap_value == nullptr) { - emit_warning(c, ZigClangVarDecl_getLocation(var_decl), - "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); - return; - } - init_node = trans_ap_value(c, ap_value, qt, ZigClangVarDecl_getLocation(var_decl)); - if (init_node == nullptr) - return; - } else { - init_node = trans_create_node(c, NodeTypeUndefinedLiteral); - } - - AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); - add_top_level_decl(c, name, var_node); - return; - } - - if (is_extern) { - AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); - var_node->data.variable_declaration.is_extern = true; - add_top_level_decl(c, name, var_node); - return; - } - - emit_warning(c, ZigClangVarDecl_getLocation(var_decl), - "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); - return; -} - -static bool decl_visitor(void *context, const ZigClangDecl *decl) { - Context *c = (Context*)context; - - switch (ZigClangDecl_getKind(decl)) { - case ZigClangDeclFunction: - visit_fn_decl(c, reinterpret_cast(decl)); - break; - case ZigClangDeclTypedef: - resolve_typedef_decl(c, reinterpret_cast(decl)); - break; - case ZigClangDeclEnum: - resolve_enum_decl(c, reinterpret_cast(decl)); - break; - case ZigClangDeclRecord: - resolve_record_decl(c, reinterpret_cast(decl)); - break; - case ZigClangDeclVar: - visit_var_decl(c, reinterpret_cast(decl)); - break; - default: - emit_warning(c, ZigClangDecl_getLocation(decl), "ignoring %s decl", ZigClangDecl_getDeclKindName(decl)); - } - - return true; -} - -static bool name_exists_global(Context *c, Buf *name) { - return get_global(c, name) != nullptr; -} - -static bool name_exists_scope(Context *c, Buf *name, TransScope *scope) { - while (scope != nullptr) { - if (scope->id == TransScopeIdVar) { - TransScopeVar *var_scope = (TransScopeVar *)scope; - if (buf_eql_buf(name, var_scope->zig_name)) { - return true; - } - } - scope = scope->parent; - } - return name_exists_global(c, name); -} - -static Buf *get_unique_name(Context *c, Buf *name, TransScope *scope) { - Buf *proposed_name = name; - int count = 0; - while (name_exists_scope(c, proposed_name, scope)) { - if (proposed_name == name) { - proposed_name = buf_alloc(); - } - buf_resize(proposed_name, 0); - buf_appendf(proposed_name, "%s_%d", buf_ptr(name), count); - count += 1; - } - return proposed_name; -} - -static TransScopeRoot *trans_scope_root_create(Context *c) { - TransScopeRoot *result = allocate(1); - result->base.id = TransScopeIdRoot; - return result; -} - -static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope) { - TransScopeWhile *result = allocate(1); - result->base.id = TransScopeIdWhile; - result->base.parent = parent_scope; - result->node = trans_create_node(c, NodeTypeWhileExpr); - return result; -} - -static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope) { - TransScopeBlock *result = allocate(1); - result->base.id = TransScopeIdBlock; - result->base.parent = parent_scope; - result->node = trans_create_node(c, NodeTypeBlock); - return result; -} - -static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name) { - TransScopeVar *result = allocate(1); - result->base.id = TransScopeIdVar; - result->base.parent = parent_scope; - result->c_name = wanted_name; - result->zig_name = get_unique_name(c, wanted_name, parent_scope); - return result; -} - -static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) { - TransScopeSwitch *result = allocate(1); - result->base.id = TransScopeIdSwitch; - result->base.parent = parent_scope; - result->switch_node = trans_create_node(c, NodeTypeSwitchExpr); - return result; -} - -static TransScopeBlock *trans_scope_block_find(TransScope *scope) { - while (scope != nullptr) { - if (scope->id == TransScopeIdBlock) { - return (TransScopeBlock *)scope; - } - scope = scope->parent; - } - return nullptr; -} - -static void render_aliases(Context *c) { - for (size_t i = 0; i < c->aliases.length; i += 1) { - Alias *alias = &c->aliases.at(i); - if (name_exists_global(c, alias->new_name)) - continue; - - add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); - } -} - -static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node); - -static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) { - if (type_node == nullptr) { - return nullptr; - } else if (type_node->type == NodeTypeContainerDecl) { - return type_node; - } else if (type_node->type == NodeTypePrefixOpExpr) { - return type_node; - } else if (type_node->type == NodeTypeSymbol) { - AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol); - if (existing_node == nullptr) - return nullptr; - if (existing_node->type != NodeTypeVariableDeclaration) - return nullptr; - return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr); - } else if (type_node->type == NodeTypeFieldAccessExpr) { - AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr); - if (container_node == nullptr) - return nullptr; - if (container_node->type != NodeTypeContainerDecl) - return container_node; - - for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) { - AstNode *field_node = container_node->data.container_decl.fields.items[i]; - if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) { - return trans_lookup_ast_container(c, field_node->data.struct_field.type); - } - } - return nullptr; - } else { - return nullptr; - } -} - -static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) { - if (ref_node->type == NodeTypeSymbol) { - AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol); - if (existing_node == nullptr) - return nullptr; - if (existing_node->type != NodeTypeVariableDeclaration) - return nullptr; - return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type); - } else if (ref_node->type == NodeTypeFieldAccessExpr) { - AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr); - if (container_node == nullptr) - return nullptr; - if (container_node->type != NodeTypeContainerDecl) - return container_node; - for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) { - AstNode *field_node = container_node->data.container_decl.fields.items[i]; - if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) { - return trans_lookup_ast_container(c, field_node->data.struct_field.type); - } - } - return nullptr; - } else { - return nullptr; - } -} - -static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) { - AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node); - if (prefix_node == nullptr) - return nullptr; - if (prefix_node->type != NodeTypePrefixOpExpr) - return nullptr; - if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpOptional) - return nullptr; - - AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr; - if (fn_proto_node->type != NodeTypeFnProto) - return nullptr; - - return fn_proto_node; -} - -static void render_macros(Context *c) { - auto it = c->macro_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; - - AstNode *proto_node; - AstNode *value_node = entry->value; - if (value_node->type == NodeTypeFnDef) { - add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node); - } else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) { - // If a macro aliases a global variable which is a function pointer, we conclude that - // the macro is intended to represent a function that assumes the function pointer - // variable is non-null and calls it. - AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node); - add_top_level_decl(c, entry->key, inline_fn_node); - } else { - add_global_var(c, entry->key, value_node); - } - } -} - -static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i); -static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i); -static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i); - -static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { - CTok *tok = &ctok->tokens.at(*tok_i); - if (tok->id == CTokIdNumLitInt) { - *tok_i += 1; - switch (tok->data.num_lit_int.suffix) { - case CNumLitSuffixNone: - return trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); - case CNumLitSuffixL: - return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_long"); - case CNumLitSuffixU: - return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_uint"); - case CNumLitSuffixLU: - return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulong"); - case CNumLitSuffixLL: - return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_longlong"); - case CNumLitSuffixLLU: - return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulonglong"); - } - zig_unreachable(); - } else if (tok->id == CTokIdNumLitFloat) { - *tok_i += 1; - double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; - return trans_create_node_float_lit(c, value); - } - return nullptr; -} - -static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i) { - CTok *tok = &ctok->tokens.at(*tok_i); - switch (tok->id) { - case CTokIdCharLit: - *tok_i += 1; - return trans_create_node_unsigned(c, tok->data.char_lit); - case CTokIdStrLit: - *tok_i += 1; - return trans_create_node_str_lit(c, buf_create_from_buf(&tok->data.str_lit)); - case CTokIdMinus: - *tok_i += 1; - return parse_ctok_num_lit(c, ctok, tok_i, true); - case CTokIdNumLitInt: - case CTokIdNumLitFloat: - return parse_ctok_num_lit(c, ctok, tok_i, false); - case CTokIdSymbol: - { - *tok_i += 1; - Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); - return trans_create_node_symbol(c, symbol_name); - } - case CTokIdLParen: - { - *tok_i += 1; - AstNode *inner_node = parse_ctok_expr(c, ctok, tok_i); - if (inner_node == nullptr) { - return nullptr; - } - - CTok *next_tok = &ctok->tokens.at(*tok_i); - if (next_tok->id == CTokIdRParen) { - *tok_i += 1; - return inner_node; - } - - AstNode *node_to_cast = parse_ctok_expr(c, ctok, tok_i); - if (node_to_cast == nullptr) { - return nullptr; - } - - CTok *next_tok2 = &ctok->tokens.at(*tok_i); - if (next_tok2->id != CTokIdRParen) { - return nullptr; - } - *tok_i += 1; - - - //if (@typeId(@TypeOf(x)) == @import("builtin").TypeId.Pointer) - // @ptrCast(dest, x) - //else if (@typeId(@TypeOf(x)) == @import("builtin").TypeId.Integer) - // @intToPtr(dest, x) - //else - // (dest)(x) - - AstNode *import_builtin = trans_create_node_builtin_fn_call_str(c, "import"); - import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("builtin"))); - AstNode *typeid_type = trans_create_node_field_access_str(c, import_builtin, "TypeId"); - AstNode *typeid_pointer = trans_create_node_field_access_str(c, typeid_type, "Pointer"); - AstNode *typeid_integer = trans_create_node_field_access_str(c, typeid_type, "Int"); - AstNode *typeof_x = trans_create_node_builtin_fn_call_str(c, "TypeOf"); - typeof_x->data.fn_call_expr.params.append(node_to_cast); - AstNode *typeid_value = trans_create_node_builtin_fn_call_str(c, "typeId"); - typeid_value->data.fn_call_expr.params.append(typeof_x); - - AstNode *outer_if_cond = trans_create_node_bin_op(c, typeid_value, BinOpTypeCmpEq, typeid_pointer); - AstNode *inner_if_cond = trans_create_node_bin_op(c, typeid_value, BinOpTypeCmpEq, typeid_integer); - AstNode *inner_if_then = trans_create_node_builtin_fn_call_str(c, "intToPtr"); - inner_if_then->data.fn_call_expr.params.append(inner_node); - inner_if_then->data.fn_call_expr.params.append(node_to_cast); - AstNode *inner_if_else = trans_create_node_cast(c, inner_node, node_to_cast); - AstNode *inner_if = trans_create_node_if(c, inner_if_cond, inner_if_then, inner_if_else); - AstNode *outer_if_then = trans_create_node_builtin_fn_call_str(c, "ptrCast"); - outer_if_then->data.fn_call_expr.params.append(inner_node); - outer_if_then->data.fn_call_expr.params.append(node_to_cast); - return trans_create_node_if(c, outer_if_cond, outer_if_then, inner_if); - } - case CTokIdDot: - case CTokIdEOF: - case CTokIdRParen: - case CTokIdAsterisk: - case CTokIdBang: - case CTokIdTilde: - case CTokIdShl: - case CTokIdLt: - // not able to make sense of this - return nullptr; - } - zig_unreachable(); -} - -static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i) { - return parse_ctok_prefix_op_expr(c, ctok, tok_i); -} - -static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { - AstNode *node = parse_ctok_primary_expr(c, ctok, tok_i); - if (node == nullptr) - return nullptr; - - while (true) { - CTok *first_tok = &ctok->tokens.at(*tok_i); - if (first_tok->id == CTokIdDot) { - *tok_i += 1; - - CTok *name_tok = &ctok->tokens.at(*tok_i); - if (name_tok->id != CTokIdSymbol) { - return nullptr; - } - *tok_i += 1; - - node = trans_create_node_field_access(c, node, buf_create_from_buf(&name_tok->data.symbol)); - } else if (first_tok->id == CTokIdAsterisk) { - *tok_i += 1; - - node = trans_create_node_ptr_type(c, false, false, node, PtrLenC); - } else if (first_tok->id == CTokIdShl) { - *tok_i += 1; - - AstNode *rhs_node = parse_ctok_expr(c, ctok, tok_i); - if (rhs_node == nullptr) - return nullptr; - node = trans_create_node_bin_op(c, node, BinOpTypeBitShiftLeft, rhs_node); - } else { - return node; - } - } -} - -static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { - CTok *op_tok = &ctok->tokens.at(*tok_i); - - switch (op_tok->id) { - case CTokIdBang: - { - *tok_i += 1; - AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); - if (prefix_op_expr == nullptr) - return nullptr; - return trans_create_node_prefix_op(c, PrefixOpBoolNot, prefix_op_expr); - } - case CTokIdMinus: - { - *tok_i += 1; - AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); - if (prefix_op_expr == nullptr) - return nullptr; - return trans_create_node_prefix_op(c, PrefixOpNegation, prefix_op_expr); - } - case CTokIdTilde: - { - *tok_i += 1; - AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); - if (prefix_op_expr == nullptr) - return nullptr; - return trans_create_node_prefix_op(c, PrefixOpBinNot, prefix_op_expr); - } - case CTokIdAsterisk: - { - *tok_i += 1; - AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); - if (prefix_op_expr == nullptr) - return nullptr; - return trans_create_node_ptr_deref(c, prefix_op_expr); - } - default: - return parse_ctok_suffix_op_expr(c, ctok, tok_i); - } -} - -static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { - tokenize_c_macro(ctok, (const uint8_t *)char_ptr); - - if (ctok->error) { - return; - } - - size_t tok_i = 0; - CTok *name_tok = &ctok->tokens.at(tok_i); - assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); - tok_i += 1; - - AstNode *result_node = parse_ctok_suffix_op_expr(c, ctok, &tok_i); - if (result_node == nullptr) { - return; - } - CTok *eof_tok = &ctok->tokens.at(tok_i); - if (eof_tok->id != CTokIdEOF) { - return; - } - if (result_node->type == NodeTypeSymbol) { - // if it equals itself, ignore. for example, from stdio.h: - // #define stdin stdin - Buf *symbol_name = result_node->data.symbol_expr.symbol; - if (buf_eql_buf(name, symbol_name)) { - return; - } - } - c->macro_table.put(name, result_node); -} - -static void process_preprocessor_entities(Context *c, ZigClangASTUnit *unit) { - CTokenize ctok = {{0}}; - - // TODO if we see #undef, delete it from the table - for (ZigClangPreprocessingRecord_iterator it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit), - it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); it.I != it_end.I; it.I += 1) - { - ZigClangPreprocessedEntity *entity = ZigClangPreprocessingRecord_iterator_deref(it); - - switch (ZigClangPreprocessedEntity_getKind(entity)) { - case ZigClangPreprocessedEntity_InvalidKind: - case ZigClangPreprocessedEntity_InclusionDirectiveKind: - case ZigClangPreprocessedEntity_MacroExpansionKind: - continue; - case ZigClangPreprocessedEntity_MacroDefinitionKind: - { - ZigClangMacroDefinitionRecord *macro = reinterpret_cast(entity); - const char *raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro); - ZigClangSourceLocation begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); - ZigClangSourceLocation end_loc = ZigClangMacroDefinitionRecord_getSourceRange_getEnd(macro); - - if (ZigClangSourceLocation_eq(begin_loc, end_loc)) { - // this means it is a macro without a value - // we don't care about such things - continue; - } - Buf *name = buf_create_from_str(raw_name); - if (name_exists_global(c, name)) { - continue; - } - - const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, begin_loc); - process_macro(c, &ctok, name, begin_c); - } - } - } -} - -Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, - Stage2ErrorMsg **errors_ptr, size_t *errors_len, - const char **args_begin, const char **args_end, - TranslateMode mode, const char *resources_path) -{ - Context context = {0}; - Context *c = &context; - c->warnings_on = codegen->verbose_cimport; - if (mode == TranslateModeImport) { - c->want_export = false; - } else { - c->want_export = true; - } - c->decl_table.init(8); - c->macro_table.init(8); - c->global_table.init(8); - c->ptr_params.init(8); - c->codegen = codegen; - c->global_scope = trans_scope_root_create(c); - - ZigClangASTUnit *ast_unit = ZigClangLoadFromCommandLine(args_begin, args_end, errors_ptr, errors_len, - resources_path); - if (ast_unit == nullptr) { - if (*errors_len == 0) return ErrorNoMem; - return ErrorCCompileErrors; - } - - c->ctx = ZigClangASTUnit_getASTContext(ast_unit); - c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit); - c->root = trans_create_node(c, NodeTypeContainerDecl); - c->root->data.container_decl.is_root = true; - - ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, decl_visitor); - - process_preprocessor_entities(c, ast_unit); - - render_macros(c); - render_aliases(c); - - *out_root_node = c->root; - - ZigClangASTUnit_delete(ast_unit); - - return ErrorNone; -} diff --git a/src/translate_c.hpp b/src/translate_c.hpp deleted file mode 100644 index 6e308dcf04b9..000000000000 --- a/src/translate_c.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - - -#ifndef ZIG_PARSEC_HPP -#define ZIG_PARSEC_HPP - -#include "all_types.hpp" - -enum TranslateMode { - TranslateModeImport, - TranslateModeTranslate, -}; - -Error parse_h_file(CodeGen *codegen, AstNode **out_root_node, - Stage2ErrorMsg **errors_ptr, size_t *errors_len, - const char **args_begin, const char **args_end, - TranslateMode mode, const char *resources_path); - -#endif diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index f1e79ab34fe8..ba25d365f7cb 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -1686,6 +1686,16 @@ const struct ZigClangStmt *ZigClangFunctionDecl_getBody(const struct ZigClangFun return reinterpret_cast(stmt); } +bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast(self); + return casted->doesDeclarationForceExternallyVisibleDefinition(); +} + +bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *self) { + auto casted = reinterpret_cast(self); + return casted->isInlineSpecified(); +} + const ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const ZigClangTypedefType *self) { auto casted = reinterpret_cast(self); const clang::TypedefNameDecl *name_decl = casted->getDecl(); diff --git a/src/zig_clang.h b/src/zig_clang.h index ce71612468ad..734eea48b589 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -873,6 +873,8 @@ ZIG_EXTERN_C bool ZigClangFunctionDecl_hasBody(const struct ZigClangFunctionDecl ZIG_EXTERN_C enum ZigClangStorageClass ZigClangFunctionDecl_getStorageClass(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C const struct ZigClangParmVarDecl *ZigClangFunctionDecl_getParamDecl(const struct ZigClangFunctionDecl *, unsigned i); ZIG_EXTERN_C const struct ZigClangStmt *ZigClangFunctionDecl_getBody(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C bool ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(const struct ZigClangFunctionDecl *); +ZIG_EXTERN_C bool ZigClangFunctionDecl_isInlineSpecified(const struct ZigClangFunctionDecl *); ZIG_EXTERN_C bool ZigClangRecordDecl_isUnion(const struct ZigClangRecordDecl *record_decl); ZIG_EXTERN_C bool ZigClangRecordDecl_isStruct(const struct ZigClangRecordDecl *record_decl); diff --git a/test/compare_output.zig b/test/compare_output.zig index b13c6cf530b2..db20709afa21 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -5,7 +5,11 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { cases.addC("hello world with libc", - \\const c = @cImport(@cInclude("stdio.h")); + \\const c = @cImport({ + \\ // See https://github.com/ziglang/zig/issues/515 + \\ @cDefine("_NO_CRT_STDIO_INLINE", "1"); + \\ @cInclude("stdio.h"); + \\}); \\pub export fn main(argc: c_int, argv: [*][*]u8) c_int { \\ _ = c.puts("Hello, world!"); \\ return 0; diff --git a/test/tests.zig b/test/tests.zig index f8d9df990fb3..5d173c44f56f 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1422,7 +1422,6 @@ pub const TranslateCContext = struct { sources: ArrayList(SourceFile), expected_lines: ArrayList([]const u8), allow_warnings: bool, - stage2: bool, const SourceFile = struct { filename: []const u8, @@ -1475,7 +1474,7 @@ pub const TranslateCContext = struct { var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; - const translate_c_cmd = if (self.case.stage2) "translate-c-2" else "translate-c"; + const translate_c_cmd = "translate-c"; zig_args.append(translate_c_cmd) catch unreachable; zig_args.append(b.pathFromRoot(root_src)) catch unreachable; @@ -1583,7 +1582,6 @@ pub const TranslateCContext = struct { .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), .expected_lines = ArrayList([]const u8).init(self.b.allocator), .allow_warnings = allow_warnings, - .stage2 = false, }; tc.addSourceFile(filename, source); @@ -1604,53 +1602,6 @@ pub const TranslateCContext = struct { self.addCase(tc); } - pub fn addC( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - const tc = self.create(false, "source.c", name, source, expected_lines); - self.addCase(tc); - } - - pub fn add_both( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - for ([_]bool{ false, true }) |stage2| { - const tc = self.create(false, "source.h", name, source, expected_lines); - tc.stage2 = stage2; - self.addCase(tc); - } - } - - pub fn addC_both( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - for ([_]bool{ false, true }) |stage2| { - const tc = self.create(false, "source.c", name, source, expected_lines); - tc.stage2 = stage2; - self.addCase(tc); - } - } - - pub fn add_2( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - const tc = self.create(false, "source.h", name, source, expected_lines); - tc.stage2 = true; - self.addCase(tc); - } - pub fn addAllowWarnings( self: *TranslateCContext, name: []const u8, @@ -1664,7 +1615,7 @@ pub const TranslateCContext = struct { pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { const b = self.b; - const translate_c_cmd = if (case.stage2) "translate-c-2" else "translate-c"; + const translate_c_cmd = "translate-c"; const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {}", .{ translate_c_cmd, case.name }) catch unreachable; if (self.test_filter) |filter| { if (mem.indexOf(u8, annotated_case_name, filter) == null) return; diff --git a/test/translate_c.zig b/test/translate_c.zig index 9994e23d4ca5..5de9abcbe79d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1,15 +1,9 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); -// add_both - test for stage1 and stage2, in #include mode -// add - test stage1 only, in #include mode -// add_2 - test stage2 only -// addC_both - test for stage1 and stage2, in -c mode -// addC - test stage1 only, in -c mode - pub fn addCases(cases: *tests.TranslateCContext) void { /////////////// Cases that pass for both stage1/stage2 //////////////// - cases.add_both("simple function prototypes", + cases.add("simple function prototypes", \\void __attribute__((noreturn)) foo(void); \\int bar(void); , &[_][]const u8{ @@ -17,23 +11,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn bar() c_int; }); - cases.addC_both("simple var decls", + cases.add("simple var decls", \\void foo(void) { \\ int a; \\ char b = 123; \\ const int c; \\ const unsigned d = 440; + \\ int e = 10; + \\ unsigned int f = 10u; \\} , &[_][]const u8{ \\pub export fn foo() void { \\ var a: c_int = undefined; - \\ var b: u8 = @as(u8, 123); + \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123))); \\ const c: c_int = undefined; - \\ const d: c_uint = @as(c_uint, 440); + \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440)); + \\ var e: c_int = 10; + \\ var f: c_uint = 10; \\} }); - cases.addC_both("ignore result, explicit function arguments", + cases.add("ignore result, explicit function arguments", \\void foo(void) { \\ int a; \\ 1; @@ -45,15 +43,25 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var a: c_int = undefined; - \\ _ = 1; + \\ _ = @as(c_int, 1); \\ _ = "hey"; - \\ _ = (1 + 1); - \\ _ = (1 - 1); + \\ _ = (@as(c_int, 1) + @as(c_int, 1)); + \\ _ = (@as(c_int, 1) - @as(c_int, 1)); \\ a = 1; \\} }); - cases.addC_both("variables", + cases.add("function with no prototype", + \\int foo() { + \\ return 5; + \\} + , &[_][]const u8{ + \\pub export fn foo() c_int { + \\ return 5; + \\} + }); + + cases.add("variables", \\extern int extern_var; \\static const int int_var = 13; , &[_][]const u8{ @@ -62,13 +70,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const int_var: c_int = 13; }); - cases.add_both("const ptr initializer", + cases.add("const ptr initializer", \\static const char *v0 = "0.0.0"; , &[_][]const u8{ \\pub var v0: [*c]const u8 = "0.0.0"; }); - cases.addC_both("static incomplete array inside function", + cases.add("static incomplete array inside function", \\void foo(void) { \\ static const char v2[] = "2.2.2"; \\} @@ -78,7 +86,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("simple function definition", + cases.add("simple function definition", \\void foo(void) {} \\static void bar(void) {} , &[_][]const u8{ @@ -86,7 +94,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn bar() void {} }); - cases.add_both("typedef void", + cases.add("typedef void", \\typedef void Foo; \\Foo fun(Foo *a); , &[_][]const u8{ @@ -95,7 +103,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn fun(a: ?*Foo) Foo; }); - cases.add_both("duplicate typedef", + cases.add("duplicate typedef", \\typedef long foo; \\typedef int bar; \\typedef long foo; @@ -106,7 +114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const baz = c_int; }); - cases.addC_both("casting pointers to ints and ints to pointers", + cases.add("casting pointers to ints and ints to pointers", \\void foo(void); \\void bar(void) { \\ void *func_ptr = foo; @@ -116,17 +124,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn foo() void; \\pub export fn bar() void { \\ var func_ptr: ?*c_void = @ptrCast(?*c_void, foo); - \\ var typed_func_ptr: ?extern fn () void = @intToPtr(?extern fn () void, @as(c_ulong, @ptrToInt(func_ptr))); + \\ var typed_func_ptr: ?extern fn () void = @intToPtr(?extern fn () void, @intCast(c_ulong, @ptrToInt(func_ptr))); \\} }); - cases.add_both("noreturn attribute", + cases.add("noreturn attribute", \\void foo(void) __attribute__((noreturn)); , &[_][]const u8{ \\pub extern fn foo() noreturn; }); - cases.addC_both("add, sub, mul, div, rem", + cases.add("add, sub, mul, div, rem", \\int s() { \\ int a, b, c; \\ c = a + b; @@ -166,7 +174,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_both("typedef of function in struct field", + cases.add("typedef of function in struct field", \\typedef void lws_callback_function(void); \\struct Foo { \\ void (*func)(void); @@ -180,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add_both("pointer to struct demoted to opaque due to bit fields", + cases.add("pointer to struct demoted to opaque due to bit fields", \\struct Foo { \\ unsigned int: 1; \\}; @@ -195,13 +203,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add_both("macro with left shift", + cases.add("macro with left shift", \\#define REDISMODULE_READ (1<<0) , &[_][]const u8{ \\pub const REDISMODULE_READ = 1 << 0; }); - cases.add_both("double define struct", + cases.add("macro with right shift", + \\#define FLASH_SIZE 0x200000UL /* 2 MB */ + \\#define FLASH_BANK_SIZE (FLASH_SIZE >> 1) /* 1 MB */ + , &[_][]const u8{ + \\pub const FLASH_SIZE = @as(c_ulong, 0x200000); + , + \\pub const FLASH_BANK_SIZE = FLASH_SIZE >> 1; + }); + + cases.add("double define struct", \\typedef struct Bar Bar; \\typedef struct Foo Foo; \\ @@ -226,7 +243,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Bar = struct_Bar; }); - cases.add_both("simple struct", + cases.add("simple struct", \\struct Foo { \\ int x; \\ char *y; @@ -240,7 +257,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - cases.add_both("self referential struct with function pointer", + cases.add("self referential struct with function pointer", \\struct Foo { \\ void (*derp)(struct Foo *foo); \\}; @@ -252,7 +269,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - cases.add_both("struct prototype used in func", + cases.add("struct prototype used in func", \\struct Foo; \\struct Foo *some_func(struct Foo *foo, int x); , &[_][]const u8{ @@ -263,13 +280,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - cases.add_both("#define an unsigned integer literal", + cases.add("#define an unsigned integer literal", \\#define CHANNEL_COUNT 24 , &[_][]const u8{ \\pub const CHANNEL_COUNT = 24; }); - cases.add_both("#define referencing another #define", + cases.add("#define referencing another #define", \\#define THING2 THING1 \\#define THING1 1234 , &[_][]const u8{ @@ -278,7 +295,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const THING2 = THING1; }); - cases.add_both("circular struct definitions", + cases.add("circular struct definitions", \\struct Bar; \\ \\struct Foo { @@ -298,13 +315,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add_both("#define string", + cases.add("#define string", \\#define foo "a string" , &[_][]const u8{ \\pub const foo = "a string"; }); - cases.add_both("zig keywords in C code", + cases.add("zig keywords in C code", \\struct comptime { \\ int defer; \\}; @@ -316,13 +333,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const @"comptime" = struct_comptime; }); - cases.add_both("macro with parens around negative number", + cases.add("macro with parens around negative number", \\#define LUA_GLOBALSINDEX (-10002) , &[_][]const u8{ \\pub const LUA_GLOBALSINDEX = -10002; }); - cases.add_both( + cases.add( "u integer suffix after 0 (zero) in macro definition", "#define ZERO 0U", &[_][]const u8{ @@ -330,7 +347,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "l integer suffix after 0 (zero) in macro definition", "#define ZERO 0L", &[_][]const u8{ @@ -338,7 +355,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "ul integer suffix after 0 (zero) in macro definition", "#define ZERO 0UL", &[_][]const u8{ @@ -346,7 +363,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "lu integer suffix after 0 (zero) in macro definition", "#define ZERO 0LU", &[_][]const u8{ @@ -354,7 +371,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "ll integer suffix after 0 (zero) in macro definition", "#define ZERO 0LL", &[_][]const u8{ @@ -362,7 +379,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "ull integer suffix after 0 (zero) in macro definition", "#define ZERO 0ULL", &[_][]const u8{ @@ -370,7 +387,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "llu integer suffix after 0 (zero) in macro definition", "#define ZERO 0LLU", &[_][]const u8{ @@ -378,7 +395,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.add_both( + cases.add( "bitwise not on u-suffixed 0 (zero) in macro definition", "#define NOT_ZERO (~0U)", &[_][]const u8{ @@ -386,7 +403,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }, ); - cases.addC_both("null statements", + cases.add("null statements", \\void foo(void) { \\ ;;;;; \\} @@ -402,7 +419,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { if (builtin.os != builtin.Os.windows) { // Windows treats this as an enum with type c_int - cases.add_both("big negative enum init values when C ABI supports long long enums", + cases.add("big negative enum init values when C ABI supports long long enums", \\enum EnumWithInits { \\ VAL01 = 0, \\ VAL02 = 1, @@ -457,7 +474,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { }); } - cases.addC_both("predefined expressions", + cases.add("predefined expressions", \\void foo(void) { \\ __func__; \\ __FUNCTION__; @@ -471,39 +488,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("ignore result, no function arguments", - \\void foo() { - \\ int a; - \\ 1; - \\ "hey"; - \\ 1 + 1; - \\ 1 - 1; - \\ a = 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = undefined; - \\ _ = 1; - \\ _ = "hey"; - \\ _ = (1 + 1); - \\ _ = (1 - 1); - \\ a = 1; - \\} - }); - - cases.add_both("constant size array", + cases.add("constant size array", \\void func(int array[20]); , &[_][]const u8{ \\pub extern fn func(array: [*c]c_int) void; }); - cases.add_both("__cdecl doesn't mess up function pointers", + cases.add("__cdecl doesn't mess up function pointers", \\void foo(void (__cdecl *fn_ptr)(void)); , &[_][]const u8{ \\pub extern fn foo(fn_ptr: ?extern fn () void) void; }); - cases.addC_both("void cast", + cases.add("void cast", \\void foo() { \\ int a; \\ (void) a; @@ -515,7 +512,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("implicit cast to void *", + cases.add("implicit cast to void *", \\void *foo() { \\ unsigned short *x; \\ return x; @@ -527,7 +524,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("null pointer implicit cast", + cases.add("null pointer implicit cast", \\int* foo(void) { \\ return 0; \\} @@ -537,7 +534,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_both("simple union", + cases.add("simple union", \\union Foo { \\ int x; \\ double y; @@ -551,7 +548,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = union_Foo; }); - cases.addC_both("string literal", + cases.add("string literal", \\const char *foo(void) { \\ return "bar"; \\} @@ -561,7 +558,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("return void", + cases.add("return void", \\void foo(void) { \\ return; \\} @@ -571,7 +568,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("for loop", + cases.add("for loop", \\void foo(void) { \\ for (int i = 0; i; i = i + 1) { } \\} @@ -579,12 +576,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn foo() void { \\ { \\ var i: c_int = 0; - \\ while (i != 0) : (i = (i + 1)) {} + \\ while (i != 0) : (i = (i + @as(c_int, 1))) {} \\ } \\} }); - cases.addC_both("empty for loop", + cases.add("empty for loop", \\void foo(void) { \\ for (;;) { } \\} @@ -594,7 +591,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("break statement", + cases.add("break statement", \\void foo(void) { \\ for (;;) { \\ break; @@ -608,7 +605,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("continue statement", + cases.add("continue statement", \\void foo(void) { \\ for (;;) { \\ continue; @@ -622,7 +619,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("pointer casting", + cases.add("pointer casting", \\float *ptrcast() { \\ int *a; \\ return (float *)a; @@ -634,7 +631,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("pointer conversion with different alignment", + cases.add("pointer conversion with different alignment", \\void test_ptr_cast() { \\ void *p; \\ { @@ -668,7 +665,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("while on non-bool", + cases.add("while on non-bool", \\int while_none_bool() { \\ int a; \\ float b; @@ -690,7 +687,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("for on non-bool", + cases.add("for on non-bool", \\int for_none_bool() { \\ int a; \\ float b; @@ -712,17 +709,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("bitshift", + cases.add("bitshift", \\int foo(void) { \\ return (1 << 2) >> 1; \\} , &[_][]const u8{ \\pub export fn foo() c_int { - \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1); + \\ return (@as(c_int, 1) << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1); \\} }); - cases.addC_both("sizeof", + cases.add("sizeof", \\#include \\size_t size_of(void) { \\ return sizeof(int); @@ -733,7 +730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("normal deref", + cases.add("normal deref", \\void foo() { \\ int *x; \\ *x = 1; @@ -745,7 +742,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("address of operator", + cases.add("address of operator", \\int foo(void) { \\ int x = 1234; \\ int *ptr = &x; @@ -759,7 +756,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("bin not", + cases.add("bin not", \\int foo() { \\ int x; \\ return ~x; @@ -771,7 +768,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC_both("bool not", + cases.add("bool not", \\int foo() { \\ int a; \\ float b; @@ -786,14 +783,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ var a: c_int = undefined; \\ var b: f32 = undefined; \\ var c: ?*c_void = undefined; - \\ return !(a == 0); + \\ return !(a == @as(c_int, 0)); \\ return !(a != 0); \\ return !(b != 0); \\ return !(c != null); \\} }); - cases.addC("__extension__ cast", + cases.add("__extension__ cast", \\int foo(void) { \\ return __extension__ 1; \\} @@ -805,16 +802,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { if (builtin.os != builtin.Os.windows) { // sysv_abi not currently supported on windows - cases.add_both("Macro qualified functions", + cases.add("Macro qualified functions", \\void __attribute__((sysv_abi)) foo(void); , &[_][]const u8{ \\pub extern fn foo() void; }); } - /////////////// Cases that pass for only stage2 //////////////// - - cases.add_2("Forward-declared enum", + cases.add("Forward-declared enum", \\extern enum enum_ty my_enum; \\enum enum_ty { FOO }; , &[_][]const u8{ @@ -825,7 +820,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern var my_enum: enum_enum_ty; }); - cases.add_2("Parameterless function pointers", + cases.add("Parameterless function pointers", \\typedef void (*fn0)(); \\typedef void (*fn1)(char); , &[_][]const u8{ @@ -833,7 +828,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const fn1 = ?extern fn (u8) void; }); - cases.add_2("Parameterless function prototypes", + cases.add("Parameterless function prototypes", \\void a() {} \\void b(void) {} \\void c(); @@ -845,7 +840,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn d() void; }); - cases.add_2("variable declarations", + cases.add("variable declarations", \\extern char arr0[] = "hello"; \\static char arr1[] = "hello"; \\char arr2[] = "hello"; @@ -855,7 +850,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export var arr2: [*c]u8 = "hello"; }); - cases.add_2("array initializer expr", + cases.add("array initializer expr", \\static void foo(void){ \\ char arr[10] ={1}; \\ char *arr1[10] ={0}; @@ -863,7 +858,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub fn foo() void { \\ var arr: [10]u8 = .{ - \\ @as(u8, 1), + \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))), \\ } ++ .{0} ** 9; \\ var arr1: [10][*c]u8 = .{ \\ null, @@ -871,7 +866,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("enums", + cases.add("enums", \\typedef enum { \\ a, \\ b, @@ -938,61 +933,61 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Baz = struct_Baz; }); - cases.add_2("#define a char literal", + cases.add("#define a char literal", \\#define A_CHAR 'a' , &[_][]const u8{ \\pub const A_CHAR = 'a'; }); - cases.add_2("comment after integer literal", + cases.add("comment after integer literal", \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = 0x00000020; }); - cases.add_2("u integer suffix after hex literal", + cases.add("u integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); }); - cases.add_2("l integer suffix after hex literal", + cases.add("l integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); }); - cases.add_2("ul integer suffix after hex literal", + cases.add("ul integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); }); - cases.add_2("lu integer suffix after hex literal", + cases.add("lu integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); }); - cases.add_2("ll integer suffix after hex literal", + cases.add("ll integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); }); - cases.add_2("ull integer suffix after hex literal", + cases.add("ull integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); }); - cases.add_2("llu integer suffix after hex literal", + cases.add("llu integer suffix after hex literal", \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); }); - cases.add_2("generate inline func for #define global extern fn", + cases.add("generate inline func for #define global extern fn", \\extern void (*fn_ptr)(void); \\#define foo fn_ptr \\ @@ -1012,7 +1007,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("macros with field targets", + cases.add("macros with field targets", \\typedef unsigned int GLbitfield; \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); \\typedef void(*OpenGLProc)(void); @@ -1047,13 +1042,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const OpenGLProcs = union_OpenGLProcs; }); - cases.add_2("macro pointer cast", + cases.add("macro pointer cast", \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) , &[_][]const u8{ \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); }); - cases.add_2("basic macro function", + cases.add("basic macro function", \\extern int c; \\#define BASIC(c) (c*2) , &[_][]const u8{ @@ -1064,7 +1059,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("macro defines string literal with hex", + cases.add("macro defines string literal with hex", \\#define FOO "aoeu\xab derp" \\#define FOO2 "aoeu\x0007a derp" \\#define FOO_CHAR '\xfF' @@ -1076,7 +1071,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const FOO_CHAR = '\xff'; }); - cases.add_2("variable aliasing", + cases.add("macro add", + \\#define PERIPH_BASE (0x40000000UL) /*!< Base address of : AHB/APB Peripherals */ + \\#define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000UL) + \\#define RCC_BASE (D3_AHB1PERIPH_BASE + 0x4400UL) + , &[_][]const u8{ + \\pub const PERIPH_BASE = @as(c_ulong, 0x40000000); + , + \\pub const D3_APB1PERIPH_BASE = PERIPH_BASE + @as(c_ulong, 0x18000000); + , + \\pub const RCC_BASE = D3_AHB1PERIPH_BASE + @as(c_ulong, 0x4400); + }); + + cases.add("variable aliasing", \\static long a = 2; \\static long b = 2; \\static int c = 4; @@ -1090,81 +1097,55 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ unsigned d = 440; \\} , &[_][]const u8{ - \\pub var a: c_long = @as(c_long, 2); - \\pub var b: c_long = @as(c_long, 2); + \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2))); + \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2))); \\pub var c: c_int = 4; - \\pub export fn foo(_arg_c_1: u8) void { - \\ var c_1 = _arg_c_1; + \\pub export fn foo(arg_c_1: u8) void { + \\ var c_1 = arg_c_1; \\ var a_2: c_int = undefined; - \\ var b_3: u8 = @as(u8, 123); - \\ b_3 = @as(u8, a_2); + \\ var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123))); + \\ b_3 = @bitCast(u8, @truncate(i8, a_2)); \\ { \\ var d: c_int = 5; \\ } - \\ var d: c_uint = @as(c_uint, 440); + \\ var d: c_uint = @bitCast(c_uint, @as(c_int, 440)); \\} }); - cases.add_2("comma operator", - \\int foo(char c) { + cases.add("comma operator", + \\int foo() { \\ 2, 4; \\ return 2, 4, 6; \\} , &[_][]const u8{ - \\pub export fn foo(_arg_c: u8) c_int { - \\ var c = _arg_c; - \\ _ = 2; - \\ _ = 4; - \\ _ = 2; - \\ _ = 4; - \\ return 6; + \\pub export fn foo() c_int { + \\ _ = @as(c_int, 2); + \\ _ = @as(c_int, 4); + \\ _ = @as(c_int, 2); + \\ _ = @as(c_int, 4); + \\ return @as(c_int, 6); \\} }); - cases.add_2("wors-case assign", - \\int foo(char c) { + cases.add("worst-case assign", + \\int foo() { \\ int a; \\ int b; \\ a = b = 2; \\} , &[_][]const u8{ - \\pub export fn foo(_arg_c: u8) c_int { - \\ var c = _arg_c; + \\pub export fn foo() c_int { \\ var a: c_int = undefined; \\ var b: c_int = undefined; \\ a = blk: { - \\ const _tmp_1 = 2; - \\ b = _tmp_1; - \\ break :blk _tmp_1; + \\ const tmp = @as(c_int, 2); + \\ b = tmp; + \\ break :blk tmp; \\ }; \\} }); - cases.add_2("if statements", - \\int foo(char c) { - \\ if (2) { - \\ int a = 2; - \\ } - \\ if (2, 5) { - \\ int a = 2; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn foo(_arg_c: u8) c_int { - \\ var c = _arg_c; - \\ if (2 != 0) { - \\ var a: c_int = 2; - \\ } - \\ if ((blk: { - \\ _ = 2; - \\ break :blk 5; - \\ }) != 0) { - \\ var a: c_int = 2; - \\ } - \\} - }); - - cases.add_2("while loops", + cases.add("while loops", \\int foo() { \\ int a = 5; \\ while (2) @@ -1185,26 +1166,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() c_int { \\ var a: c_int = 5; - \\ while (2 != 0) a = 2; - \\ while (4 != 0) { - \\ var a: c_int = 4; - \\ a = 9; - \\ _ = 6; - \\ return a; + \\ while (@as(c_int, 2) != 0) a = 2; + \\ while (@as(c_int, 4) != 0) { + \\ var a_1: c_int = 4; + \\ a_1 = 9; + \\ _ = @as(c_int, 6); + \\ return a_1; \\ } \\ while (true) { - \\ var a: c_int = 2; - \\ a = 12; - \\ if (!(4 != 0)) break; + \\ var a_1: c_int = 2; + \\ a_1 = 12; + \\ if (!(@as(c_int, 4) != 0)) break; \\ } \\ while (true) { \\ a = 7; - \\ if (!(4 != 0)) break; + \\ if (!(@as(c_int, 4) != 0)) break; \\ } \\} }); - cases.add_2("for loops", + cases.add("for loops", \\int foo() { \\ for (int i = 2, b = 4; i + 2; i = 2) { \\ int a = 2; @@ -1217,24 +1198,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ { \\ var i: c_int = 2; \\ var b: c_int = 4; - \\ while ((i + 2) != 0) : (i = 2) { + \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) { \\ var a: c_int = 2; \\ a = 6; - \\ _ = 5; - \\ _ = 7; + \\ _ = @as(c_int, 5); + \\ _ = @as(c_int, 7); \\ } \\ } - \\ var i: u8 = @as(u8, 2); + \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2))); \\} }); - cases.add_2("shadowing primitive types", + cases.add("shadowing primitive types", \\unsigned anyerror = 2; , &[_][]const u8{ - \\pub export var _anyerror: c_uint = @as(c_uint, 2); + \\pub export var _anyerror: c_uint = @bitCast(c_uint, @as(c_int, 2)); }); - cases.add_2("floats", + cases.add("floats", \\float a = 3.1415; \\double b = 3.1415; \\int c = 3.1415; @@ -1243,22 +1224,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export var a: f32 = @floatCast(f32, 3.1415); \\pub export var b: f64 = 3.1415; \\pub export var c: c_int = @floatToInt(c_int, 3.1415); - \\pub export var d: f64 = @intToFloat(f64, 3); + \\pub export var d: f64 = @intToFloat(f64, @as(c_int, 3)); }); - cases.add_2("conditional operator", + cases.add("conditional operator", \\int bar(void) { \\ if (2 ? 5 : 5 ? 4 : 6) 2; \\ return 2 ? 5 : 5 ? 4 : 6; \\} , &[_][]const u8{ \\pub export fn bar() c_int { - \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2; - \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6; + \\ if ((if (@as(c_int, 2) != 0) @as(c_int, 5) else (if (@as(c_int, 5) != 0) @as(c_int, 4) else @as(c_int, 6))) != 0) _ = @as(c_int, 2); + \\ return if (@as(c_int, 2) != 0) @as(c_int, 5) else if (@as(c_int, 5) != 0) @as(c_int, 4) else @as(c_int, 6); \\} }); - cases.add_2("switch on int", + cases.add("switch on int", \\int switch_fn(int i) { \\ int res = 0; \\ switch (i) { @@ -1274,8 +1255,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ } \\} , &[_][]const u8{ - \\pub export fn switch_fn(_arg_i: c_int) c_int { - \\ var i = _arg_i; + \\pub export fn switch_fn(arg_i: c_int) c_int { + \\ var i = arg_i; \\ var res: c_int = 0; \\ __switch: { \\ __case_2: { @@ -1293,7 +1274,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ } \\ res = 2; \\ } - \\ res = (3 * i); + \\ res = (@as(c_int, 3) * i); \\ break :__switch; \\ } \\ res = 5; @@ -1301,7 +1282,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("type referenced struct", + cases.add("type referenced struct", \\struct Foo { \\ struct Bar{ \\ int b; @@ -1317,52 +1298,52 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add_2("undefined array global", + cases.add("undefined array global", \\int array[100] = {}; , &[_][]const u8{ \\pub export var array: [100]c_int = .{0} ** 100; }); - cases.add_2("restrict -> noalias", + cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , &[_][]const u8{ \\pub extern fn foo(noalias bar: ?*c_void, noalias ?*c_void) void; }); - cases.add_2("assign", + cases.add("assign", \\int max(int a) { \\ int tmp; \\ tmp = a; \\ a = tmp; \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int) c_int { - \\ var a = _arg_a; + \\pub export fn max(arg_a: c_int) c_int { + \\ var a = arg_a; \\ var tmp: c_int = undefined; \\ tmp = a; \\ a = tmp; \\} }); - cases.add_2("chaining assign", + cases.add("chaining assign", \\void max(int a) { \\ int b, c; \\ c = b = a; \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int) void { - \\ var a = _arg_a; + \\pub export fn max(arg_a: c_int) void { + \\ var a = arg_a; \\ var b: c_int = undefined; \\ var c: c_int = undefined; \\ c = blk: { - \\ const _tmp_1 = a; - \\ b = _tmp_1; - \\ break :blk _tmp_1; + \\ const tmp = a; + \\ b = tmp; + \\ break :blk tmp; \\ }; \\} }); - cases.add_2("anonymous enum", + cases.add("anonymous enum", \\enum { \\ One, \\ Two, @@ -1376,18 +1357,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add_2("c style cast", + cases.add("c style cast", \\int float_to_int(float a) { \\ return (int)a; \\} , &[_][]const u8{ - \\pub export fn float_to_int(_arg_a: f32) c_int { - \\ var a = _arg_a; + \\pub export fn float_to_int(arg_a: f32) c_int { + \\ var a = arg_a; \\ return @floatToInt(c_int, a); \\} }); - cases.add_2("escape sequences", + // TODO translate-c should in theory be able to figure out to drop all these casts + cases.add("escape sequences", \\const char *escapes() { \\char a = '\'', \\ b = '\\', @@ -1405,22 +1387,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ , &[_][]const u8{ \\pub export fn escapes() [*c]const u8 { - \\ var a: u8 = @as(u8, '\''); - \\ var b: u8 = @as(u8, '\\'); - \\ var c: u8 = @as(u8, '\x07'); - \\ var d: u8 = @as(u8, '\x08'); - \\ var e: u8 = @as(u8, '\x0c'); - \\ var f: u8 = @as(u8, '\n'); - \\ var g: u8 = @as(u8, '\r'); - \\ var h: u8 = @as(u8, '\t'); - \\ var i: u8 = @as(u8, '\x0b'); - \\ var j: u8 = @as(u8, '\x00'); - \\ var k: u8 = @as(u8, '\"'); + \\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\''))); + \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\'))); + \\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07'))); + \\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08'))); + \\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c'))); + \\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n'))); + \\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r'))); + \\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t'))); + \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b'))); + \\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00'))); + \\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"'))); \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; \\} }); - cases.add_2("do loop", + cases.add("do loop", \\void foo(void) { \\ int a = 2; \\ do { @@ -1436,18 +1418,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn foo() void { \\ var a: c_int = 2; \\ while (true) { - \\ a = (a - 1); + \\ a = (a - @as(c_int, 1)); \\ if (!(a != 0)) break; \\ } \\ var b: c_int = 2; \\ while (true) { - \\ b = (b - 1); + \\ b = (b - @as(c_int, 1)); \\ if (!(b != 0)) break; \\ } \\} }); - cases.add_2("logical and, logical or, on non-bool values, extra parens", + cases.add("logical and, logical or, on non-bool values, extra parens", \\enum Foo { \\ FooA, \\ FooB, @@ -1477,10 +1459,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ C, \\}; \\pub const SomeTypedef = c_int; - \\pub export fn and_or_non_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; - \\ var c = _arg_c; + \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int { + \\ var a = arg_a; + \\ var b = arg_b; + \\ var c = arg_c; \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA); \\ var e: c_int = @boolToInt(((a != 0) and (b != 0))); \\ var f: c_int = @boolToInt(((b != 0) and (c != null))); @@ -1500,7 +1482,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = enum_Foo; }); - cases.add_2("qualified struct and enum", + cases.add("qualified struct and enum", \\struct Foo { \\ int x; \\ int y; @@ -1526,19 +1508,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Bar = enum_Bar; }); - cases.add_2("bitwise binary operators, simpler parens", + cases.add("bitwise binary operators, simpler parens", \\int max(int a, int b) { \\ return (a & b) ^ (a | b); \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; + \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { + \\ var a = arg_a; + \\ var b = arg_b; \\ return ((a & b) ^ (a | b)); \\} }); - cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. + cases.add("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. \\int test_comparisons(int a, int b) { \\ int c = (a < b); \\ int d = (a > b); @@ -1550,9 +1532,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return i; \\} , &[_][]const u8{ - \\pub export fn test_comparisons(_arg_a: c_int, _arg_b: c_int) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; + \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int { + \\ var a = arg_a; + \\ var b = arg_b; \\ var c: c_int = @boolToInt((a < b)); \\ var d: c_int = @boolToInt((a > b)); \\ var e: c_int = @boolToInt((a <= b)); @@ -1564,7 +1546,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("==, !=", + cases.add("==, !=", \\int max(int a, int b) { \\ if (a == b) \\ return a; @@ -1573,16 +1555,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return a; \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; + \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { + \\ var a = arg_a; + \\ var b = arg_b; \\ if (a == b) return a; \\ if (a != b) return b; \\ return a; \\} }); - cases.add_2("typedeffed bool expression", + cases.add("typedeffed bool expression", \\typedef char* yes; \\void foo(void) { \\ yes a; @@ -1592,11 +1574,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const yes = [*c]u8; \\pub export fn foo() void { \\ var a: yes = undefined; - \\ if (a != null) _ = 2; + \\ if (a != null) _ = @as(c_int, 2); \\} }); - cases.add_2("statement expression", + cases.add("statement expression", \\int foo(void) { \\ return ({ \\ int a = 1; @@ -1614,7 +1596,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("field access expression", + cases.add("field access expression", \\#define ARROW a->b \\#define DOT a.b \\extern struct Foo { @@ -1643,7 +1625,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const ARROW = a.*.b; }); - cases.add_2("array access", + cases.add("array access", \\#define ACCESS array[2] \\int array[100] = {}; \\int foo(int index) { @@ -1651,15 +1633,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , &[_][]const u8{ \\pub export var array: [100]c_int = .{0} ** 100; - \\pub export fn foo(_arg_index: c_int) c_int { - \\ var index = _arg_index; + \\pub export fn foo(arg_index: c_int) c_int { + \\ var index = arg_index; \\ return array[index]; \\} , \\pub const ACCESS = array[2]; }); - cases.add_2("macro call", + cases.add("macro call", \\#define CALL(arg) bar(arg) , &[_][]const u8{ \\pub inline fn CALL(arg: var) @TypeOf(bar(arg)) { @@ -1667,7 +1649,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("logical and, logical or", + cases.add("logical and, logical or", \\int max(int a, int b) { \\ if (a < b || a == b) \\ return b; @@ -1676,16 +1658,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return a; \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; + \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { + \\ var a = arg_a; + \\ var b = arg_b; \\ if ((a < b) or (a == b)) return b; \\ if ((a >= b) and (a == b)) return a; \\ return a; \\} }); - cases.add_2("if statement", + cases.add("simple if statement", \\int max(int a, int b) { \\ if (a < b) \\ return b; @@ -1698,16 +1680,39 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ if (a < b) ; else ; \\} , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; + \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int { + \\ var a = arg_a; + \\ var b = arg_b; \\ if (a < b) return b; \\ if (a < b) return b else return a; \\ if (a < b) {} else {} \\} }); - cases.add_2("if on non-bool", + cases.add("if statements", + \\int foo() { + \\ if (2) { + \\ int a = 2; + \\ } + \\ if (2, 5) { + \\ int a = 2; + \\ } + \\} + , &[_][]const u8{ + \\pub export fn foo() c_int { + \\ if (@as(c_int, 2) != 0) { + \\ var a: c_int = 2; + \\ } + \\ if ((blk: { + \\ _ = @as(c_int, 2); + \\ break :blk @as(c_int, 5); + \\ }) != 0) { + \\ var a: c_int = 2; + \\ } + \\} + }); + + cases.add("if on non-bool", \\enum SomeEnum { A, B, C }; \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { \\ if (a) return 0; @@ -1722,11 +1727,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ B, \\ C, \\}; - \\pub export fn if_none_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void, _arg_d: enum_SomeEnum) c_int { - \\ var a = _arg_a; - \\ var b = _arg_b; - \\ var c = _arg_c; - \\ var d = _arg_d; + \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int { + \\ var a = arg_a; + \\ var b = arg_b; + \\ var c = arg_c; + \\ var d = arg_d; \\ if (a != 0) return 0; \\ if (b != 0) return 1; \\ if (c != null) return 2; @@ -1735,7 +1740,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("simple data types", + cases.add("simple data types", \\#include \\int foo(char a, unsigned char b, signed char c); \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype @@ -1747,18 +1752,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; }); - cases.add_2("simple function", + cases.add("simple function", \\int abs(int a) { \\ return a < 0 ? -a : a; \\} , &[_][]const u8{ - \\pub export fn abs(_arg_a: c_int) c_int { - \\ var a = _arg_a; - \\ return if (a < 0) -a else a; + \\pub export fn abs(arg_a: c_int) c_int { + \\ var a = arg_a; + \\ return if (a < @as(c_int, 0)) -a else a; \\} }); - cases.add_2("post increment", + cases.add("post increment", \\unsigned foo1(unsigned a) { \\ a++; \\ return a; @@ -1767,20 +1772,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ a++; \\ return a; \\} + \\int *foo3(int *a) { + \\ a++; + \\ return a; + \\} , &[_][]const u8{ - \\pub export fn foo1(_arg_a: c_uint) c_uint { - \\ var a = _arg_a; + \\pub export fn foo1(arg_a: c_uint) c_uint { + \\ var a = arg_a; \\ a +%= 1; \\ return a; \\} - \\pub export fn foo2(_arg_a: c_int) c_int { - \\ var a = _arg_a; + \\pub export fn foo2(arg_a: c_int) c_int { + \\ var a = arg_a; + \\ a += 1; + \\ return a; + \\} + \\pub export fn foo3(arg_a: [*c]c_int) [*c]c_int { + \\ var a = arg_a; \\ a += 1; \\ return a; \\} }); - cases.add_2("deref function pointer", + cases.add("deref function pointer", \\void foo(void) {} \\int baz(void) { return 0; } \\void bar(void) { @@ -1810,7 +1824,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("pre increment/decrement", + cases.add("pre increment/decrement", \\void foo(void) { \\ int i = 0; \\ unsigned u = 0; @@ -1826,35 +1840,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var i: c_int = 0; - \\ var u: c_uint = @as(c_uint, 0); + \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0)); \\ i += 1; \\ i -= 1; \\ u +%= 1; \\ u -%= 1; \\ i = (blk: { - \\ const _ref_1 = &i; - \\ _ref_1.* += 1; - \\ break :blk _ref_1.*; + \\ const ref = &i; + \\ ref.* += 1; + \\ break :blk ref.*; \\ }); \\ i = (blk: { - \\ const _ref_2 = &i; - \\ _ref_2.* -= 1; - \\ break :blk _ref_2.*; + \\ const ref = &i; + \\ ref.* -= 1; + \\ break :blk ref.*; \\ }); \\ u = (blk: { - \\ const _ref_3 = &u; - \\ _ref_3.* +%= 1; - \\ break :blk _ref_3.*; + \\ const ref = &u; + \\ ref.* +%= 1; + \\ break :blk ref.*; \\ }); \\ u = (blk: { - \\ const _ref_4 = &u; - \\ _ref_4.* -%= 1; - \\ break :blk _ref_4.*; + \\ const ref = &u; + \\ ref.* -%= 1; + \\ break :blk ref.*; \\ }); \\} }); - cases.add_2("shift right assign", + cases.add("shift right assign", \\int log2(unsigned a) { \\ int i = 0; \\ while (a > 0) { @@ -1863,17 +1877,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return i; \\} , &[_][]const u8{ - \\pub export fn log2(_arg_a: c_uint) c_int { - \\ var a = _arg_a; + \\pub export fn log2(arg_a: c_uint) c_int { + \\ var a = arg_a; \\ var i: c_int = 0; - \\ while (a > @as(c_uint, 0)) { + \\ while (a > @bitCast(c_uint, @as(c_int, 0))) { \\ a >>= @as(@import("std").math.Log2Int(c_int), 1); \\ } \\ return i; \\} }); - cases.add_2("shift right assign with a fixed size type", + cases.add("shift right assign with a fixed size type", \\#include \\int log2(uint32_t a) { \\ int i = 0; @@ -1883,17 +1897,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return i; \\} , &[_][]const u8{ - \\pub export fn log2(_arg_a: u32) c_int { - \\ var a = _arg_a; + \\pub export fn log2(arg_a: u32) c_int { + \\ var a = arg_a; \\ var i: c_int = 0; - \\ while (a > @as(c_uint, 0)) { + \\ while (a > @bitCast(c_uint, @as(c_int, 0))) { \\ a >>= @as(@import("std").math.Log2Int(c_int), 1); \\ } \\ return i; \\} }); - cases.add_2("compound assignment operators", + cases.add("compound assignment operators", \\void foo(void) { \\ int a = 0; \\ a += (a += 1); @@ -1909,49 +1923,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn foo() void { \\ var a: c_int = 0; \\ a += (blk: { - \\ const _ref_1 = &a; - \\ _ref_1.* = _ref_1.* + 1; - \\ break :blk _ref_1.*; + \\ const ref = &a; + \\ ref.* = ref.* + @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a -= (blk: { - \\ const _ref_2 = &a; - \\ _ref_2.* = _ref_2.* - 1; - \\ break :blk _ref_2.*; + \\ const ref = &a; + \\ ref.* = ref.* - @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a *= (blk: { - \\ const _ref_3 = &a; - \\ _ref_3.* = _ref_3.* * 1; - \\ break :blk _ref_3.*; + \\ const ref = &a; + \\ ref.* = ref.* * @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a &= (blk: { - \\ const _ref_4 = &a; - \\ _ref_4.* = _ref_4.* & 1; - \\ break :blk _ref_4.*; + \\ const ref = &a; + \\ ref.* = ref.* & @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a |= (blk: { - \\ const _ref_5 = &a; - \\ _ref_5.* = _ref_5.* | 1; - \\ break :blk _ref_5.*; + \\ const ref = &a; + \\ ref.* = ref.* | @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a ^= (blk: { - \\ const _ref_6 = &a; - \\ _ref_6.* = _ref_6.* ^ 1; - \\ break :blk _ref_6.*; + \\ const ref = &a; + \\ ref.* = ref.* ^ @as(c_int, 1); + \\ break :blk ref.*; \\ }); \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: { - \\ const _ref_7 = &a; - \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1); - \\ break :blk _ref_7.*; + \\ const ref = &a; + \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1)); + \\ break :blk ref.*; \\ })); \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: { - \\ const _ref_8 = &a; - \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1); - \\ break :blk _ref_8.*; + \\ const ref = &a; + \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1)); + \\ break :blk ref.*; \\ })); \\} }); - cases.add_2("compound assignment operators unsigned", + cases.add("compound assignment operators unsigned", \\void foo(void) { \\ unsigned a = 0; \\ a += (a += 1); @@ -1965,51 +1979,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , &[_][]const u8{ \\pub export fn foo() void { - \\ var a: c_uint = @as(c_uint, 0); + \\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0)); \\ a +%= (blk: { - \\ const _ref_1 = &a; - \\ _ref_1.* = _ref_1.* +% @as(c_uint, 1); - \\ break :blk _ref_1.*; + \\ const ref = &a; + \\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a -%= (blk: { - \\ const _ref_2 = &a; - \\ _ref_2.* = _ref_2.* -% @as(c_uint, 1); - \\ break :blk _ref_2.*; + \\ const ref = &a; + \\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a *%= (blk: { - \\ const _ref_3 = &a; - \\ _ref_3.* = _ref_3.* *% @as(c_uint, 1); - \\ break :blk _ref_3.*; + \\ const ref = &a; + \\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a &= (blk: { - \\ const _ref_4 = &a; - \\ _ref_4.* = _ref_4.* & @as(c_uint, 1); - \\ break :blk _ref_4.*; + \\ const ref = &a; + \\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a |= (blk: { - \\ const _ref_5 = &a; - \\ _ref_5.* = _ref_5.* | @as(c_uint, 1); - \\ break :blk _ref_5.*; + \\ const ref = &a; + \\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a ^= (blk: { - \\ const _ref_6 = &a; - \\ _ref_6.* = _ref_6.* ^ @as(c_uint, 1); - \\ break :blk _ref_6.*; + \\ const ref = &a; + \\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1)); + \\ break :blk ref.*; \\ }); \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: { - \\ const _ref_7 = &a; - \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1); - \\ break :blk _ref_7.*; + \\ const ref = &a; + \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1)); + \\ break :blk ref.*; \\ })); \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: { - \\ const _ref_8 = &a; - \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1); - \\ break :blk _ref_8.*; + \\ const ref = &a; + \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1)); + \\ break :blk ref.*; \\ })); \\} }); - cases.add_2("post increment/decrement", + cases.add("post increment/decrement", \\void foo(void) { \\ int i = 0; \\ unsigned u = 0; @@ -2025,39 +2039,39 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var i: c_int = 0; - \\ var u: c_uint = @as(c_uint, 0); + \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0)); \\ i += 1; \\ i -= 1; \\ u +%= 1; \\ u -%= 1; \\ i = (blk: { - \\ const _ref_1 = &i; - \\ const _tmp_2 = _ref_1.*; - \\ _ref_1.* += 1; - \\ break :blk _tmp_2; + \\ const ref = &i; + \\ const tmp = ref.*; + \\ ref.* += 1; + \\ break :blk tmp; \\ }); \\ i = (blk: { - \\ const _ref_3 = &i; - \\ const _tmp_4 = _ref_3.*; - \\ _ref_3.* -= 1; - \\ break :blk _tmp_4; + \\ const ref = &i; + \\ const tmp = ref.*; + \\ ref.* -= 1; + \\ break :blk tmp; \\ }); \\ u = (blk: { - \\ const _ref_5 = &u; - \\ const _tmp_6 = _ref_5.*; - \\ _ref_5.* +%= 1; - \\ break :blk _tmp_6; + \\ const ref = &u; + \\ const tmp = ref.*; + \\ ref.* +%= 1; + \\ break :blk tmp; \\ }); \\ u = (blk: { - \\ const _ref_7 = &u; - \\ const _tmp_8 = _ref_7.*; - \\ _ref_7.* -%= 1; - \\ break :blk _tmp_8; + \\ const ref = &u; + \\ const tmp = ref.*; + \\ ref.* -%= 1; + \\ break :blk tmp; \\ }); \\} }); - cases.add_2("implicit casts", + cases.add("implicit casts", \\#include \\ \\void fn_int(int x); @@ -2067,7 +2081,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\void fn_bool(bool x); \\void fn_ptr(void *x); \\ - \\void call(int q) { + \\void call() { \\ fn_int(3.0f); \\ fn_int(3.0); \\ fn_int(3.0L); @@ -2092,28 +2106,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn fn_char(x: u8) void; \\pub extern fn fn_bool(x: bool) void; \\pub extern fn fn_ptr(x: ?*c_void) void; - \\pub export fn call(_arg_q: c_int) void { - \\ var q = _arg_q; + \\pub export fn call() void { \\ fn_int(@floatToInt(c_int, 3)); \\ fn_int(@floatToInt(c_int, 3)); \\ fn_int(@floatToInt(c_int, 3)); - \\ fn_int(1094861636); - \\ fn_f32(@intToFloat(f32, 3)); - \\ fn_f64(@intToFloat(f64, 3)); - \\ fn_char(@as(u8, '3')); - \\ fn_char(@as(u8, '\x01')); - \\ fn_char(@as(u8, 0)); + \\ fn_int(@as(c_int, 1094861636)); + \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); + \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01')))); + \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0)))); \\ fn_f32(3); \\ fn_f64(3); - \\ fn_bool(123 != 0); - \\ fn_bool(0 != 0); + \\ fn_bool(@as(c_int, 123) != 0); + \\ fn_bool(@as(c_int, 0) != 0); \\ fn_bool(@ptrToInt(&fn_int) != 0); \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); - \\ fn_ptr(@intToPtr(?*c_void, 42)); + \\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42))); \\} }); - cases.add_2("function call", + cases.add("function call", \\static void bar(void) { } \\void foo(int *(baz)(void)) { \\ bar(); @@ -2121,14 +2134,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , &[_][]const u8{ \\pub fn bar() void {} - \\pub export fn foo(_arg_baz: ?extern fn () [*c]c_int) void { - \\ var baz = _arg_baz; + \\pub export fn foo(arg_baz: ?extern fn () [*c]c_int) void { + \\ var baz = arg_baz; \\ bar(); \\ _ = baz.?(); \\} }); - cases.add_2("macro defines string literal with octal", + cases.add("macro defines string literal with octal", \\#define FOO "aoeu\023 derp" \\#define FOO2 "aoeu\0234 derp" \\#define FOO_CHAR '\077' @@ -2140,7 +2153,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const FOO_CHAR = '\x3f'; }); - cases.add_2("enums", + cases.add("enums", \\enum Foo { \\ FooA, \\ FooB, @@ -2162,7 +2175,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = enum_Foo; }); - cases.add_2("enums", + cases.add("enums", \\enum Foo { \\ FooA = 2, \\ FooB = 5, @@ -2184,7 +2197,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = enum_Foo; }); - cases.add_2("macro cast", + cases.add("macro cast", \\#define FOO(bar) baz((void *)(baz)) , &[_][]const u8{ \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz))) { @@ -2192,1006 +2205,111 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add_2("macro conditional operator", + cases.add("macro conditional operator", \\#define FOO a ? b : c , &[_][]const u8{ \\pub const FOO = if (a) b else c; }); - /////////////// Cases for only stage1 because stage2 behavior is better //////////////// - cases.addC("Parameterless function prototypes", - \\void foo() {} - \\void bar(void) {} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub export fn bar() void {} - }); - - cases.add("#define a char literal", - \\#define A_CHAR 'a' - , &[_][]const u8{ - \\pub const A_CHAR = 97; - }); - - cases.add("generate inline func for #define global extern fn", - \\extern void (*fn_ptr)(void); - \\#define foo fn_ptr - \\ - \\extern char (*fn_ptr2)(int, float); - \\#define bar fn_ptr2 - , &[_][]const u8{ - \\pub extern var fn_ptr: ?extern fn () void; - , - \\pub inline fn foo() void { - \\ return fn_ptr.?(); + cases.add("do while as expr", + \\static void foo(void) { + \\ if (1) + \\ do {} while (0); \\} - , - \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; - , - \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { - \\ return fn_ptr2.?(arg0, arg1); - \\} - }); - cases.add("comment after integer literal", - \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = 32; - }); - - cases.add("u integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); - }); - - cases.add("l integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_long, 32); - }); - - cases.add("ul integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); - }); - - cases.add("lu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); - }); - - cases.add("ll integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); - }); - - cases.add("ull integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); - }); - - cases.add("llu integer suffix after hex literal", - \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ - , &[_][]const u8{ - \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); + \\pub fn foo() void { + \\ if (@as(c_int, 1) != 0) while (true) { + \\ if (!(@as(c_int, 0) != 0)) break; + \\ }; + \\} }); - cases.add("macros with field targets", - \\typedef unsigned int GLbitfield; - \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); - \\typedef void(*OpenGLProc)(void); - \\union OpenGLProcs { - \\ OpenGLProc ptr[1]; - \\ struct { - \\ PFNGLCLEARPROC Clear; - \\ } gl; - \\}; - \\extern union OpenGLProcs glProcs; - \\#define glClearUnion glProcs.gl.Clear - \\#define glClearPFN PFNGLCLEARPROC + cases.add("macro comparisions", + \\#define MIN(a, b) ((b) < (a) ? (b) : (a)) + \\#define MAX(a, b) ((b) > (a) ? (b) : (a)) , &[_][]const u8{ - \\pub const GLbitfield = c_uint; - , - \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; - , - \\pub const OpenGLProc = ?extern fn () void; - , - \\pub const union_OpenGLProcs = extern union { - \\ ptr: [1]OpenGLProc, - \\ gl: extern struct { - \\ Clear: PFNGLCLEARPROC, - \\ }, - \\}; - , - \\pub extern var glProcs: union_OpenGLProcs; - , - \\pub const glClearPFN = PFNGLCLEARPROC; - , - \\pub inline fn glClearUnion(arg0: GLbitfield) void { - \\ return glProcs.gl.Clear.?(arg0); + \\pub inline fn MIN(a: var, b: var) @TypeOf(if (b < a) b else a) { + \\ return if (b < a) b else a; \\} , - \\pub const OpenGLProcs = union_OpenGLProcs; - }); - - cases.add("macro pointer cast", - \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) - , &[_][]const u8{ - \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); + \\pub inline fn MAX(a: var, b: var) @TypeOf(if (b > a) b else a) { + \\ return if (b > a) b else a; + \\} }); - cases.add("switch on int", - \\int switch_fn(int i) { - \\ int res = 0; - \\ switch (i) { - \\ case 0: - \\ res = 1; - \\ case 1: - \\ res = 2; - \\ default: - \\ res = 3 * i; - \\ break; - \\ case 2: - \\ res = 5; - \\ } + // TODO: detect to use different block labels here + cases.add("nested assignment", + \\int foo(int *p, int x) { + \\ return *p++ = x; \\} , &[_][]const u8{ - \\pub fn switch_fn(i: c_int) c_int { - \\ var res: c_int = 0; - \\ __switch: { - \\ __case_2: { - \\ __default: { - \\ __case_1: { - \\ __case_0: { - \\ switch (i) { - \\ 0 => break :__case_0, - \\ 1 => break :__case_1, - \\ else => break :__default, - \\ 2 => break :__case_2, - \\ } - \\ } - \\ res = 1; - \\ } - \\ res = 2; - \\ } - \\ res = (3 * i); - \\ break :__switch; - \\ } - \\ res = 5; - \\ } + \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int { + \\ var p = arg_p; + \\ var x = arg_x; + \\ return blk: { + \\ const tmp = x; + \\ (blk: { + \\ const ref = &p; + \\ const tmp_1 = ref.*; + \\ ref.* += 1; + \\ break :blk tmp_1; + \\ }).?.* = tmp; + \\ break :blk tmp; + \\ }; \\} }); - cases.add("for loop with var init but empty body", - \\void foo(void) { - \\ for (int x = 0; x < 10; x++); + cases.add("widening and truncating integer casting to different signedness", + \\unsigned long foo(void) { + \\ return -1; + \\} + \\unsigned short bar(long x) { + \\ return x; \\} , &[_][]const u8{ - \\pub fn foo() void { - \\ { - \\ var x: c_int = 0; - \\ while (x < 10) : (x += 1) {} - \\ } + \\pub export fn foo() c_ulong { + \\ return @bitCast(c_ulong, @as(c_long, -@as(c_int, 1))); + \\} + \\pub export fn bar(arg_x: c_long) c_ushort { + \\ var x = arg_x; + \\ return @bitCast(c_ushort, @truncate(c_short, x)); \\} }); - cases.add("do while with empty body", - \\void foo(void) { - \\ do ; while (1); + cases.add("arg name aliasing decl which comes after", + \\int foo(int bar) { + \\ bar = 2; \\} - , &[_][]const u8{ // TODO this should be if (1 != 0) break - \\pub fn foo() void { - \\ while (true) { - \\ {} - \\ if (!1) break; - \\ } + \\int bar = 4; + , &[_][]const u8{ + \\pub export fn foo(arg_bar_1: c_int) c_int { + \\ var bar_1 = arg_bar_1; + \\ bar_1 = 2; \\} + \\pub export var bar: c_int = 4; }); - cases.add("for with empty body", - \\void foo(void) { - \\ for (;;); + cases.add("arg name aliasing macro which comes after", + \\int foo(int bar) { + \\ bar = 2; \\} + \\#define bar 4 , &[_][]const u8{ - \\pub fn foo() void { - \\ while (true) {} + \\pub export fn foo(arg_bar_1: c_int) c_int { + \\ var bar_1 = arg_bar_1; + \\ bar_1 = 2; \\} + , + \\pub const bar = 4; }); - cases.add("while with empty body", - \\void foo(void) { - \\ while (1); - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ while (1 != 0) {} - \\} - }); - - cases.add("undefined array global", - \\int array[100]; - , &[_][]const u8{ - \\pub var array: [100]c_int = undefined; - }); - - cases.add("qualified struct and enum", - \\struct Foo { - \\ int x; - \\ int y; - \\}; - \\enum Bar { - \\ BarA, - \\ BarB, - \\}; - \\void func(struct Foo *a, enum Bar **b); - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ x: c_int, - \\ y: c_int, - \\}; - , - \\pub const enum_Bar = extern enum { - \\ A, - \\ B, - \\}; - , - \\pub const BarA = enum_Bar.A; - , - \\pub const BarB = enum_Bar.B; - , - \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void; - , - \\pub const Foo = struct_Foo; - , - \\pub const Bar = enum_Bar; - }); - - cases.add("restrict -> noalias", - \\void foo(void *restrict bar, void *restrict); - , &[_][]const u8{ - \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; - }); - - cases.addC("assign", - \\int max(int a) { - \\ int tmp; - \\ tmp = a; - \\ a = tmp; - \\} - , &[_][]const u8{ - \\pub export fn max(_arg_a: c_int) c_int { - \\ var a = _arg_a; - \\ var tmp: c_int = undefined; - \\ tmp = a; - \\ a = tmp; - \\} - }); - - cases.addC("chaining assign", - \\void max(int a) { - \\ int b, c; - \\ c = b = a; - \\} - , &[_][]const u8{ - \\pub export fn max(a: c_int) void { - \\ var b: c_int = undefined; - \\ var c: c_int = undefined; - \\ c = (x: { - \\ const _tmp = a; - \\ b = _tmp; - \\ break :x _tmp; - \\ }); - \\} - }); - - cases.add("anonymous enum", - \\enum { - \\ One, - \\ Two, - \\}; - , &[_][]const u8{ - \\pub const One = 0; - \\pub const Two = 1; - }); - - cases.addC("c style cast", - \\int float_to_int(float a) { - \\ return (int)a; - \\} - , &[_][]const u8{ - \\pub export fn float_to_int(a: f32) c_int { - \\ return @as(c_int, a); - \\} - }); - - cases.addC("comma operator", - \\int foo(void) { - \\ return 1, 2; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return x: { - \\ _ = 1; - \\ break :x 2; - \\ }; - \\} - }); - - cases.addC("escape sequences", - \\const char *escapes() { - \\char a = '\'', - \\ b = '\\', - \\ c = '\a', - \\ d = '\b', - \\ e = '\f', - \\ f = '\n', - \\ g = '\r', - \\ h = '\t', - \\ i = '\v', - \\ j = '\0', - \\ k = '\"'; - \\ return "\'\\\a\b\f\n\r\t\v\0\""; - \\} - \\ - , &[_][]const u8{ - \\pub export fn escapes() [*c]const u8 { - \\ var a: u8 = @as(u8, '\''); - \\ var b: u8 = @as(u8, '\\'); - \\ var c: u8 = @as(u8, '\x07'); - \\ var d: u8 = @as(u8, '\x08'); - \\ var e: u8 = @as(u8, '\x0c'); - \\ var f: u8 = @as(u8, '\n'); - \\ var g: u8 = @as(u8, '\r'); - \\ var h: u8 = @as(u8, '\t'); - \\ var i: u8 = @as(u8, '\x0b'); - \\ var j: u8 = @as(u8, '\x00'); - \\ var k: u8 = @as(u8, '\"'); - \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; - \\} - \\ - }); - - cases.addC("do loop", - \\void foo(void) { - \\ int a = 2; - \\ do { - \\ a--; - \\ } while (a != 0); - \\ - \\ int b = 2; - \\ do - \\ b--; - \\ while (b != 0); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = 2; - \\ while (true) { - \\ a -= 1; - \\ if (!(a != 0)) break; - \\ } - \\ var b: c_int = 2; - \\ while (true) { - \\ b -= 1; - \\ if (!(b != 0)) break; - \\ } - \\} - }); - - cases.addC("==, !=", - \\int max(int a, int b) { - \\ if (a == b) - \\ return a; - \\ if (a != b) - \\ return b; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn max(a: c_int, b: c_int) c_int { - \\ if (a == b) return a; - \\ if (a != b) return b; - \\ return a; - \\} - }); - - cases.addC("bitwise binary operators", - \\int max(int a, int b) { - \\ return (a & b) ^ (a | b); - \\} - , &[_][]const u8{ - \\pub export fn max(a: c_int, b: c_int) c_int { - \\ return (a & b) ^ (a | b); - \\} - }); - - cases.addC("statement expression", - \\int foo(void) { - \\ return ({ - \\ int a = 1; - \\ a; - \\ }); - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return x: { - \\ var a: c_int = 1; - \\ break :x a; - \\ }; - \\} - }); - - cases.addC("field access expression", - \\struct Foo { - \\ int field; - \\}; - \\int read_field(struct Foo *foo) { - \\ return foo->field; - \\} - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ field: c_int, - \\}; - \\pub export fn read_field(foo: [*c]struct_Foo) c_int { - \\ return foo.*.field; - \\} - }); - - cases.addC("array access", - \\int array[100]; - \\int foo(int index) { - \\ return array[index]; - \\} - , &[_][]const u8{ - \\pub var array: [100]c_int = undefined; - \\pub export fn foo(index: c_int) c_int { - \\ return array[index]; - \\} - }); - - cases.addC("logical and, logical or", - \\int max(int a, int b) { - \\ if (a < b || a == b) - \\ return b; - \\ if (a >= b && a == b) - \\ return a; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn max(a: c_int, b: c_int) c_int { - \\ if ((a < b) or (a == b)) return b; - \\ if ((a >= b) and (a == b)) return a; - \\ return a; - \\} - }); - - cases.addC("if statement", - \\int max(int a, int b) { - \\ if (a < b) - \\ return b; - \\ - \\ if (a < b) - \\ return b; - \\ else - \\ return a; - \\ - \\ if (a < b) ; else ; - \\} - , &[_][]const u8{ - \\pub export fn max(a: c_int, b: c_int) c_int { - \\ if (a < b) return b; - \\ if (a < b) return b else return a; - \\ if (a < b) {} else {} - \\} - }); - - cases.add("variable name shadowing", - \\int foo(void) { - \\ int x = 1; - \\ { - \\ int x = 2; - \\ x += 1; - \\ } - \\ return x; - \\} - , &[_][]const u8{ - \\pub fn foo() c_int { - \\ var x: c_int = 1; - \\ { - \\ var x_0: c_int = 2; - \\ x_0 += 1; - \\ } - \\ return x; - \\} - }); - - cases.add("if on non-bool", - \\enum SomeEnum { A, B, C }; - \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { - \\ if (a) return 0; - \\ if (b) return 1; - \\ if (c) return 2; - \\ if (d) return 3; - \\ return 4; - \\} - , &[_][]const u8{ - \\pub const A = enum_SomeEnum.A; - \\pub const B = enum_SomeEnum.B; - \\pub const C = enum_SomeEnum.C; - \\pub const enum_SomeEnum = extern enum { - \\ A, - \\ B, - \\ C, - \\}; - \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { - \\ if (a != 0) return 0; - \\ if (b != 0) return 1; - \\ if (c != null) return 2; - \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3; - \\ return 4; - \\} - }); - - cases.addAllowWarnings("simple data types", - \\#include - \\int foo(char a, unsigned char b, signed char c); - \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype - \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); - \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); - , &[_][]const u8{ - \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; - , - \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; - , - \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; - }); - - cases.addC("simple function", - \\int abs(int a) { - \\ return a < 0 ? -a : a; - \\} - , &[_][]const u8{ - \\pub export fn abs(a: c_int) c_int { - \\ return if (a < 0) -a else a; - \\} - }); - - cases.addC("post increment", - \\unsigned foo1(unsigned a) { - \\ a++; - \\ return a; - \\} - \\int foo2(int a) { - \\ a++; - \\ return a; - \\} - , &[_][]const u8{ - \\pub export fn foo1(_arg_a: c_uint) c_uint { - \\ var a = _arg_a; - \\ a +%= 1; - \\ return a; - \\} - \\pub export fn foo2(_arg_a: c_int) c_int { - \\ var a = _arg_a; - \\ a += 1; - \\ return a; - \\} - }); - - cases.addC("deref function pointer", - \\void foo(void) {} - \\int baz(void) { return 0; } - \\void bar(void) { - \\ void(*f)(void) = foo; - \\ int(*b)(void) = baz; - \\ f(); - \\ (*(f))(); - \\ foo(); - \\ b(); - \\ (*(b))(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub export fn foo() void {} - \\pub export fn baz() c_int { - \\ return 0; - \\} - \\pub export fn bar() void { - \\ var f: ?extern fn () void = foo; - \\ var b: ?extern fn () c_int = baz; - \\ f.?(); - \\ f.?(); - \\ foo(); - \\ _ = b.?(); - \\ _ = b.?(); - \\ _ = baz(); - \\} - }); - - cases.addC("pre increment/decrement", - \\void foo(void) { - \\ int i = 0; - \\ unsigned u = 0; - \\ ++i; - \\ --i; - \\ ++u; - \\ --u; - \\ i = ++i; - \\ i = --i; - \\ u = ++u; - \\ u = --u; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var i: c_int = 0; - \\ var u: c_uint = @as(c_uint, 0); - \\ i += 1; - \\ i -= 1; - \\ u +%= 1; - \\ u -%= 1; - \\ i = (x: { - \\ const _ref = &i; - \\ _ref.* += 1; - \\ break :x _ref.*; - \\ }); - \\ i = (x: { - \\ const _ref = &i; - \\ _ref.* -= 1; - \\ break :x _ref.*; - \\ }); - \\ u = (x: { - \\ const _ref = &u; - \\ _ref.* +%= 1; - \\ break :x _ref.*; - \\ }); - \\ u = (x: { - \\ const _ref = &u; - \\ _ref.* -%= 1; - \\ break :x _ref.*; - \\ }); - \\} - }); - - cases.addC("shift right assign", - \\int log2(unsigned a) { - \\ int i = 0; - \\ while (a > 0) { - \\ a >>= 1; - \\ } - \\ return i; - \\} - , &[_][]const u8{ - \\pub export fn log2(_arg_a: c_uint) c_int { - \\ var a = _arg_a; - \\ var i: c_int = 0; - \\ while (a > @as(c_uint, 0)) { - \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1); - \\ } - \\ return i; - \\} - }); - - cases.addC("shift right assign with a fixed size type", - \\#include - \\int log2(uint32_t a) { - \\ int i = 0; - \\ while (a > 0) { - \\ a >>= 1; - \\ } - \\ return i; - \\} - , &[_][]const u8{ - \\pub export fn log2(_arg_a: u32) c_int { - \\ var a = _arg_a; - \\ var i: c_int = 0; - \\ while (a > @as(c_uint, 0)) { - \\ a >>= @as(u5, 1); - \\ } - \\ return i; - \\} - }); - - cases.addC("compound assignment operators", - \\void foo(void) { - \\ int a = 0; - \\ a += (a += 1); - \\ a -= (a -= 1); - \\ a *= (a *= 1); - \\ a &= (a &= 1); - \\ a |= (a |= 1); - \\ a ^= (a ^= 1); - \\ a >>= (a >>= 1); - \\ a <<= (a <<= 1); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = 0; - \\ a += (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* + 1); - \\ break :x _ref.*; - \\ }); - \\ a -= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* - 1); - \\ break :x _ref.*; - \\ }); - \\ a *= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* * 1); - \\ break :x _ref.*; - \\ }); - \\ a &= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* & 1); - \\ break :x _ref.*; - \\ }); - \\ a |= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* | 1); - \\ break :x _ref.*; - \\ }); - \\ a ^= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* ^ 1); - \\ break :x _ref.*; - \\ }); - \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1)); - \\ break :x _ref.*; - \\ })); - \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1)); - \\ break :x _ref.*; - \\ })); - \\} - }); - - cases.addC("compound assignment operators unsigned", - \\void foo(void) { - \\ unsigned a = 0; - \\ a += (a += 1); - \\ a -= (a -= 1); - \\ a *= (a *= 1); - \\ a &= (a &= 1); - \\ a |= (a |= 1); - \\ a ^= (a ^= 1); - \\ a >>= (a >>= 1); - \\ a <<= (a <<= 1); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_uint = @as(c_uint, 0); - \\ a +%= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* +% @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a -%= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* -% @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a *%= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* *% @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a &= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* & @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a |= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* | @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a ^= (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* ^ @as(c_uint, 1)); - \\ break :x _ref.*; - \\ }); - \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1)); - \\ break :x _ref.*; - \\ })); - \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: { - \\ const _ref = &a; - \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1)); - \\ break :x _ref.*; - \\ })); - \\} - }); - - cases.addC("post increment/decrement", - \\void foo(void) { - \\ int i = 0; - \\ unsigned u = 0; - \\ i++; - \\ i--; - \\ u++; - \\ u--; - \\ i = i++; - \\ i = i--; - \\ u = u++; - \\ u = u--; - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var i: c_int = 0; - \\ var u: c_uint = @as(c_uint, 0); - \\ i += 1; - \\ i -= 1; - \\ u +%= 1; - \\ u -%= 1; - \\ i = (x: { - \\ const _ref = &i; - \\ const _tmp = _ref.*; - \\ _ref.* += 1; - \\ break :x _tmp; - \\ }); - \\ i = (x: { - \\ const _ref = &i; - \\ const _tmp = _ref.*; - \\ _ref.* -= 1; - \\ break :x _tmp; - \\ }); - \\ u = (x: { - \\ const _ref = &u; - \\ const _tmp = _ref.*; - \\ _ref.* +%= 1; - \\ break :x _tmp; - \\ }); - \\ u = (x: { - \\ const _ref = &u; - \\ const _tmp = _ref.*; - \\ _ref.* -%= 1; - \\ break :x _tmp; - \\ }); - \\} - }); - - cases.addC("implicit casts", - \\#include - \\ - \\void fn_int(int x); - \\void fn_f32(float x); - \\void fn_f64(double x); - \\void fn_char(char x); - \\void fn_bool(bool x); - \\void fn_ptr(void *x); - \\ - \\void call(int q) { - \\ fn_int(3.0f); - \\ fn_int(3.0); - \\ fn_int(3.0L); - \\ fn_int('ABCD'); - \\ fn_f32(3); - \\ fn_f64(3); - \\ fn_char('3'); - \\ fn_char('\x1'); - \\ fn_char(0); - \\ fn_f32(3.0f); - \\ fn_f64(3.0); - \\ fn_bool(123); - \\ fn_bool(0); - \\ fn_bool(&fn_int); - \\ fn_int(&fn_int); - \\ fn_ptr(42); - \\} - , &[_][]const u8{ - \\pub extern fn fn_int(x: c_int) void; - \\pub extern fn fn_f32(x: f32) void; - \\pub extern fn fn_f64(x: f64) void; - \\pub extern fn fn_char(x: u8) void; - \\pub extern fn fn_bool(x: bool) void; - \\pub extern fn fn_ptr(x: ?*c_void) void; - \\pub export fn call(q: c_int) void { - \\ fn_int(@floatToInt(c_int, 3.000000)); - \\ fn_int(@floatToInt(c_int, 3.000000)); - \\ fn_int(@floatToInt(c_int, 3.000000)); - \\ fn_int(1094861636); - \\ fn_f32(@intToFloat(f32, 3)); - \\ fn_f64(@intToFloat(f64, 3)); - \\ fn_char(@as(u8, '3')); - \\ fn_char(@as(u8, '\x01')); - \\ fn_char(@as(u8, 0)); - \\ fn_f32(3.000000); - \\ fn_f64(3.000000); - \\ fn_bool(true); - \\ fn_bool(false); - \\ fn_bool(@ptrToInt(&fn_int) != 0); - \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); - \\ fn_ptr(@intToPtr(?*c_void, 42)); - \\} - }); - - cases.addC("function call", - \\static void bar(void) { } - \\void foo(int *(baz)(void)) { - \\ bar(); - \\ baz(); - \\} - , &[_][]const u8{ - \\pub fn bar() void {} - \\pub export fn foo(baz: ?extern fn () [*c]c_int) void { - \\ bar(); - \\ _ = baz.?(); - \\} - }); - - cases.add("macro defines string literal with hex", - \\#define FOO "aoeu\xab derp" - \\#define FOO2 "aoeu\x0007a derp" - \\#define FOO_CHAR '\xfF' - , &[_][]const u8{ - \\pub const FOO = "aoeu\xab derp"; - , - \\pub const FOO2 = "aoeuz derp"; - , - \\pub const FOO_CHAR = 255; - }); - - cases.add("macro defines string literal with octal", - \\#define FOO "aoeu\023 derp" - \\#define FOO2 "aoeu\0234 derp" - \\#define FOO_CHAR '\077' - , &[_][]const u8{ - \\pub const FOO = "aoeu\x13 derp"; - , - \\pub const FOO2 = "aoeu\x134 derp"; - , - \\pub const FOO_CHAR = 63; - }); - - cases.add("enums", - \\enum Foo { - \\ FooA, - \\ FooB, - \\ Foo1, - \\}; - , &[_][]const u8{ - \\pub const enum_Foo = extern enum { - \\ A, - \\ B, - \\ @"1", - \\}; - , - \\pub const FooA = enum_Foo.A; - , - \\pub const FooB = enum_Foo.B; - , - \\pub const Foo1 = enum_Foo.@"1"; - , - \\pub const Foo = enum_Foo; - }); - - cases.add("enums", - \\enum Foo { - \\ FooA = 2, - \\ FooB = 5, - \\ Foo1, - \\}; + cases.add("don't export inline functions", + \\inline void a(void) {} + \\static void b(void) {} + \\void c(void) {} , &[_][]const u8{ - \\pub const enum_Foo = extern enum { - \\ A = 2, - \\ B = 5, - \\ @"1" = 6, - \\}; - , - \\pub const FooA = enum_Foo.A; - , - \\pub const FooB = enum_Foo.B; - , - \\pub const Foo1 = enum_Foo.@"1"; - , - \\pub const Foo = enum_Foo; + \\pub fn a() void {} + \\pub fn b() void {} + \\pub export fn c() void {} }); }