Commit 42ee364e7b

kcbanner <kcbanner@gmail.com>
2023-04-22 08:11:16
translate-c: support brace-enclosed string initializers (c++20 9.4.2.1)
1 parent bc8e1e1
src/clang.zig
@@ -460,6 +460,9 @@ pub const Expr = opaque {
 
     pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
     extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstantExprKind, *const ASTContext) bool;
+
+    pub const castToStringLiteral = ZigClangExpr_castToStringLiteral;
+    extern fn ZigClangExpr_castToStringLiteral(*const Expr) ?*const StringLiteral;
 };
 
 pub const FieldDecl = opaque {
@@ -1053,6 +1056,12 @@ pub const InitListExpr = opaque {
     pub const getArrayFiller = ZigClangInitListExpr_getArrayFiller;
     extern fn ZigClangInitListExpr_getArrayFiller(*const InitListExpr) *const Expr;
 
+    pub const hasArrayFiller = ZigClangInitListExpr_hasArrayFiller;
+    extern fn ZigClangInitListExpr_hasArrayFiller(*const InitListExpr) bool;
+
+    pub const isStringLiteralInit = ZigClangInitListExpr_isStringLiteralInit;
+    extern fn ZigClangInitListExpr_isStringLiteralInit(*const InitListExpr) bool;
+
     pub const getNumInits = ZigClangInitListExpr_getNumInits;
     extern fn ZigClangInitListExpr_getNumInits(*const InitListExpr) c_uint;
 
src/translate_c.zig
@@ -2697,6 +2697,13 @@ fn transInitListExprArray(
         return Tag.empty_array.create(c.arena, child_type);
     }
 
+    if (expr.isStringLiteralInit()) {
+        assert(init_count == 1);
+        const init_expr = expr.getInit(0);
+        const string_literal = init_expr.castToStringLiteral().?;
+        return try transStringLiteral(c, scope, string_literal, .used);
+    }
+
     const init_node = if (init_count != 0) blk: {
         const init_list = try c.arena.alloc(Node, init_count);
 
@@ -2714,6 +2721,7 @@ fn transInitListExprArray(
         break :blk init_node;
     } else null;
 
+    assert(expr.hasArrayFiller());
     const filler_val_expr = expr.getArrayFiller();
     const filler_node = try Tag.array_filler.create(c.arena, .{
         .type = child_type,
@@ -4176,6 +4184,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
     try c.global_scope.nodes.append(decl_node);
 }
 
+fn transQualTypeInitializedStringLiteral(c: *Context, elem_ty: Node, string_lit: *const clang.StringLiteral) TypeError!Node {
+    const string_lit_size = string_lit.getLength();
+    const array_size = @intCast(usize, string_lit_size);
+
+    // incomplete array initialized with empty string, will be translated as [1]T{0}
+    // see https://github.com/ziglang/zig/issues/8256
+    if (array_size == 0) return Tag.array_type.create(c.arena, .{ .len = 1, .elem_type = elem_ty });
+
+    return Tag.null_sentinel_array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
+}
+
 /// Translate a qualtype for a variable with an initializer. This only matters
 /// for incomplete arrays, since the initializer determines the size of the array.
 fn transQualTypeInitialized(
@@ -4193,18 +4212,18 @@ fn transQualTypeInitialized(
         switch (decl_init.getStmtClass()) {
             .StringLiteralClass => {
                 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
-                const string_lit_size = string_lit.getLength();
-                const array_size = @intCast(usize, string_lit_size);
-
-                // incomplete array initialized with empty string, will be translated as [1]T{0}
-                // see https://github.com/ziglang/zig/issues/8256
-                if (array_size == 0) return Tag.array_type.create(c.arena, .{ .len = 1, .elem_type = elem_ty });
-
-                return Tag.null_sentinel_array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
+                return transQualTypeInitializedStringLiteral(c, elem_ty, string_lit);
             },
             .InitListExprClass => {
                 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
                 const size = init_expr.getNumInits();
+
+                if (init_expr.isStringLiteralInit()) {
+                    assert(size == 1);
+                    const string_lit = init_expr.getInit(0).castToStringLiteral().?;
+                    return transQualTypeInitializedStringLiteral(c, elem_ty, string_lit);
+                }
+
                 return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty });
             },
             else => {},
src/zig_clang.cpp
@@ -2382,6 +2382,12 @@ bool ZigClangExpr_EvaluateAsConstantExpr(const ZigClangExpr *self, ZigClangExprE
     return true;
 }
 
+const ZigClangStringLiteral *ZigClangExpr_castToStringLiteral(const struct ZigClangExpr *self) {
+    auto casted_self = reinterpret_cast<const clang::Expr *>(self);
+    auto cast = clang::dyn_cast<const clang::StringLiteral>(casted_self);
+    return reinterpret_cast<const ZigClangStringLiteral *>(cast);
+}
+
 const ZigClangExpr *ZigClangInitListExpr_getInit(const ZigClangInitListExpr *self, unsigned i) {
     auto casted = reinterpret_cast<const clang::InitListExpr *>(self);
     const clang::Expr *result = casted->getInit(i);
@@ -2394,6 +2400,16 @@ const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListEx
     return reinterpret_cast<const ZigClangExpr *>(result);
 }
 
+bool ZigClangInitListExpr_hasArrayFiller(const ZigClangInitListExpr *self) {
+    auto casted = reinterpret_cast<const clang::InitListExpr *>(self);
+    return casted->hasArrayFiller();
+}
+
+bool ZigClangInitListExpr_isStringLiteralInit(const ZigClangInitListExpr *self) {
+    auto casted = reinterpret_cast<const clang::InitListExpr *>(self);
+    return casted->isStringLiteralInit();
+}
+
 const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self) {
     auto casted = reinterpret_cast<const clang::InitListExpr *>(self);
     const clang::FieldDecl *result = casted->getInitializedFieldInUnion();
src/zig_clang.h
@@ -1220,9 +1220,12 @@ ZIG_EXTERN_C bool ZigClangExpr_EvaluateAsFloat(const struct ZigClangExpr *self,
         ZigClangAPFloat **result, const struct ZigClangASTContext *ctx);
 ZIG_EXTERN_C bool ZigClangExpr_EvaluateAsConstantExpr(const struct ZigClangExpr *,
         struct ZigClangExprEvalResult *, ZigClangExpr_ConstantExprKind, const struct ZigClangASTContext *);
+ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangExpr_castToStringLiteral(const struct ZigClangExpr *self);
 
 ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getInit(const ZigClangInitListExpr *, unsigned);
 ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListExpr *);
+ZIG_EXTERN_C bool ZigClangInitListExpr_hasArrayFiller(const ZigClangInitListExpr *);
+ZIG_EXTERN_C bool ZigClangInitListExpr_isStringLiteralInit(const ZigClangInitListExpr *);
 ZIG_EXTERN_C unsigned ZigClangInitListExpr_getNumInits(const ZigClangInitListExpr *);
 ZIG_EXTERN_C const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self);
 
test/translate_c.zig
@@ -3956,4 +3956,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    .name = "foo",
         \\});
     });
+
+    cases.add("string array initializer",
+        \\static const char foo[] = {"bar"};
+    , &[_][]const u8{
+        \\pub const foo: [3:0]u8 = "bar";
+    });
 }