diff --git a/src/clang.zig b/src/clang.zig index 954cfee6b2..fbb955205b 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -127,6 +127,9 @@ pub const APSInt = opaque { pub const getNumWords = ZigClangAPSInt_getNumWords; extern fn ZigClangAPSInt_getNumWords(*const APSInt) c_uint; + + pub const lessThanEqual = ZigClangAPSInt_lessThanEqual; + extern fn ZigClangAPSInt_lessThanEqual(*const APSInt, rhs: u64) bool; }; pub const ASTContext = opaque { @@ -407,7 +410,7 @@ pub const Expr = opaque { pub const getBeginLoc = ZigClangExpr_getBeginLoc; extern fn ZigClangExpr_getBeginLoc(*const Expr) SourceLocation; - pub const EvaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr; + pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr; extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstExprUsage, *const ASTContext) bool; }; diff --git a/src/translate_c.zig b/src/translate_c.zig index fbd0ec6245..1fcac233fc 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1820,11 +1820,55 @@ fn transExprCoercing(c: *Context, scope: *Scope, expr: *const clang.Expr, used: return transExprCoercing(c, scope, un_expr.getSubExpr(), used); } }, + .ImplicitCastExprClass => { + const cast_expr = @ptrCast(*const clang.ImplicitCastExpr, expr); + const sub_expr = cast_expr.getSubExpr(); + switch (@ptrCast(*const clang.Stmt, sub_expr).getStmtClass()) { + .IntegerLiteralClass, .CharacterLiteralClass => switch (cast_expr.getCastKind()) { + .IntegralToFloating => return transExprCoercing(c, scope, sub_expr, used), + .IntegralCast => { + const dest_type = getExprQualType(c, expr); + if (literalFitsInType(c, sub_expr, dest_type)) + return transExprCoercing(c, scope, sub_expr, used); + }, + else => {}, + }, + else => {}, + } + }, else => {}, } return transExpr(c, scope, expr, .used); } +fn literalFitsInType(c: *Context, expr: *const clang.Expr, qt: clang.QualType) bool { + var width = qualTypeIntBitWidth(c, qt) catch 8; + if (width == 0) width = 8; // Byte is the smallest type. + const is_signed = cIsSignedInteger(qt); + const width_max_int= (@as(u64, 1) << math.lossyCast(u6, width - @boolToInt(is_signed))) - 1; + + switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) { + .CharacterLiteralClass => { + const char_lit = @ptrCast(*const clang.CharacterLiteral, expr); + const val = char_lit.getValue(); + // If the val is less than the max int then it fits. + return val <= width_max_int; + }, + .IntegerLiteralClass => { + const int_lit = @ptrCast(*const clang.IntegerLiteral, expr); + var eval_result: clang.ExprEvalResult = undefined; + if (!int_lit.EvaluateAsInt(&eval_result, c.clang_context)) { + return false; + } + + const int = eval_result.Val.getInt(); + return int.lessThanEqual(width_max_int); + }, + else => unreachable, + } + +} + fn transInitListExprRecord( c: *Context, scope: *Scope, @@ -2331,7 +2375,7 @@ fn transDefault( fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { var result: clang.ExprEvalResult = undefined; - if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context)) + if (!expr.evaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context)) return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{}); switch (result.Val.getKind()) { @@ -3171,7 +3215,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool { return qualTypeCanon(qt).isBooleanType(); } -fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 { +fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType) !u32 { const ty = qt.getTypePtr(); switch (ty.getTypeClass()) { @@ -3211,12 +3255,10 @@ fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType, source_loc: clang.Source }, else => return 0, } - - unreachable; } fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) !Node { - const int_bit_width = try qualTypeIntBitWidth(c, qt, source_loc); + const int_bit_width = try qualTypeIntBitWidth(c, qt); if (int_bit_width != 0) { // we can perform the log2 now. diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 8dc6a0823b..d9e5e527ac 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2244,6 +2244,11 @@ unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) { return casted->getNumWords(); } +bool ZigClangAPSInt_lessThanEqual(const ZigClangAPSInt *self, uint64_t rhs) { + auto casted = reinterpret_cast(self); + return casted->ule(rhs); +} + uint64_t ZigClangAPInt_getLimitedValue(const ZigClangAPInt *self, uint64_t limit) { auto casted = reinterpret_cast(self); return casted->getLimitedValue(limit); diff --git a/src/zig_clang.h b/src/zig_clang.h index 6fe1da0bc1..a697c58b4f 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1097,6 +1097,7 @@ ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct Zig ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self); ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self); ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self); +ZIG_EXTERN_C bool ZigClangAPSInt_lessThanEqual(const struct ZigClangAPSInt *self, uint64_t rhs); ZIG_EXTERN_C uint64_t ZigClangAPInt_getLimitedValue(const struct ZigClangAPInt *self, uint64_t limit); diff --git a/test/translate_c.zig b/test/translate_c.zig index 6cbdbe931c..dda0e45144 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -313,22 +313,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub const uuid_t = [16]u8; \\pub const UUID_NULL: uuid_t = [16]u8{ - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))), + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, + \\ 0, \\}; }); @@ -382,10 +382,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; \\pub export var ub: union_unnamed_1 = union_unnamed_1{ \\ .c = [4]u8{ - \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))), - \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))), + \\ 'a', + \\ 'b', + \\ 'b', + \\ 'a', \\ }, \\}; }); @@ -512,7 +512,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var a: c_int = undefined; - \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123))); + \\ var b: u8 = 123; \\ const c: c_int = undefined; \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440)); \\ var e: c_int = 10; @@ -1468,7 +1468,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub fn foo() callconv(.C) void { \\ var arr: [10]u8 = [1]u8{ - \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))), + \\ 1, \\ } ++ [1]u8{0} ** 9; \\ var arr1: [10][*c]u8 = [1][*c]u8{ \\ null, @@ -1721,13 +1721,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ unsigned d = 440; \\} , &[_][]const u8{ - \\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 a: c_long = 2; + \\pub var b: c_long = 2; \\pub var c: c_int = 4; \\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 = @bitCast(u8, @truncate(i8, @as(c_int, 123))); + \\ var b_3: u8 = 123; \\ b_3 = @bitCast(u8, @truncate(i8, a_2)); \\ { \\ var d: c_int = 5; @@ -1838,7 +1838,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ }; \\ } \\ } - \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2))); + \\ var i: u8 = 2; \\} }); @@ -1846,7 +1846,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\unsigned anyerror = 2; \\#define noreturn _Noreturn , &[_][]const u8{ - \\pub export var anyerror_1: c_uint = @bitCast(c_uint, @as(c_int, 2)); + \\pub export var anyerror_1: c_uint = 2; , \\pub const noreturn_2 = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn"); }); @@ -1860,7 +1860,7 @@ 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, @as(c_int, 3)); + \\pub export var d: f64 = 3; }); cases.add("conditional operator", @@ -2009,7 +2009,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - // 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 = '\'', @@ -2028,17 +2027,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ , &[_][]const u8{ \\pub export fn escapes() [*c]const 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, '\"'))); + \\ var a: u8 = '\''; + \\ var b: u8 = '\\'; + \\ var c: u8 = '\x07'; + \\ var d: u8 = '\x08'; + \\ var e: u8 = '\x0c'; + \\ var f: u8 = '\n'; + \\ var g: u8 = '\r'; + \\ var h: u8 = '\t'; + \\ var i: u8 = '\x0b'; + \\ var j: u8 = '\x00'; + \\ var k: u8 = '\"'; \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; \\} }); @@ -2308,8 +2307,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var a: [10]c_longlong = undefined; - \\ var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0))); - \\ a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0))); + \\ var i: c_longlong = 0; + \\ a[@intCast(usize, i)] = 0; \\} }); @@ -2321,8 +2320,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var a: [10]c_uint = undefined; - \\ var i: c_uint = @bitCast(c_uint, @as(c_int, 0)); - \\ a[i] = @bitCast(c_uint, @as(c_int, 0)); + \\ var i: c_uint = 0; + \\ a[i] = 0; \\} }); @@ -2527,7 +2526,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var i: c_int = 0; - \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0)); + \\ var u: c_uint = 0; \\ i += 1; \\ i -= 1; \\ u +%= 1; @@ -2614,7 +2613,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var a: c_int = 0; - \\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0)); + \\ var b: c_uint = 0; \\ a += blk: { \\ const ref = &a; \\ ref.* += @as(c_int, 1); @@ -2692,7 +2691,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , &[_][]const u8{ \\pub export fn foo() void { - \\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0)); + \\ var a: c_uint = 0; \\ a +%= blk: { \\ const ref = &a; \\ ref.* +%= @bitCast(c_uint, @as(c_int, 1)); @@ -2752,7 +2751,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub export fn foo() void { \\ var i: c_int = 0; - \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0)); + \\ var u: c_uint = 0; \\ i += 1; \\ i -= 1; \\ u +%= 1;