commit 9e8943736e34d28d1ea62229d6ca708303cd0eba (tree)
parent d91605e27eb25ae9175f6e92d5f9f9db1ce6a714
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sat, 27 Feb 2021 02:25:58 -0700
Merge remote-tracking branch 'origin/master' into llvm12
Diffstat:
8 files changed, 111 insertions(+), 9 deletions(-)
diff --git a/lib/std/ascii.zig b/lib/std/ascii.zig
@@ -379,3 +379,23 @@ test "indexOfIgnoreCase" {
std.testing.expect(indexOfIgnoreCase("FOO foo", "fOo").? == 0);
}
+
+/// Compares two slices of numbers lexicographically. O(n).
+pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {
+ const n = std.math.min(lhs.len, rhs.len);
+ var i: usize = 0;
+ while (i < n) : (i += 1) {
+ switch (std.math.order(toLower(lhs[i]), toLower(rhs[i]))) {
+ .eq => continue,
+ .lt => return .lt,
+ .gt => return .gt,
+ }
+ }
+ return std.math.order(lhs.len, rhs.len);
+}
+
+/// Returns true if lhs < rhs, false otherwise
+/// TODO rename "IgnoreCase" to "Insensitive" in this entire file.
+pub fn lessThanIgnoreCase(lhs: []const u8, rhs: []const u8) bool {
+ return orderIgnoreCase(lhs, rhs) == .lt;
+}
diff --git a/lib/std/zig/fmt.zig b/lib/std/zig/fmt.zig
@@ -12,7 +12,7 @@ pub fn formatId(
return writer.writeAll(bytes);
}
try writer.writeAll("@\"");
- try formatEscapes(bytes, fmt, options, writer);
+ try formatEscapes(bytes, "", options, writer);
try writer.writeByte('"');
}
@@ -32,6 +32,9 @@ pub fn isValidId(bytes: []const u8) bool {
return std.zig.Token.getKeyword(bytes) == null;
}
+/// Print the string as escaped contents of a double quoted or single-quoted string.
+/// Format `{}` treats contents as a double-quoted string.
+/// Format `{'}` treats contents as a single-quoted string.
pub fn formatEscapes(
bytes: []const u8,
comptime fmt: []const u8,
@@ -43,8 +46,24 @@ pub fn formatEscapes(
'\r' => try writer.writeAll("\\r"),
'\t' => try writer.writeAll("\\t"),
'\\' => try writer.writeAll("\\\\"),
- '"' => try writer.writeAll("\\\""),
- '\'' => try writer.writeAll("\\'"),
+ '"' => {
+ if (fmt.len == 1 and fmt[0] == '\'') {
+ try writer.writeByte('"');
+ } else if (fmt.len == 0) {
+ try writer.writeAll("\\\"");
+ } else {
+ @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
+ }
+ },
+ '\'' => {
+ if (fmt.len == 1 and fmt[0] == '\'') {
+ try writer.writeAll("\\'");
+ } else if (fmt.len == 0) {
+ try writer.writeByte('\'');
+ } else {
+ @compileError("expected {} or {'}, found {" ++ fmt ++ "}");
+ }
+ },
' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
// Use hex escapes for rest any unprintable characters.
else => {
@@ -54,7 +73,10 @@ pub fn formatEscapes(
};
}
-/// Return a Formatter for Zig Escapes
+/// Return a Formatter for Zig Escapes of a double quoted string.
+/// The format specifier must be one of:
+/// * `{}` treats contents as a double-quoted string.
+/// * `{'}` treats contents as a single-quoted string.
pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(formatEscapes) {
return .{ .data = bytes };
}
@@ -67,6 +89,9 @@ test "escape invalid identifiers" {
try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
try expectFmt(
- \\" \\ hi \x07 \x11 \" derp \'"
+ \\" \\ hi \x07 \x11 " derp \'"
+ , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
+ try expectFmt(
+ \\" \\ hi \x07 \x11 \" derp '"
, "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
}
diff --git a/src/clang.zig b/src/clang.zig
@@ -583,6 +583,16 @@ pub const MacroQualifiedType = opaque {
extern fn ZigClangMacroQualifiedType_getModifiedType(*const MacroQualifiedType) QualType;
};
+pub const TypeOfType = opaque {
+ pub const getUnderlyingType = ZigClangTypeOfType_getUnderlyingType;
+ extern fn ZigClangTypeOfType_getUnderlyingType(*const TypeOfType) QualType;
+};
+
+pub const TypeOfExprType = opaque {
+ pub const getUnderlyingExpr = ZigClangTypeOfExprType_getUnderlyingExpr;
+ extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr;
+};
+
pub const MemberExpr = opaque {
pub const getBase = ZigClangMemberExpr_getBase;
extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr;
diff --git a/src/translate_c.zig b/src/translate_c.zig
@@ -2475,7 +2475,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined
fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node {
return Tag.char_literal.create(c.arena, if (narrow)
- try std.fmt.allocPrint(c.arena, "'{s}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})})
+ try std.fmt.allocPrint(c.arena, "'{'}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})})
else
try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val}));
}
@@ -3827,6 +3827,20 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan
const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty);
return transQualType(c, scope, macroqualified_ty.getModifiedType(), source_loc);
},
+ .TypeOf => {
+ const typeof_ty = @ptrCast(*const clang.TypeOfType, ty);
+ return transQualType(c, scope, typeof_ty.getUnderlyingType(), source_loc);
+ },
+ .TypeOfExpr => {
+ const typeofexpr_ty = @ptrCast(*const clang.TypeOfExprType, ty);
+ const underlying_expr = transExpr(c, scope, typeofexpr_ty.getUnderlyingExpr(), .used) catch |err| switch (err) {
+ error.UnsupportedTranslation => {
+ return fail(c, error.UnsupportedType, source_loc, "unsupported underlying expression for TypeOfExpr", .{});
+ },
+ else => |e| return e,
+ };
+ return Tag.typeof.create(c.arena, underlying_expr);
+ },
else => {
const type_name = c.str(ty.getTypeClassName());
return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig
@@ -995,7 +995,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
const compile_error_tok = try c.addToken(.builtin, "@compileError");
_ = try c.addToken(.l_paren, "(");
- const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.mangled)});
+ const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(payload.mangled)});
const err_msg = try c.addNode(.{
.tag = .string_literal,
.main_token = err_msg_tok,
@@ -2265,7 +2265,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
_ = try c.addToken(.l_paren, "(");
const res = try c.addNode(.{
.tag = .string_literal,
- .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
+ .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}),
.data = undefined,
});
_ = try c.addToken(.r_paren, ")");
@@ -2347,7 +2347,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
_ = try c.addToken(.l_paren, "(");
const res = try c.addNode(.{
.tag = .string_literal,
- .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
+ .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}),
.data = undefined,
});
_ = try c.addToken(.r_paren, ")");
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
@@ -2613,6 +2613,16 @@ struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct
return bitcast(casted->getModifiedType());
}
+struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const struct ZigClangTypeOfType *self) {
+ auto casted = reinterpret_cast<const clang::TypeOfType *>(self);
+ return bitcast(casted->getUnderlyingType());
+}
+
+const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *self) {
+ auto casted = reinterpret_cast<const clang::TypeOfExprType *>(self);
+ return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr());
+}
+
struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {
auto casted = reinterpret_cast<const clang::ElaboratedType *>(self);
return bitcast(casted->getNamedType());
diff --git a/src/zig_clang.h b/src/zig_clang.h
@@ -1164,6 +1164,10 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangAttributedType_getEquivalentType(co
ZIG_EXTERN_C struct ZigClangQualType ZigClangMacroQualifiedType_getModifiedType(const struct ZigClangMacroQualifiedType *);
+ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const struct ZigClangTypeOfType *);
+
+ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);
+
ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);
ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);
diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig
@@ -1054,4 +1054,23 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
+
+ cases.add("typeof operator",
+ \\#include <stdlib.h>
+ \\static int FOO = 42;
+ \\typedef typeof(FOO) foo_type;
+ \\typeof(foo_type) myfunc(typeof(FOO) x) { return (typeof(FOO)) x; }
+ \\int main(void) {
+ \\ int x = FOO;
+ \\ typeof(x) y = x;
+ \\ foo_type z = y;
+ \\ if (x != y) abort();
+ \\ if (myfunc(z) != x) abort();
+ \\
+ \\ const char *my_string = "bar";
+ \\ typeof (typeof (my_string)[4]) string_arr = {"a","b","c","d"};
+ \\ if (string_arr[0][0] != 'a' || string_arr[3][0] != 'd') abort();
+ \\ return 0;
+ \\}
+ , "");
}