mirror of
https://github.com/ziglang/zig.git
synced 2026-02-10 03:20:58 +00:00
Merge pull request #13806 from Vexu/stage2-fixes
misc fixes and improvements
This commit is contained in:
commit
d69e97ae16
@ -3,7 +3,9 @@ const divc3 = @import("./divc3.zig");
|
||||
const Complex = @import("./mulc3.zig").Complex;
|
||||
|
||||
comptime {
|
||||
@export(__divdc3, .{ .name = "__divdc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__divdc3, .{ .name = "__divdc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __divdc3(a: f64, b: f64, c: f64, d: f64) callconv(.C) Complex(f64) {
|
||||
|
||||
@ -3,7 +3,9 @@ const divc3 = @import("./divc3.zig");
|
||||
const Complex = @import("./mulc3.zig").Complex;
|
||||
|
||||
comptime {
|
||||
@export(__divhc3, .{ .name = "__divhc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__divhc3, .{ .name = "__divhc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __divhc3(a: f16, b: f16, c: f16, d: f16) callconv(.C) Complex(f16) {
|
||||
|
||||
@ -3,7 +3,9 @@ const divc3 = @import("./divc3.zig");
|
||||
const Complex = @import("./mulc3.zig").Complex;
|
||||
|
||||
comptime {
|
||||
@export(__divsc3, .{ .name = "__divsc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__divsc3, .{ .name = "__divsc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __divsc3(a: f32, b: f32, c: f32, d: f32) callconv(.C) Complex(f32) {
|
||||
|
||||
@ -3,7 +3,9 @@ const divc3 = @import("./divc3.zig");
|
||||
const Complex = @import("./mulc3.zig").Complex;
|
||||
|
||||
comptime {
|
||||
@export(__divtc3, .{ .name = "__divtc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__divtc3, .{ .name = "__divtc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __divtc3(a: f128, b: f128, c: f128, d: f128) callconv(.C) Complex(f128) {
|
||||
|
||||
@ -3,7 +3,9 @@ const divc3 = @import("./divc3.zig");
|
||||
const Complex = @import("./mulc3.zig").Complex;
|
||||
|
||||
comptime {
|
||||
@export(__divxc3, .{ .name = "__divxc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__divxc3, .{ .name = "__divxc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __divxc3(a: f80, b: f80, c: f80, d: f80) callconv(.C) Complex(f80) {
|
||||
|
||||
@ -4,7 +4,9 @@ const mulc3 = @import("./mulc3.zig");
|
||||
pub const panic = common.panic;
|
||||
|
||||
comptime {
|
||||
@export(__muldc3, .{ .name = "__muldc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__muldc3, .{ .name = "__muldc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __muldc3(a: f64, b: f64, c: f64, d: f64) callconv(.C) mulc3.Complex(f64) {
|
||||
|
||||
@ -4,7 +4,9 @@ const mulc3 = @import("./mulc3.zig");
|
||||
pub const panic = common.panic;
|
||||
|
||||
comptime {
|
||||
@export(__mulhc3, .{ .name = "__mulhc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__mulhc3, .{ .name = "__mulhc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __mulhc3(a: f16, b: f16, c: f16, d: f16) callconv(.C) mulc3.Complex(f16) {
|
||||
|
||||
@ -4,7 +4,9 @@ const mulc3 = @import("./mulc3.zig");
|
||||
pub const panic = common.panic;
|
||||
|
||||
comptime {
|
||||
@export(__mulsc3, .{ .name = "__mulsc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__mulsc3, .{ .name = "__mulsc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __mulsc3(a: f32, b: f32, c: f32, d: f32) callconv(.C) mulc3.Complex(f32) {
|
||||
|
||||
@ -4,7 +4,9 @@ const mulc3 = @import("./mulc3.zig");
|
||||
pub const panic = common.panic;
|
||||
|
||||
comptime {
|
||||
@export(__multc3, .{ .name = "__multc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__multc3, .{ .name = "__multc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __multc3(a: f128, b: f128, c: f128, d: f128) callconv(.C) mulc3.Complex(f128) {
|
||||
|
||||
@ -4,7 +4,9 @@ const mulc3 = @import("./mulc3.zig");
|
||||
pub const panic = common.panic;
|
||||
|
||||
comptime {
|
||||
@export(__mulxc3, .{ .name = "__mulxc3", .linkage = common.linkage });
|
||||
if (@import("builtin").zig_backend != .stage2_c) {
|
||||
@export(__mulxc3, .{ .name = "__mulxc3", .linkage = common.linkage });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __mulxc3(a: f80, b: f80, c: f80, d: f80) callconv(.C) mulc3.Complex(f80) {
|
||||
|
||||
@ -177,7 +177,7 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void {
|
||||
.Float,
|
||||
.Null,
|
||||
=> try out.print("{any}", .{val}),
|
||||
else => @compileError(comptime std.fmt.comptimePrint("`{s}` are not yet supported as build options", .{@tagName(@typeInfo(T))})),
|
||||
else => @compileError(std.fmt.comptimePrint("`{s}` are not yet supported as build options", .{@tagName(@typeInfo(T))})),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ pub fn format(
|
||||
switch (missing_count) {
|
||||
0 => unreachable,
|
||||
1 => @compileError("unused argument in '" ++ fmt ++ "'"),
|
||||
else => @compileError((comptime comptimePrint("{d}", .{missing_count})) ++ " unused arguments in '" ++ fmt ++ "'"),
|
||||
else => @compileError(comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -765,7 +765,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
|
||||
}
|
||||
const expected_args_tuple_len = fn_args_fields.len - 1;
|
||||
if (extra_args.len != expected_args_tuple_len) {
|
||||
@compileError("The provided function expects " ++ (comptime std.fmt.comptimePrint("{d}", .{expected_args_tuple_len})) ++ " extra arguments, but the provided tuple contains " ++ (comptime std.fmt.comptimePrint("{d}", .{extra_args.len})));
|
||||
@compileError("The provided function expects " ++ std.fmt.comptimePrint("{d}", .{expected_args_tuple_len}) ++ " extra arguments, but the provided tuple contains " ++ std.fmt.comptimePrint("{d}", .{extra_args.len}));
|
||||
}
|
||||
|
||||
// Setup the tuple that will actually be used with @call (we'll need to insert
|
||||
|
||||
@ -425,7 +425,16 @@ pub const Tokenizer = struct {
|
||||
const c = self.buffer[self.index];
|
||||
switch (state) {
|
||||
.start => switch (c) {
|
||||
0 => break,
|
||||
0 => {
|
||||
if (self.index != self.buffer.len) {
|
||||
result.tag = .invalid;
|
||||
result.loc.start = self.index;
|
||||
self.index += 1;
|
||||
result.loc.end = self.index;
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
},
|
||||
' ', '\n', '\t', '\r' => {
|
||||
result.loc.start = self.index + 1;
|
||||
},
|
||||
@ -1851,6 +1860,13 @@ test "saturating operators" {
|
||||
try testTokenize("-|=", &.{.minus_pipe_equal});
|
||||
}
|
||||
|
||||
test "null byte before eof" {
|
||||
try testTokenize("123 \x00 456", &.{ .number_literal, .invalid, .number_literal });
|
||||
try testTokenize("//\x00", &.{.invalid});
|
||||
try testTokenize("\\\\\x00", &.{ .multiline_string_literal_line, .invalid });
|
||||
try testTokenize("\x00", &.{.invalid});
|
||||
}
|
||||
|
||||
fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
|
||||
var tokenizer = Tokenizer.init(source);
|
||||
for (expected_token_tags) |expected_token_tag| {
|
||||
|
||||
@ -8455,8 +8455,12 @@ fn simpleUnOp(
|
||||
operand_node: Ast.Node.Index,
|
||||
tag: Zir.Inst.Tag,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const prev_force_comptime = gz.force_comptime;
|
||||
defer gz.force_comptime = prev_force_comptime;
|
||||
|
||||
switch (tag) {
|
||||
.tag_name, .error_name, .ptr_to_int => try emitDbgNode(gz, node),
|
||||
.compile_error => gz.force_comptime = true,
|
||||
else => {},
|
||||
}
|
||||
const operand = try expr(gz, scope, operand_ri, operand_node);
|
||||
|
||||
17
src/Sema.zig
17
src/Sema.zig
@ -5405,6 +5405,13 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
{
|
||||
try sema.mod.ensureDeclAnalyzed(decl_index);
|
||||
const exported_decl = sema.mod.declPtr(decl_index);
|
||||
if (exported_decl.val.castTag(.function)) |some| {
|
||||
return sema.analyzeExport(block, src, options, some.data.owner_decl);
|
||||
}
|
||||
}
|
||||
try sema.analyzeExport(block, src, options, decl_index);
|
||||
}
|
||||
|
||||
@ -17870,6 +17877,13 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
operand_ty.fmt(mod),
|
||||
}),
|
||||
};
|
||||
if (enum_ty.enumFieldCount() == 0) {
|
||||
// TODO I don't think this is the correct way to handle this but
|
||||
// it prevents a crash.
|
||||
return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{
|
||||
enum_ty.fmt(mod),
|
||||
});
|
||||
}
|
||||
const enum_decl_index = enum_ty.getOwnerDecl();
|
||||
const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
|
||||
if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
|
||||
@ -20997,6 +21011,9 @@ fn analyzeMinMax(
|
||||
|
||||
if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
|
||||
|
||||
try sema.resolveLazyValue(lhs_val);
|
||||
try sema.resolveLazyValue(rhs_val);
|
||||
|
||||
const opFunc = switch (air_tag) {
|
||||
.min => Value.numberMin,
|
||||
.max => Value.numberMax,
|
||||
|
||||
@ -46,6 +46,7 @@ pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value {
|
||||
}
|
||||
|
||||
const max_aggregate_items = 100;
|
||||
const max_string_len = 256;
|
||||
|
||||
const FormatContext = struct {
|
||||
tv: TypedValue,
|
||||
@ -141,10 +142,12 @@ pub fn print(
|
||||
.extern_options_type => return writer.writeAll("std.builtin.ExternOptions"),
|
||||
.type_info_type => return writer.writeAll("std.builtin.Type"),
|
||||
|
||||
.empty_struct_value, .aggregate => {
|
||||
.empty_struct_value => return writer.writeAll(".{}"),
|
||||
.aggregate => {
|
||||
if (level == 0) {
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const values = val.castTag(.aggregate).?;
|
||||
if (ty.zigTypeTag() == .Struct) {
|
||||
try writer.writeAll(".{");
|
||||
const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items);
|
||||
@ -159,9 +162,9 @@ pub fn print(
|
||||
try print(.{
|
||||
.ty = ty.structFieldType(i),
|
||||
.val = switch (ty.containerLayout()) {
|
||||
.Packed => val.castTag(.aggregate).?.data[i],
|
||||
.Packed => values.data[i],
|
||||
else => ty.structFieldValueComptime(i) orelse b: {
|
||||
const vals = val.castTag(.aggregate).?.data;
|
||||
const vals = values.data;
|
||||
break :b vals[i];
|
||||
},
|
||||
},
|
||||
@ -172,17 +175,31 @@ pub fn print(
|
||||
}
|
||||
return writer.writeAll("}");
|
||||
} else {
|
||||
try writer.writeAll(".{ ");
|
||||
const elem_ty = ty.elemType2();
|
||||
const len = ty.arrayLen();
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
buf[i] = std.math.cast(u8, values.data[i].toUnsignedInt(target)) orelse break :str;
|
||||
}
|
||||
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
try print(.{
|
||||
.ty = elem_ty,
|
||||
.val = val.castTag(.aggregate).?.data[i],
|
||||
.val = values.data[i],
|
||||
}, writer, level - 1, mod);
|
||||
}
|
||||
if (len > max_aggregate_items) {
|
||||
@ -372,11 +389,28 @@ pub fn print(
|
||||
return writer.writeAll(".{ ... }");
|
||||
}
|
||||
const payload = val.castTag(.slice).?.data;
|
||||
try writer.writeAll(".{ ");
|
||||
const elem_ty = ty.elemType2();
|
||||
const len = payload.len.toUnsignedInt(target);
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
|
||||
if (elem_ty.eql(Type.u8, mod)) str: {
|
||||
const max_len = @intCast(usize, std.math.min(len, max_string_len));
|
||||
var buf: [max_string_len]u8 = undefined;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
var elem_buf: Value.ElemValueBuffer = undefined;
|
||||
const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf);
|
||||
buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str;
|
||||
}
|
||||
|
||||
// TODO would be nice if this had a bit of unicode awareness.
|
||||
const truncated = if (len > max_string_len) " (truncated)" else "";
|
||||
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
|
||||
}
|
||||
|
||||
try writer.writeAll(".{ ");
|
||||
|
||||
const max_len = std.math.min(len, max_aggregate_items);
|
||||
var i: u32 = 0;
|
||||
while (i < max_len) : (i += 1) {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
|
||||
@ -95,3 +95,10 @@ test "@min for vectors" {
|
||||
try S.doTheTest();
|
||||
comptime try S.doTheTest();
|
||||
}
|
||||
|
||||
test "@min/@max on lazy values" {
|
||||
const A = extern struct { u8_4: [4]u8 };
|
||||
const B = extern struct { u8_16: [16]u8 };
|
||||
const size = @max(@sizeOf(A), @sizeOf(B));
|
||||
try expect(size == @sizeOf(B));
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
extern fn foo(ptr: fn(*void) callconv(.C) void) void;
|
||||
|
||||
export fn entry() void {
|
||||
foo(bar);
|
||||
}
|
||||
|
||||
fn bar(x: *void) callconv(.C) void { _ = x; }
|
||||
export fn entry2() void {
|
||||
bar(&{});
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:1:23: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'
|
||||
// tmp.zig:7:11: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'C'
|
||||
@ -1,12 +0,0 @@
|
||||
fn foo() void {
|
||||
const node: struct {} = undefined;
|
||||
const vla_ptr = @ptrCast([*]const u8, &node);
|
||||
_ = vla_ptr;
|
||||
}
|
||||
comptime { foo(); }
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation
|
||||
@ -1,16 +0,0 @@
|
||||
const Set1 = error{A, C};
|
||||
const Set2 = error{B, D};
|
||||
export fn entry() void {
|
||||
foo(Set1.A);
|
||||
}
|
||||
fn foo(x: Set1) void {
|
||||
if (x == Set2.B) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors
|
||||
@ -1,11 +0,0 @@
|
||||
comptime {
|
||||
var c_ptr: [*c]u8 = undefined;
|
||||
var zig_ptr: *u8 = c_ptr;
|
||||
_ = zig_ptr;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:24: error: use of undefined value here causes undefined behavior
|
||||
@ -1,27 +0,0 @@
|
||||
export fn foo1() void {
|
||||
const a: *[1]u8 = undefined;
|
||||
var b: []u8 = a;
|
||||
_ = b;
|
||||
}
|
||||
export fn foo2() void {
|
||||
comptime {
|
||||
var a: *[1]u8 = undefined;
|
||||
var b: []u8 = a;
|
||||
_ = b;
|
||||
}
|
||||
}
|
||||
export fn foo3() void {
|
||||
comptime {
|
||||
const a: *[1]u8 = undefined;
|
||||
var b: []u8 = a;
|
||||
_ = b;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:19: error: use of undefined value here causes undefined behavior
|
||||
// tmp.zig:9:23: error: use of undefined value here causes undefined behavior
|
||||
// tmp.zig:16:23: error: use of undefined value here causes undefined behavior
|
||||
@ -1,9 +0,0 @@
|
||||
export fn entry() bool {
|
||||
return @ptrToInt(&{}) == @ptrToInt(&{});
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:23: error: pointer to size 0 type has no address
|
||||
@ -1,11 +0,0 @@
|
||||
export fn entry() void {
|
||||
var pointer: ?*u0 = null;
|
||||
var x = @ptrToInt(pointer);
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:23: error: pointer to size 0 type has no address
|
||||
@ -1,18 +0,0 @@
|
||||
export fn entry() void {
|
||||
_ = @Type(.{ .Pointer = .{
|
||||
.size = .One,
|
||||
.is_const = false,
|
||||
.is_volatile = false,
|
||||
.alignment = 1,
|
||||
.address_space = .gs,
|
||||
.child = u8,
|
||||
.is_allowzero = false,
|
||||
.sentinel = null,
|
||||
}});
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:16: error: address space 'gs' not available in stage 1 compiler, must be .generic
|
||||
@ -1,11 +0,0 @@
|
||||
const builtin = @import("std").builtin;
|
||||
var globalTypeInfo : builtin.Type = undefined;
|
||||
export fn entry() void {
|
||||
_ = @Type(globalTypeInfo);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:15: error: unable to evaluate constant expression
|
||||
@ -1,10 +0,0 @@
|
||||
var buf: *[1]u8 = undefined;
|
||||
export fn entry() void {
|
||||
_ = buf[0..1];
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:12: error: non-zero length slice of undefined pointer
|
||||
@ -1,17 +0,0 @@
|
||||
export fn entry() void {
|
||||
Test(i32);
|
||||
}
|
||||
fn Test(comptime T: type) void {
|
||||
const x = switch (T) {
|
||||
[]u8 => |x| x,
|
||||
i32 => |x| x,
|
||||
else => unreachable,
|
||||
};
|
||||
_ = x;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:7:17: error: switch on type 'type' provides no expression parameter
|
||||
@ -1,13 +0,0 @@
|
||||
const Cmd = struct {
|
||||
exec: fn () void,
|
||||
};
|
||||
export fn entry() void {
|
||||
const command = Cmd{ .exec = undefined };
|
||||
command.exec();
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:6:12: error: use of undefined value here causes undefined behavior
|
||||
Loading…
x
Reference in New Issue
Block a user