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 d53accbaf7..e00271968b 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 ac5c52ee0d..60b3961e6e 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 32bb9b4487..efdef1e26b 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 eac3592692..4ea8cc731b 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); 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 5fa4c32041..846eec0d62 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)));