From 7c3896e6cd20a51e63a018fd2e05ea3c552b7401 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 24 Apr 2021 18:42:23 +0200 Subject: [PATCH 1/2] translate-c: Prevent mistranslation of fp literals When trying to retrieve 80bit fp values from clang using getValueAsApproximateDouble we'd eventually hit the ceiling value and return infinity, an invalid value for a fp literal. Add some logic to prevent this error and warn the user. Closes #8602 --- src/clang.zig | 16 ++++++++++++++++ src/translate_c.zig | 17 +++++++++++++++-- src/zig_clang.cpp | 5 +++++ src/zig_clang.h | 11 +++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/clang.zig b/src/clang.zig index d53accbaf7eb6f18640ef4a5bdb4013b27b79afb..e00271968bc305ced0e2a2f8a4d2d6b1a0ae53f8 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -104,6 +104,16 @@ pub const APFloat = opaque { extern fn ZigClangAPFloat_toString(*const APFloat, precision: c_uint, maxPadding: c_uint, truncateZero: bool) [*:0]const u8; }; +pub const APFloatBaseSemantics = extern enum { + IEEEhalf, + BFloat, + IEEEsingle, + IEEEdouble, + x86DoubleExtended, + IEEEquad, + PPCDoubleDouble, +}; + pub const APInt = opaque { pub const getLimitedValue = ZigClangAPInt_getLimitedValue; extern fn ZigClangAPInt_getLimitedValue(*const APInt, limit: u64) u64; @@ -455,6 +465,12 @@ pub const FileID = opaque {}; pub const FloatingLiteral = opaque { pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble; extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64; + + pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; + extern fn ZigClangIntegerLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation; + + pub const getRawSemantics = ZigClangFloatingLiteral_getRawSemantics; + extern fn ZigClangFloatingLiteral_getRawSemantics(*const FloatingLiteral) APFloatBaseSemantics; }; pub const ForStmt = opaque { diff --git a/src/translate_c.zig b/src/translate_c.zig index ac5c52ee0d95744cbd4f5b9457ff9169b8821082..60b3961e6ef99ca33e2044d8da88b82a5405329b 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -3547,9 +3547,22 @@ fn transCPtrCast( } } -fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { +fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { + switch (expr.getRawSemantics()) { + .IEEEhalf, // f16 + .IEEEsingle, // f32 + .IEEEdouble, // f64 + => {}, + else => |format| return fail( + c, + error.UnsupportedTranslation, + expr.getBeginLoc(), + "unsupported floating point constant format {}", + .{format}, + ), + } // TODO use something more accurate - var dbl = stmt.getValueAsApproximateDouble(); + var dbl = expr.getValueAsApproximateDouble(); const is_negative = dbl < 0; if (is_negative) dbl = -dbl; const str = if (dbl == std.math.floor(dbl)) diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 32bb9b44877435cadf53369a1f931d4516233d14..efdef1e26b26bb0d470ebadd0aeec3e67a06854f 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2528,6 +2528,11 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin return casted->getValueAsApproximateDouble(); } +ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self) { + auto casted = reinterpret_cast(self); + return static_cast(casted->getRawSemantics()); +} + enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { auto casted = reinterpret_cast(self); return (ZigClangStringLiteral_StringKind)casted->getKind(); diff --git a/src/zig_clang.h b/src/zig_clang.h index eac359269250e9000962aed847eddb997a998b44..4ea8cc731b4b751025c82022b9807a5ed170add7 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -881,6 +881,16 @@ enum ZigClangAPFloat_roundingMode { ZigClangAPFloat_roundingMode_Invalid = -1, }; +enum ZigClangAPFloatBase_Semantics { + ZigClangAPFloatBase_Semantics_IEEEhalf, + ZigClangAPFloatBase_Semantics_BFloat, + ZigClangAPFloatBase_Semantics_IEEEsingle, + ZigClangAPFloatBase_Semantics_IEEEdouble, + ZigClangAPFloatBase_Semantics_x87DoubleExtended, + ZigClangAPFloatBase_Semantics_IEEEquad, + ZigClangAPFloatBase_Semantics_PPCDoubleDouble, +}; + enum ZigClangStringLiteral_StringKind { ZigClangStringLiteral_StringKind_Ascii, ZigClangStringLiteral_StringKind_Wide, @@ -1142,6 +1152,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); +ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self); ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); ZIG_EXTERN_C uint32_t ZigClangStringLiteral_getCodeUnit(const struct ZigClangStringLiteral *self, size_t i); -- 2.54.0 From cf98dfbe22548728f247c314e3119c5a5dfceac5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 24 Apr 2021 20:35:04 +0200 Subject: [PATCH 2/2] Remove translate-c test using long double literal Removed until the rendering logic is adapted to deal with 80bit (and bigger) floats, those are used sparingly in the wild so it's not much of a loss. --- test/translate_c.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/translate_c.zig b/test/translate_c.zig index 5fa4c3204163f3bc4a31a4d7a680eca7fed6ebc8..846eec0d624e6f05e199ccbe524444ce8181c40e 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -3028,7 +3028,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\void call() { \\ fn_int(3.0f); \\ fn_int(3.0); - \\ fn_int(3.0L); \\ fn_int('ABCD'); \\ fn_f32(3); \\ fn_f64(3); @@ -3053,7 +3052,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export fn call() void { \\ fn_int(@floatToInt(c_int, 3.0)); \\ fn_int(@floatToInt(c_int, 3.0)); - \\ fn_int(@floatToInt(c_int, 3.0)); \\ fn_int(@as(c_int, 1094861636)); \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); -- 2.54.0