| ... | @@ -710,6 +710,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { | ... | @@ -710,6 +710,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 710 | return addTopLevelDecl(c, fn_name, &proto_node.base); | 710 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 711 | } | 711 | } |
| 712 | | 712 | |
| | 713 | fn transQualTypeMaybeInitialized(rp: RestorePoint, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!*ast.Node { |
| | 714 | return if (decl_init) |init_expr| |
| | 715 | transQualTypeInitialized(rp, qt, init_expr, loc) |
| | 716 | else |
| | 717 | transQualType(rp, qt, loc); |
| | 718 | } |
| 713 | /// if mangled_name is not null, this var decl was declared in a block scope. | 719 | /// if mangled_name is not null, this var decl was declared in a block scope. |
| 714 | fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void { | 720 | fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void { |
| 715 | const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); | 721 | const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); |
| ... | @@ -734,6 +740,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co | ... | @@ -734,6 +740,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 734 | const storage_class = var_decl.getStorageClass(); | 740 | const storage_class = var_decl.getStorageClass(); |
| 735 | const is_const = qual_type.isConstQualified(); | 741 | const is_const = qual_type.isConstQualified(); |
| 736 | const has_init = var_decl.hasInit(); | 742 | const has_init = var_decl.hasInit(); |
| | 743 | const decl_init = var_decl.getInit(); |
| 737 | | 744 | |
| 738 | // In C extern variables with initializers behave like Zig exports. | 745 | // In C extern variables with initializers behave like Zig exports. |
| 739 | // extern int foo = 2; | 746 | // extern int foo = 2; |
| ... | @@ -755,8 +762,9 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co | ... | @@ -755,8 +762,9 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 755 | const name_tok = try appendIdentifier(c, checked_name); | 762 | const name_tok = try appendIdentifier(c, checked_name); |
| 756 | | 763 | |
| 757 | _ = try appendToken(c, .Colon, ":"); | 764 | _ = try appendToken(c, .Colon, ":"); |
| 758 | const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { | 765 | |
| 759 | error.UnsupportedType => { | 766 | const type_node = transQualTypeMaybeInitialized(rp, qual_type, decl_init, var_decl_loc) catch |err| switch (err) { |
| | 767 | error.UnsupportedTranslation, error.UnsupportedType => { |
| 760 | return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{}); | 768 | return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{}); |
| 761 | }, | 769 | }, |
| 762 | error.OutOfMemory => |e| return e, | 770 | error.OutOfMemory => |e| return e, |
| ... | @@ -770,17 +778,22 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co | ... | @@ -770,17 +778,22 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 770 | // with the variable type. | 778 | // with the variable type. |
| 771 | if (has_init) { | 779 | if (has_init) { |
| 772 | eq_tok = try appendToken(c, .Equal, "="); | 780 | eq_tok = try appendToken(c, .Equal, "="); |
| 773 | init_node = if (var_decl.getInit()) |expr| | 781 | if (decl_init) |expr| { |
| 774 | transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { | 782 | const node_or_error = if (expr.getStmtClass() == .StringLiteralClass) |
| | 783 | transStringLiteralAsArray(rp, &c.global_scope.base, @ptrCast(*const clang.StringLiteral, expr), type_node) |
| | 784 | else |
| | 785 | transExprCoercing(rp, scope, expr, .used, .r_value); |
| | 786 | init_node = node_or_error catch |err| switch (err) { |
| 775 | error.UnsupportedTranslation, | 787 | error.UnsupportedTranslation, |
| 776 | error.UnsupportedType, | 788 | error.UnsupportedType, |
| 777 | => { | 789 | => { |
| 778 | return failDecl(c, var_decl_loc, checked_name, "unable to translate initializer", .{}); | 790 | return failDecl(c, var_decl_loc, checked_name, "unable to translate initializer", .{}); |
| 779 | }, | 791 | }, |
| 780 | error.OutOfMemory => |e| return e, | 792 | error.OutOfMemory => |e| return e, |
| 781 | } | 793 | }; |
| 782 | else | 794 | } else { |
| 783 | try transCreateNodeUndefinedLiteral(c); | 795 | init_node = try transCreateNodeUndefinedLiteral(c); |
| | 796 | } |
| 784 | } else if (storage_class != .Extern) { | 797 | } else if (storage_class != .Extern) { |
| 785 | eq_tok = try appendToken(c, .Equal, "="); | 798 | eq_tok = try appendToken(c, .Equal, "="); |
| 786 | // The C language specification states that variables with static or threadlocal | 799 | // The C language specification states that variables with static or threadlocal |
| ... | @@ -1620,6 +1633,7 @@ fn transDeclStmtOne( | ... | @@ -1620,6 +1633,7 @@ fn transDeclStmtOne( |
| 1620 | switch (decl.getKind()) { | 1633 | switch (decl.getKind()) { |
| 1621 | .Var => { | 1634 | .Var => { |
| 1622 | const var_decl = @ptrCast(*const clang.VarDecl, decl); | 1635 | const var_decl = @ptrCast(*const clang.VarDecl, decl); |
| | 1636 | const decl_init = var_decl.getInit(); |
| 1623 | | 1637 | |
| 1624 | const qual_type = var_decl.getTypeSourceInfo_getType(); | 1638 | const qual_type = var_decl.getTypeSourceInfo_getType(); |
| 1625 | const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); | 1639 | const name = try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); |
| ... | @@ -1643,11 +1657,14 @@ fn transDeclStmtOne( | ... | @@ -1643,11 +1657,14 @@ fn transDeclStmtOne( |
| 1643 | | 1657 | |
| 1644 | _ = try appendToken(c, .Colon, ":"); | 1658 | _ = try appendToken(c, .Colon, ":"); |
| 1645 | const loc = decl.getLocation(); | 1659 | const loc = decl.getLocation(); |
| 1646 | const type_node = try transQualType(rp, qual_type, loc); | 1660 | const type_node = try transQualTypeMaybeInitialized(rp, qual_type, decl_init, loc); |
| 1647 | | 1661 | |
| 1648 | const eq_token = try appendToken(c, .Equal, "="); | 1662 | const eq_token = try appendToken(c, .Equal, "="); |
| 1649 | var init_node = if (var_decl.getInit()) |expr| | 1663 | var init_node = if (decl_init) |expr| |
| 1650 | try transExprCoercing(rp, scope, expr, .used, .r_value) | 1664 | if (expr.getStmtClass() == .StringLiteralClass) |
| | 1665 | try transStringLiteralAsArray(rp, scope, @ptrCast(*const clang.StringLiteral, expr), type_node) |
| | 1666 | else |
| | 1667 | try transExprCoercing(rp, scope, expr, .used, .r_value) |
| 1651 | else | 1668 | else |
| 1652 | try transCreateNodeUndefinedLiteral(c); | 1669 | try transCreateNodeUndefinedLiteral(c); |
| 1653 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { | 1670 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { |
| ... | @@ -1740,7 +1757,7 @@ fn transImplicitCastExpr( | ... | @@ -1740,7 +1757,7 @@ fn transImplicitCastExpr( |
| 1740 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); | 1757 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1741 | }, | 1758 | }, |
| 1742 | .ArrayToPointerDecay => { | 1759 | .ArrayToPointerDecay => { |
| 1743 | if (exprIsStringLiteral(sub_expr)) { | 1760 | if (exprIsNarrowStringLiteral(sub_expr)) { |
| 1744 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); | 1761 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1745 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); | 1762 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1746 | } | 1763 | } |
| ... | @@ -1841,17 +1858,20 @@ fn exprIsBooleanType(expr: *const clang.Expr) bool { | ... | @@ -1841,17 +1858,20 @@ fn exprIsBooleanType(expr: *const clang.Expr) bool { |
| 1841 | return qualTypeIsBoolean(expr.getType()); | 1858 | return qualTypeIsBoolean(expr.getType()); |
| 1842 | } | 1859 | } |
| 1843 | | 1860 | |
| 1844 | fn exprIsStringLiteral(expr: *const clang.Expr) bool { | 1861 | fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool { |
| 1845 | switch (expr.getStmtClass()) { | 1862 | switch (expr.getStmtClass()) { |
| 1846 | .StringLiteralClass => return true, | 1863 | .StringLiteralClass => { |
| | 1864 | const string_lit = @ptrCast(*const clang.StringLiteral, expr); |
| | 1865 | return string_lit.getCharByteWidth() == 1; |
| | 1866 | }, |
| 1847 | .PredefinedExprClass => return true, | 1867 | .PredefinedExprClass => return true, |
| 1848 | .UnaryOperatorClass => { | 1868 | .UnaryOperatorClass => { |
| 1849 | const op_expr = @ptrCast(*const clang.UnaryOperator, expr).getSubExpr(); | 1869 | const op_expr = @ptrCast(*const clang.UnaryOperator, expr).getSubExpr(); |
| 1850 | return exprIsStringLiteral(op_expr); | 1870 | return exprIsNarrowStringLiteral(op_expr); |
| 1851 | }, | 1871 | }, |
| 1852 | .ParenExprClass => { | 1872 | .ParenExprClass => { |
| 1853 | const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr(); | 1873 | const op_expr = @ptrCast(*const clang.ParenExpr, expr).getSubExpr(); |
| 1854 | return exprIsStringLiteral(op_expr); | 1874 | return exprIsNarrowStringLiteral(op_expr); |
| 1855 | }, | 1875 | }, |
| 1856 | else => return false, | 1876 | else => return false, |
| 1857 | } | 1877 | } |
| ... | @@ -2049,6 +2069,71 @@ fn transStringLiteral( | ... | @@ -2049,6 +2069,71 @@ fn transStringLiteral( |
| 2049 | } | 2069 | } |
| 2050 | } | 2070 | } |
| 2051 | | 2071 | |
| | 2072 | /// Parse the size of an array back out from an ast Node. |
| | 2073 | fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize { |
| | 2074 | if (node.castTag(.ArrayType)) |array| { |
| | 2075 | if (array.len_expr.castTag(.IntegerLiteral)) |int_lit| { |
| | 2076 | const tok = tokenSlice(c, int_lit.token); |
| | 2077 | return std.fmt.parseUnsigned(usize, tok, 10) catch error.UnsupportedTranslation; |
| | 2078 | } |
| | 2079 | } |
| | 2080 | return error.UnsupportedTranslation; |
| | 2081 | } |
| | 2082 | |
| | 2083 | /// Translate a string literal to an array of integers. Used when an |
| | 2084 | /// array is initialized from a string literal. `target_node` is the |
| | 2085 | /// array being initialized. If the string literal is larger than the |
| | 2086 | /// array, truncate the string. If the array is larger than the string |
| | 2087 | /// literal, pad the array with 0's |
| | 2088 | fn transStringLiteralAsArray( |
| | 2089 | rp: RestorePoint, |
| | 2090 | scope: *Scope, |
| | 2091 | stmt: *const clang.StringLiteral, |
| | 2092 | target_node: *ast.Node, |
| | 2093 | ) TransError!*ast.Node { |
| | 2094 | const array_size = try zigArraySize(rp.c, target_node); |
| | 2095 | const str_length = stmt.getLength(); |
| | 2096 | |
| | 2097 | const expr_base = @ptrCast(*const clang.Expr, stmt); |
| | 2098 | const ty = expr_base.getType().getTypePtr(); |
| | 2099 | const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty); |
| | 2100 | |
| | 2101 | const ty_node = try rp.c.arena.create(ast.Node.ArrayType); |
| | 2102 | const op_token = try appendToken(rp.c, .LBracket, "["); |
| | 2103 | const len_expr = try transCreateNodeInt(rp.c, array_size); |
| | 2104 | _ = try appendToken(rp.c, .RBracket, "]"); |
| | 2105 | |
| | 2106 | ty_node.* = .{ |
| | 2107 | .op_token = op_token, |
| | 2108 | .rhs = try transQualType(rp, const_arr_ty.getElementType(), expr_base.getBeginLoc()), |
| | 2109 | .len_expr = len_expr, |
| | 2110 | }; |
| | 2111 | _ = try appendToken(rp.c, .LBrace, "{"); |
| | 2112 | var init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, array_size); |
| | 2113 | init_node.* = .{ |
| | 2114 | .lhs = &ty_node.base, |
| | 2115 | .rtoken = undefined, |
| | 2116 | .list_len = array_size, |
| | 2117 | }; |
| | 2118 | const init_list = init_node.list(); |
| | 2119 | |
| | 2120 | var i: c_uint = 0; |
| | 2121 | const kind = stmt.getKind(); |
| | 2122 | const narrow = kind == .Ascii or kind == .UTF8; |
| | 2123 | while (i < str_length and i < array_size) : (i += 1) { |
| | 2124 | const code_unit = stmt.getCodeUnit(i); |
| | 2125 | init_list[i] = try transCreateCharLitNode(rp.c, narrow, code_unit); |
| | 2126 | _ = try appendToken(rp.c, .Comma, ","); |
| | 2127 | } |
| | 2128 | while (i < array_size) : (i += 1) { |
| | 2129 | init_list[i] = try transCreateNodeInt(rp.c, 0); |
| | 2130 | _ = try appendToken(rp.c, .Comma, ","); |
| | 2131 | } |
| | 2132 | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| | 2133 | |
| | 2134 | return &init_node.base; |
| | 2135 | } |
| | 2136 | |
| 2052 | fn cIsEnum(qt: clang.QualType) bool { | 2137 | fn cIsEnum(qt: clang.QualType) bool { |
| 2053 | return qt.getCanonicalType().getTypeClass() == .Enum; | 2138 | return qt.getCanonicalType().getTypeClass() == .Enum; |
| 2054 | } | 2139 | } |
| ... | @@ -2343,6 +2428,18 @@ fn transCreateNodeArrayType( | ... | @@ -2343,6 +2428,18 @@ fn transCreateNodeArrayType( |
| 2343 | return &node.base; | 2428 | return &node.base; |
| 2344 | } | 2429 | } |
| 2345 | | 2430 | |
| | 2431 | fn transCreateEmptyArray(rp: RestorePoint, loc: clang.SourceLocation, ty: *const clang.Type) TransError!*ast.Node { |
| | 2432 | const ty_node = try transCreateNodeArrayType(rp, loc, ty, 0); |
| | 2433 | _ = try appendToken(rp.c, .LBrace, "{"); |
| | 2434 | const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 0); |
| | 2435 | filler_init_node.* = .{ |
| | 2436 | .lhs = ty_node, |
| | 2437 | .rtoken = try appendToken(rp.c, .RBrace, "}"), |
| | 2438 | .list_len = 0, |
| | 2439 | }; |
| | 2440 | return &filler_init_node.base; |
| | 2441 | } |
| | 2442 | |
| 2346 | fn transInitListExprArray( | 2443 | fn transInitListExprArray( |
| 2347 | rp: RestorePoint, | 2444 | rp: RestorePoint, |
| 2348 | scope: *Scope, | 2445 | scope: *Scope, |
| ... | @@ -2360,6 +2457,10 @@ fn transInitListExprArray( | ... | @@ -2360,6 +2457,10 @@ fn transInitListExprArray( |
| 2360 | const all_count = size_ap_int.getLimitedValue(math.maxInt(usize)); | 2457 | const all_count = size_ap_int.getLimitedValue(math.maxInt(usize)); |
| 2361 | const leftover_count = all_count - init_count; | 2458 | const leftover_count = all_count - init_count; |
| 2362 | | 2459 | |
| | 2460 | if (all_count == 0) { |
| | 2461 | return transCreateEmptyArray(rp, loc, child_qt.getTypePtr()); |
| | 2462 | } |
| | 2463 | |
| 2363 | var init_node: *ast.Node.ArrayInitializer = undefined; | 2464 | var init_node: *ast.Node.ArrayInitializer = undefined; |
| 2364 | var cat_tok: ast.TokenIndex = undefined; | 2465 | var cat_tok: ast.TokenIndex = undefined; |
| 2365 | if (init_count != 0) { | 2466 | if (init_count != 0) { |
| ... | @@ -2934,6 +3035,21 @@ fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Prede | ... | @@ -2934,6 +3035,21 @@ fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Prede |
| 2934 | return transStringLiteral(rp, scope, expr.getFunctionName(), used); | 3035 | return transStringLiteral(rp, scope, expr.getFunctionName(), used); |
| 2935 | } | 3036 | } |
| 2936 | | 3037 | |
| | 3038 | fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node { |
| | 3039 | const node = try c.arena.create(ast.Node.OneToken); |
| | 3040 | node.* = .{ |
| | 3041 | .base = .{ .tag = .CharLiteral }, |
| | 3042 | .token = undefined, |
| | 3043 | }; |
| | 3044 | if (narrow) { |
| | 3045 | const val_array = [_]u8{@intCast(u8, val)}; |
| | 3046 | node.token = try appendTokenFmt(c, .CharLiteral, "'{}'", .{std.zig.fmtEscapes(&val_array)}); |
| | 3047 | } else { |
| | 3048 | node.token = try appendTokenFmt(c, .CharLiteral, "'\\u{{{x}}}'", .{val}); |
| | 3049 | } |
| | 3050 | return &node.base; |
| | 3051 | } |
| | 3052 | |
| 2937 | fn transCharLiteral( | 3053 | fn transCharLiteral( |
| 2938 | rp: RestorePoint, | 3054 | rp: RestorePoint, |
| 2939 | scope: *Scope, | 3055 | scope: *Scope, |
| ... | @@ -2943,33 +3059,14 @@ fn transCharLiteral( | ... | @@ -2943,33 +3059,14 @@ fn transCharLiteral( |
| 2943 | ) TransError!*ast.Node { | 3059 | ) TransError!*ast.Node { |
| 2944 | const kind = stmt.getKind(); | 3060 | const kind = stmt.getKind(); |
| 2945 | const val = stmt.getValue(); | 3061 | const val = stmt.getValue(); |
| 2946 | const int_lit_node = switch (kind) { | 3062 | const narrow = kind == .Ascii or kind == .UTF8; |
| 2947 | .Ascii, .UTF8 => blk: { | 3063 | // C has a somewhat obscure feature called multi-character character constant |
| 2948 | if (kind == .Ascii) { | 3064 | // e.g. 'abcd' |
| 2949 | // C has a somewhat obscure feature called multi-character character | 3065 | const int_lit_node = if (kind == .Ascii and val > 255) |
| 2950 | // constant | 3066 | try transCreateNodeInt(rp.c, val) |
| 2951 | if (val > 255) | 3067 | else |
| 2952 | break :blk try transCreateNodeInt(rp.c, val); | 3068 | try transCreateCharLitNode(rp.c, narrow, val); |
| 2953 | } | 3069 | |
| 2954 | const val_array = [_]u8 { @intCast(u8, val) }; | | |
| 2955 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{std.zig.fmtEscapes(&val_array)}); | | |
| 2956 | const node = try rp.c.arena.create(ast.Node.OneToken); | | |
| 2957 | node.* = .{ | | |
| 2958 | .base = .{ .tag = .CharLiteral }, | | |
| 2959 | .token = token, | | |
| 2960 | }; | | |
| 2961 | break :blk &node.base; | | |
| 2962 | }, | | |
| 2963 | .Wide, .UTF16, .UTF32 => blk: { | | |
| 2964 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'\\u{{{x}}}'", .{val}); | | |
| 2965 | const node = try rp.c.arena.create(ast.Node.OneToken); | | |
| 2966 | node.* = .{ | | |
| 2967 | .base = .{ .tag = .CharLiteral }, | | |
| 2968 | .token = token, | | |
| 2969 | }; | | |
| 2970 | break :blk &node.base; | | |
| 2971 | }, | | |
| 2972 | }; | | |
| 2973 | if (suppress_as == .no_as) { | 3070 | if (suppress_as == .no_as) { |
| 2974 | return maybeSuppressResult(rp, scope, result_used, int_lit_node); | 3071 | return maybeSuppressResult(rp, scope, result_used, int_lit_node); |
| 2975 | } | 3072 | } |
| ... | @@ -3891,6 +3988,38 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { | ... | @@ -3891,6 +3988,38 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { |
| 3891 | _ = try c.global_scope.sym_table.put(name, decl_node); | 3988 | _ = try c.global_scope.sym_table.put(name, decl_node); |
| 3892 | } | 3989 | } |
| 3893 | | 3990 | |
| | 3991 | /// Translate a qual type for a variable with an initializer. The initializer |
| | 3992 | /// only matters for incomplete arrays, since the size of the array is determined |
| | 3993 | /// by the size of the initializer |
| | 3994 | fn transQualTypeInitialized( |
| | 3995 | rp: RestorePoint, |
| | 3996 | qt: clang.QualType, |
| | 3997 | decl_init: *const clang.Expr, |
| | 3998 | source_loc: clang.SourceLocation, |
| | 3999 | ) TypeError!*ast.Node { |
| | 4000 | const ty = qt.getTypePtr(); |
| | 4001 | if (ty.getTypeClass() == .IncompleteArray) { |
| | 4002 | const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); |
| | 4003 | const elem_ty = incomplete_array_ty.getElementType().getTypePtr(); |
| | 4004 | |
| | 4005 | switch (decl_init.getStmtClass()) { |
| | 4006 | .StringLiteralClass => { |
| | 4007 | const string_lit = @ptrCast(*const clang.StringLiteral, decl_init); |
| | 4008 | const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator |
| | 4009 | const array_size = @intCast(usize, string_lit_size); |
| | 4010 | return transCreateNodeArrayType(rp, source_loc, elem_ty, array_size); |
| | 4011 | }, |
| | 4012 | .InitListExprClass => { |
| | 4013 | const init_expr = @ptrCast(*const clang.InitListExpr, decl_init); |
| | 4014 | const size = init_expr.getNumInits(); |
| | 4015 | return transCreateNodeArrayType(rp, source_loc, elem_ty, size); |
| | 4016 | }, |
| | 4017 | else => {}, |
| | 4018 | } |
| | 4019 | } |
| | 4020 | return transQualType(rp, qt, source_loc); |
| | 4021 | } |
| | 4022 | |
| 3894 | fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node { | 4023 | fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node { |
| 3895 | return transType(rp, qt.getTypePtr(), source_loc); | 4024 | return transType(rp, qt.getTypePtr(), source_loc); |
| 3896 | } | 4025 | } |