Commit c090e38340

Evan Haas <evan@lagerdata.com>
2021-07-28 01:06:38
translate-c: add support for ChooseExpr
1 parent 98eea96
src/clang.zig
@@ -269,6 +269,11 @@ pub const CharacterLiteral = opaque {
     extern fn ZigClangCharacterLiteral_getValue(*const CharacterLiteral) c_uint;
 };
 
+pub const ChooseExpr = opaque {
+    pub const getChosenSubExpr = ZigClangChooseExpr_getChosenSubExpr;
+    extern fn ZigClangChooseExpr_getChosenSubExpr(*const ChooseExpr) *const Expr;
+};
+
 pub const CompoundAssignOperator = opaque {
     pub const getType = ZigClangCompoundAssignOperator_getType;
     extern fn ZigClangCompoundAssignOperator_getType(*const CompoundAssignOperator) QualType;
src/translate_c.zig
@@ -1308,6 +1308,10 @@ fn transStmt(
             const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
             return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);
         },
+        .ChooseExprClass => {
+            const choose_expr = @ptrCast(*const clang.ChooseExpr, stmt);
+            return transExpr(c, scope, choose_expr.getChosenSubExpr(), result_used);
+        },
         // When adding new cases here, see comment for maybeBlockify()
         .GCCAsmStmtClass,
         .GotoStmtClass,
src/zig_clang.cpp
@@ -2832,6 +2832,11 @@ unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral
     return casted->getValue();
 }
 
+const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *self) {
+    auto casted = reinterpret_cast<const clang::ChooseExpr *>(self);
+    return reinterpret_cast<const ZigClangExpr *>(casted->getChosenSubExpr());
+}
+
 const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *self) {
     auto casted = reinterpret_cast<const clang::AbstractConditionalOperator *>(self);
     return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
src/zig_clang.h
@@ -104,6 +104,7 @@ struct ZigClangCStyleCastExpr;
 struct ZigClangCallExpr;
 struct ZigClangCaseStmt;
 struct ZigClangCharacterLiteral;
+struct ZigClangChooseExpr;
 struct ZigClangCompoundAssignOperator;
 struct ZigClangCompoundStmt;
 struct ZigClangConditionalOperator;
@@ -1242,6 +1243,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(
 ZIG_EXTERN_C enum ZigClangCharacterLiteral_CharacterKind ZigClangCharacterLiteral_getKind(const struct ZigClangCharacterLiteral *);
 ZIG_EXTERN_C unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral *);
 
+ZIG_EXTERN_C const struct ZigClangExpr *ZigClangChooseExpr_getChosenSubExpr(const struct ZigClangChooseExpr *);
+
 ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getCond(const struct ZigClangAbstractConditionalOperator *);
 ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getTrueExpr(const struct ZigClangAbstractConditionalOperator *);
 ZIG_EXTERN_C const struct ZigClangExpr *ZigClangAbstractConditionalOperator_getFalseExpr(const struct ZigClangAbstractConditionalOperator *);
test/run_translated_c.zig
@@ -1659,4 +1659,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\    return 0;
         \\}
     , "");
+
+    cases.add("__builtin_choose_expr (unchosen expression is not evaluated)",
+        \\#include <stdlib.h>
+        \\int main(void) {
+        \\    int x = 0.0;
+        \\    int y = 0.0;
+        \\    int res;
+        \\    res = __builtin_choose_expr(1, 1, x / y);
+        \\    if (res != 1) abort();
+        \\    res = __builtin_choose_expr(0, x / y, 2);
+        \\    if (res != 2) abort();
+        \\    return 0;
+        \\}
+    , "");
+
+    // TODO: add isnan check for long double once bitfield support is added
+    //       (needed for x86_64-windows-gnu)
+    // TODO: add isinf check for long double once std.math.isInf supports c_longdouble
+    cases.add("NAN and INFINITY",
+        \\#include <math.h>
+        \\#include <stdint.h>
+        \\#include <stdlib.h>
+        \\union uf { uint32_t u; float f; };
+        \\#define CHECK_NAN(STR, VAL) { \
+        \\    union uf unpack = {.f = __builtin_nanf(STR)}; \
+        \\    if (!isnan(unpack.f)) abort(); \
+        \\    if (unpack.u != VAL) abort(); \
+        \\}
+        \\int main(void) {
+        \\    float f_nan = NAN;
+        \\    if (!isnan(f_nan)) abort();
+        \\    double d_nan = NAN;
+        \\    if (!isnan(d_nan)) abort();
+        \\    CHECK_NAN("0", 0x7FC00000);
+        \\    CHECK_NAN("", 0x7FC00000);
+        \\    CHECK_NAN("1", 0x7FC00001);
+        \\    CHECK_NAN("0x7FC00000", 0x7FC00000);
+        \\    CHECK_NAN("0x7FC0000F", 0x7FC0000F);
+        \\    CHECK_NAN("0x7FC000F0", 0x7FC000F0);
+        \\    CHECK_NAN("0x7FC00F00", 0x7FC00F00);
+        \\    CHECK_NAN("0x7FC0F000", 0x7FC0F000);
+        \\    CHECK_NAN("0x7FCF0000", 0x7FCF0000);
+        \\    CHECK_NAN("0xFFFFFFFF", 0x7FFFFFFF);
+        \\    float f_inf = INFINITY;
+        \\    if (!isinf(f_inf)) abort();
+        \\    double d_inf = INFINITY;
+        \\    if (!isinf(d_inf)) abort();
+        \\    return 0;
+        \\}
+    , "");
 }