| ... | @@ -965,9 +965,9 @@ pub const DeclGen = struct { | ... | @@ -965,9 +965,9 @@ pub const DeclGen = struct { |
| 965 | .Array, .Vector => { | 965 | .Array, .Vector => { |
| 966 | const ai = ty.arrayInfo(mod); | 966 | const ai = ty.arrayInfo(mod); |
| 967 | if (ai.elem_type.eql(Type.u8, mod)) { | 967 | if (ai.elem_type.eql(Type.u8, mod)) { |
| 968 | var literal = stringLiteral(writer); | | |
| 969 | try literal.start(); | | |
| 970 | const c_len = ty.arrayLenIncludingSentinel(mod); | 968 | const c_len = ty.arrayLenIncludingSentinel(mod); |
| | 969 | var literal = stringLiteral(writer, c_len); |
| | 970 | try literal.start(); |
| 971 | var index: u64 = 0; | 971 | var index: u64 = 0; |
| 972 | while (index < c_len) : (index += 1) | 972 | while (index < c_len) : (index += 1) |
| 973 | try literal.writeChar(0xaa); | 973 | try literal.writeChar(0xaa); |
| ... | @@ -1290,46 +1290,24 @@ pub const DeclGen = struct { | ... | @@ -1290,46 +1290,24 @@ pub const DeclGen = struct { |
| 1290 | } | 1290 | } |
| 1291 | // Fall back to generic implementation. | 1291 | // Fall back to generic implementation. |
| 1292 | | 1292 | |
| 1293 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | | |
| 1294 | const max_string_initializer_len = 65535; | | |
| 1295 | | | |
| 1296 | const ai = ty.arrayInfo(mod); | 1293 | const ai = ty.arrayInfo(mod); |
| 1297 | if (ai.elem_type.eql(Type.u8, mod)) { | 1294 | if (ai.elem_type.eql(Type.u8, mod)) { |
| 1298 | if (ai.len <= max_string_initializer_len) { | 1295 | var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(mod)); |
| 1299 | var literal = stringLiteral(writer); | 1296 | try literal.start(); |
| 1300 | try literal.start(); | 1297 | var index: usize = 0; |
| 1301 | var index: usize = 0; | 1298 | while (index < ai.len) : (index += 1) { |
| 1302 | while (index < ai.len) : (index += 1) { | 1299 | const elem_val = try val.elemValue(mod, index); |
| 1303 | const elem_val = try val.elemValue(mod, index); | 1300 | const elem_val_u8: u8 = if (elem_val.isUndef(mod)) |
| 1304 | const elem_val_u8: u8 = if (elem_val.isUndef(mod)) | 1301 | undefPattern(u8) |
| 1305 | undefPattern(u8) | 1302 | else |
| 1306 | else | 1303 | @intCast(elem_val.toUnsignedInt(mod)); |
| 1307 | @intCast(elem_val.toUnsignedInt(mod)); | 1304 | try literal.writeChar(elem_val_u8); |
| 1308 | try literal.writeChar(elem_val_u8); | | |
| 1309 | } | | |
| 1310 | if (ai.sentinel) |s| { | | |
| 1311 | const s_u8: u8 = @intCast(s.toUnsignedInt(mod)); | | |
| 1312 | if (s_u8 != 0) try literal.writeChar(s_u8); | | |
| 1313 | } | | |
| 1314 | try literal.end(); | | |
| 1315 | } else { | | |
| 1316 | try writer.writeByte('{'); | | |
| 1317 | var index: usize = 0; | | |
| 1318 | while (index < ai.len) : (index += 1) { | | |
| 1319 | if (index != 0) try writer.writeByte(','); | | |
| 1320 | const elem_val = try val.elemValue(mod, index); | | |
| 1321 | const elem_val_u8: u8 = if (elem_val.isUndef(mod)) | | |
| 1322 | undefPattern(u8) | | |
| 1323 | else | | |
| 1324 | @intCast(elem_val.toUnsignedInt(mod)); | | |
| 1325 | try writer.print("'\\x{x}'", .{elem_val_u8}); | | |
| 1326 | } | | |
| 1327 | if (ai.sentinel) |s| { | | |
| 1328 | if (index != 0) try writer.writeByte(','); | | |
| 1329 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | | |
| 1330 | } | | |
| 1331 | try writer.writeByte('}'); | | |
| 1332 | } | 1305 | } |
| | 1306 | if (ai.sentinel) |s| { |
| | 1307 | const s_u8: u8 = @intCast(s.toUnsignedInt(mod)); |
| | 1308 | if (s_u8 != 0) try literal.writeChar(s_u8); |
| | 1309 | } |
| | 1310 | try literal.end(); |
| 1333 | } else { | 1311 | } else { |
| 1334 | try writer.writeByte('{'); | 1312 | try writer.writeByte('{'); |
| 1335 | var index: usize = 0; | 1313 | var index: usize = 0; |
| ... | @@ -7660,11 +7638,17 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 { | ... | @@ -7660,11 +7638,17 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 { |
| 7660 | } | 7638 | } |
| 7661 | | 7639 | |
| 7662 | fn StringLiteral(comptime WriterType: type) type { | 7640 | fn StringLiteral(comptime WriterType: type) type { |
| | 7641 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal, |
| | 7642 | // regardless of the length of the string literal initializing it. Array initializer syntax is |
| | 7643 | // used instead. |
| | 7644 | const max_string_initializer_len = 65535; |
| | 7645 | |
| 7663 | // MSVC has a length limit of 16380 per string literal (before concatenation) | 7646 | // MSVC has a length limit of 16380 per string literal (before concatenation) |
| 7664 | const max_char_len = 4; | 7647 | const max_char_len = 4; |
| 7665 | const max_len = 16380 - max_char_len; | 7648 | const max_literal_len = 16380 - max_char_len; |
| 7666 | | 7649 | |
| 7667 | return struct { | 7650 | return struct { |
| | 7651 | len: u64, |
| 7668 | cur_len: u64 = 0, | 7652 | cur_len: u64 = 0, |
| 7669 | counting_writer: std.io.CountingWriter(WriterType), | 7653 | counting_writer: std.io.CountingWriter(WriterType), |
| 7670 | | 7654 | |
| ... | @@ -7674,12 +7658,20 @@ fn StringLiteral(comptime WriterType: type) type { | ... | @@ -7674,12 +7658,20 @@ fn StringLiteral(comptime WriterType: type) type { |
| 7674 | | 7658 | |
| 7675 | pub fn start(self: *Self) Error!void { | 7659 | pub fn start(self: *Self) Error!void { |
| 7676 | const writer = self.counting_writer.writer(); | 7660 | const writer = self.counting_writer.writer(); |
| 7677 | try writer.writeByte('\"'); | 7661 | if (self.len <= max_string_initializer_len) { |
| | 7662 | try writer.writeByte('\"'); |
| | 7663 | } else { |
| | 7664 | try writer.writeByte('{'); |
| | 7665 | } |
| 7678 | } | 7666 | } |
| 7679 | | 7667 | |
| 7680 | pub fn end(self: *Self) Error!void { | 7668 | pub fn end(self: *Self) Error!void { |
| 7681 | const writer = self.counting_writer.writer(); | 7669 | const writer = self.counting_writer.writer(); |
| 7682 | try writer.writeByte('\"'); | 7670 | if (self.len <= max_string_initializer_len) { |
| | 7671 | try writer.writeByte('\"'); |
| | 7672 | } else { |
| | 7673 | try writer.writeByte('}'); |
| | 7674 | } |
| 7683 | } | 7675 | } |
| 7684 | | 7676 | |
| 7685 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { | 7677 | fn writeStringLiteralChar(writer: anytype, c: u8) !void { |
| ... | @@ -7701,24 +7693,34 @@ fn StringLiteral(comptime WriterType: type) type { | ... | @@ -7701,24 +7693,34 @@ fn StringLiteral(comptime WriterType: type) type { |
| 7701 | | 7693 | |
| 7702 | pub fn writeChar(self: *Self, c: u8) Error!void { | 7694 | pub fn writeChar(self: *Self, c: u8) Error!void { |
| 7703 | const writer = self.counting_writer.writer(); | 7695 | const writer = self.counting_writer.writer(); |
| | 7696 | if (self.len <= max_string_initializer_len) { |
| | 7697 | if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) |
| | 7698 | try writer.writeAll("\"\""); |
| 7704 | | 7699 | |
| 7705 | if (self.cur_len == 0 and self.counting_writer.bytes_written > 1) | 7700 | const len = self.counting_writer.bytes_written; |
| 7706 | try writer.writeAll("\"\""); | 7701 | try writeStringLiteralChar(writer, c); |
| 7707 | | 7702 | |
| 7708 | const len = self.counting_writer.bytes_written; | 7703 | const char_length = self.counting_writer.bytes_written - len; |
| 7709 | try writeStringLiteralChar(writer, c); | 7704 | assert(char_length <= max_char_len); |
| | 7705 | self.cur_len += char_length; |
| 7710 | | 7706 | |
| 7711 | const char_length = self.counting_writer.bytes_written - len; | 7707 | if (self.cur_len >= max_literal_len) self.cur_len = 0; |
| 7712 | assert(char_length <= max_char_len); | 7708 | } else { |
| 7713 | self.cur_len += char_length; | 7709 | if (self.counting_writer.bytes_written > 1) try writer.writeByte(','); |
| 7714 | | 7710 | try writer.print("'\\x{x}'", .{c}); |
| 7715 | if (self.cur_len >= max_len) self.cur_len = 0; | 7711 | } |
| 7716 | } | 7712 | } |
| 7717 | }; | 7713 | }; |
| 7718 | } | 7714 | } |
| 7719 | | 7715 | |
| 7720 | fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) { | 7716 | fn stringLiteral( |
| 7721 | return .{ .counting_writer = std.io.countingWriter(child_stream) }; | 7717 | child_stream: anytype, |
| | 7718 | len: u64, |
| | 7719 | ) StringLiteral(@TypeOf(child_stream)) { |
| | 7720 | return .{ |
| | 7721 | .len = len, |
| | 7722 | .counting_writer = std.io.countingWriter(child_stream), |
| | 7723 | }; |
| 7722 | } | 7724 | } |
| 7723 | | 7725 | |
| 7724 | const FormatStringContext = struct { str: []const u8, sentinel: ?u8 }; | 7726 | const FormatStringContext = struct { str: []const u8, sentinel: ?u8 }; |
| ... | @@ -7730,7 +7732,7 @@ fn formatStringLiteral( | ... | @@ -7730,7 +7732,7 @@ fn formatStringLiteral( |
| 7730 | ) @TypeOf(writer).Error!void { | 7732 | ) @TypeOf(writer).Error!void { |
| 7731 | if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); | 7733 | if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); |
| 7732 | | 7734 | |
| 7733 | var literal = stringLiteral(writer); | 7735 | var literal = stringLiteral(writer, data.str.len + @intFromBool(data.sentinel != null)); |
| 7734 | try literal.start(); | 7736 | try literal.start(); |
| 7735 | for (data.str) |c| try literal.writeChar(c); | 7737 | for (data.str) |c| try literal.writeChar(c); |
| 7736 | if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel); | 7738 | if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel); |