translate-c: Implement generic selection expressions

Enables translation of C code that uses the `_Generic` keyword
This commit is contained in:
Evan Haas
2021-03-09 20:49:24 -08:00
committed by Veikka Tuominen
parent 9a94415680
commit c558a1ae26
5 changed files with 58 additions and 0 deletions

View File

@@ -537,6 +537,11 @@ pub const FunctionType = opaque {
extern fn ZigClangFunctionType_getReturnType(*const FunctionType) QualType;
};
pub const GenericSelectionExpr = opaque {
pub const getResultExpr = ZigClangGenericSelectionExpr_getResultExpr;
extern fn ZigClangGenericSelectionExpr_getResultExpr(*const GenericSelectionExpr) *const Expr;
};
pub const IfStmt = opaque {
pub const getThen = ZigClangIfStmt_getThen;
extern fn ZigClangIfStmt_getThen(*const IfStmt) *const Stmt;

View File

@@ -1058,6 +1058,10 @@ fn transStmt(
const compound_literal = @ptrCast(*const clang.CompoundLiteralExpr, stmt);
return transExpr(c, scope, compound_literal.getInitializer(), result_used);
},
.GenericSelectionExprClass => {
const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt);
return transExpr(c, scope, gen_sel.getResultExpr(), result_used);
},
else => {
return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
},
@@ -1582,6 +1586,10 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {
const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr();
return exprIsNarrowStringLiteral(op_expr);
},
.GenericSelectionExprClass => {
const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, expr);
return exprIsNarrowStringLiteral(gen_sel.getResultExpr());
},
else => return false,
}
}
@@ -2726,6 +2734,10 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool {
const opcode = un_op.getOpcode();
return (opcode == .AddrOf or opcode == .Deref) and cIsFunctionDeclRef(un_op.getSubExpr());
},
.GenericSelectionExprClass => {
const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, expr);
return cIsFunctionDeclRef(gen_sel.getResultExpr());
},
else => return false,
}
}

View File

@@ -2445,6 +2445,11 @@ struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClang
return bitcast(casted->getReturnType());
}
const struct ZigClangExpr *ZigClangGenericSelectionExpr_getResultExpr(const struct ZigClangGenericSelectionExpr *self) {
auto casted = reinterpret_cast<const clang::GenericSelectionExpr *>(self);
return reinterpret_cast<const struct ZigClangExpr *>(casted->getResultExpr());
}
bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self) {
auto casted = reinterpret_cast<const clang::FunctionProtoType *>(self);
return casted->isVariadic();

View File

@@ -1116,6 +1116,8 @@ ZIG_EXTERN_C bool ZigClangFunctionType_getNoReturnAttr(const struct ZigClangFunc
ZIG_EXTERN_C enum ZigClangCallingConv ZigClangFunctionType_getCallConv(const struct ZigClangFunctionType *self);
ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionType_getReturnType(const struct ZigClangFunctionType *self);
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangGenericSelectionExpr_getResultExpr(const struct ZigClangGenericSelectionExpr *self);
ZIG_EXTERN_C bool ZigClangFunctionProtoType_isVariadic(const struct ZigClangFunctionProtoType *self);
ZIG_EXTERN_C unsigned ZigClangFunctionProtoType_getNumParams(const struct ZigClangFunctionProtoType *self);
ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionProtoType_getParamType(const struct ZigClangFunctionProtoType *self, unsigned i);

View File

@@ -1187,4 +1187,38 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
cases.add("Generic selections",
\\#include <stdlib.h>
\\#include <string.h>
\\#include <stdint.h>
\\#define my_generic_fn(X) _Generic((X), \
\\ int: abs, \
\\ char *: strlen, \
\\ size_t: malloc, \
\\ default: free \
\\)(X)
\\#define my_generic_val(X) _Generic((X), \
\\ int: 1, \
\\ const char *: "bar" \
\\)
\\int main(void) {
\\ if (my_generic_val(100) != 1) abort();
\\
\\ const char *foo = "foo";
\\ const char *bar = my_generic_val(foo);
\\ if (strcmp(bar, "bar") != 0) abort();
\\
\\ if (my_generic_fn(-42) != 42) abort();
\\ if (my_generic_fn("hello") != 5) abort();
\\
\\ size_t size = 8192;
\\ uint8_t *mem = my_generic_fn(size);
\\ memset(mem, 42, size);
\\ if (mem[size - 1] != 42) abort();
\\ my_generic_fn(mem);
\\
\\ return 0;
\\}
, "");
}