Commit 7c3896e6cd

LemonBoy <thatlemon@gmail.com>
2021-04-24 18:42:23
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
1 parent 4ec6d17
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 {
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))
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<const clang::FloatingLiteral *>(self);
+    return static_cast<ZigClangAPFloatBase_Semantics>(casted->getRawSemantics());
+}
+
 enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) {
     auto casted = reinterpret_cast<const clang::StringLiteral *>(self);
     return (ZigClangStringLiteral_StringKind)casted->getKind();
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);