librustc: Rename reinterpret_cast
to transmute_copy
and remove the intrinsic
This commit is contained in:
parent
b6277f8140
commit
c6a9e28842
@ -185,7 +185,7 @@ pub mod traits {}
|
||||
|
||||
pub mod raw {
|
||||
use at_vec::{capacity, rustrt};
|
||||
use cast::transmute;
|
||||
use cast::{transmute, transmute_copy};
|
||||
use libc;
|
||||
use ptr;
|
||||
use sys;
|
||||
@ -211,12 +211,11 @@ pub mod raw {
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn push<T>(v: &mut @[T], initval: T) {
|
||||
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
|
||||
let repr: **VecRepr = transmute_copy(&v);
|
||||
let fill = (**repr).unboxed.fill;
|
||||
if (**repr).unboxed.alloc > fill {
|
||||
push_fast(v, initval);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
push_slow(v, initval);
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,19 @@ pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
|
||||
rusti::reinterpret_cast(*src)
|
||||
}
|
||||
|
||||
/// Unsafely copies and casts the value at `src` to U, even if the value is
|
||||
/// noncopyable. The two types must have the same length.
|
||||
#[inline(always)]
|
||||
#[cfg(stage0)]
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
rusti::reinterpret_cast(*src)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
#[cfg(stage3)]
|
||||
pub unsafe fn reinterpret_cast<T, U>(src: &T) -> U {
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
let mut dest: U = unstable::intrinsics::init();
|
||||
{
|
||||
let dest_ptr: *mut u8 = rusti::transmute(&mut dest);
|
||||
@ -148,11 +156,20 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use cast::{bump_box_refcount, reinterpret_cast, transmute};
|
||||
use cast::{bump_box_refcount, transmute};
|
||||
|
||||
#[test]
|
||||
#[cfg(stage0)]
|
||||
fn test_reinterpret_cast() {
|
||||
assert!(1u == unsafe { reinterpret_cast(&1) });
|
||||
assert!(1u == unsafe { ::cast::reinterpret_cast(&1) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
#[cfg(stage3)]
|
||||
fn test_transmute_copy() {
|
||||
assert!(1u == unsafe { ::cast::transmute_copy(&1) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -82,7 +82,7 @@ bounded and unbounded protocols allows for less code duplication.
|
||||
|
||||
*/
|
||||
|
||||
use cast::{forget, reinterpret_cast, transmute};
|
||||
use cast::{forget, transmute, transmute_copy};
|
||||
use either::{Either, Left, Right};
|
||||
use kinds::Owned;
|
||||
use libc;
|
||||
@ -131,7 +131,7 @@ pub struct PacketHeader {
|
||||
mut state: State,
|
||||
mut blocked_task: *rust_task,
|
||||
|
||||
// This is a reinterpret_cast of a ~buffer, that can also be cast
|
||||
// This is a transmute_copy of a ~buffer, that can also be cast
|
||||
// to a buffer_header if need be.
|
||||
mut buffer: *libc::c_void,
|
||||
}
|
||||
@ -170,12 +170,12 @@ pub impl PacketHeader {
|
||||
// thing. You'll proobably want to forget them when you're done.
|
||||
unsafe fn buf_header(&self) -> ~BufferHeader {
|
||||
assert!(self.buffer.is_not_null());
|
||||
reinterpret_cast(&self.buffer)
|
||||
transmute_copy(&self.buffer)
|
||||
}
|
||||
|
||||
fn set_buffer<T:Owned>(&self, b: ~Buffer<T>) {
|
||||
unsafe {
|
||||
self.buffer = reinterpret_cast(&b);
|
||||
self.buffer = transmute_copy(&b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,7 +211,7 @@ fn unibuffer<T>() -> ~Buffer<Packet<T>> {
|
||||
};
|
||||
|
||||
unsafe {
|
||||
b.data.header.buffer = reinterpret_cast(&b);
|
||||
b.data.header.buffer = transmute_copy(&b);
|
||||
}
|
||||
b
|
||||
}
|
||||
@ -229,7 +229,7 @@ pub fn entangle_buffer<T:Owned,Tstart:Owned>(
|
||||
init: &fn(*libc::c_void, x: &T) -> *Packet<Tstart>)
|
||||
-> (SendPacketBuffered<Tstart, T>, RecvPacketBuffered<Tstart, T>)
|
||||
{
|
||||
let p = init(unsafe { reinterpret_cast(&buffer) }, &buffer.data);
|
||||
let p = init(unsafe { transmute_copy(&buffer) }, &buffer.data);
|
||||
unsafe { forget(buffer) }
|
||||
(SendPacketBuffered(p), RecvPacketBuffered(p))
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: int, count: uint) {
|
||||
/**
|
||||
Transform a region pointer - &T - to an unsafe pointer - *T.
|
||||
This is safe, but is implemented with an unsafe block due to
|
||||
reinterpret_cast.
|
||||
transmute.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
|
||||
@ -129,7 +129,7 @@ pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
|
||||
/**
|
||||
Transform a const region pointer - &const T - to a const unsafe pointer -
|
||||
*const T. This is safe, but is implemented with an unsafe block due to
|
||||
reinterpret_cast.
|
||||
transmute.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
|
||||
@ -139,7 +139,7 @@ pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
|
||||
/**
|
||||
Transform a mutable region pointer - &mut T - to a mutable unsafe pointer -
|
||||
*mut T. This is safe, but is implemented with an unsafe block due to
|
||||
reinterpret_cast.
|
||||
transmute.
|
||||
*/
|
||||
#[inline(always)]
|
||||
pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
|
||||
@ -149,7 +149,7 @@ pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
|
||||
/**
|
||||
Cast a region pointer - &T - to a uint.
|
||||
This is safe, but is implemented with an unsafe block due to
|
||||
reinterpret_cast.
|
||||
transmute.
|
||||
|
||||
(I couldn't think of a cutesy name for this one.)
|
||||
*/
|
||||
|
@ -154,8 +154,8 @@ pub fn pref_align_of_val<T>(_val: &T) -> uint {
|
||||
#[inline(always)]
|
||||
pub fn refcount<T>(t: @T) -> uint {
|
||||
unsafe {
|
||||
let ref_ptr: *uint = cast::reinterpret_cast(&t);
|
||||
*ref_ptr - 1
|
||||
let ref_ptr: *uint = cast::transmute(t);
|
||||
*ref_ptr
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,9 +59,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
|
||||
let map_ptr = rt::rust_get_task_local_data(task);
|
||||
if map_ptr.is_null() {
|
||||
let map: TaskLocalMap = @mut ~[];
|
||||
// Use reinterpret_cast -- transmute would take map away from us also.
|
||||
rt::rust_set_task_local_data(
|
||||
task, cast::transmute(map));
|
||||
rt::rust_set_task_local_data(task, cast::transmute(map));
|
||||
rt::rust_task_local_data_atexit(task, cleanup_task_local_map);
|
||||
// Also need to reference it an extra time to keep it for now.
|
||||
let nonmut = cast::transmute::<TaskLocalMap,
|
||||
@ -77,12 +75,10 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn key_to_key_value<T:Durable>(
|
||||
key: LocalDataKey<T>) -> *libc::c_void {
|
||||
|
||||
unsafe fn key_to_key_value<T:Durable>(key: LocalDataKey<T>) -> *libc::c_void {
|
||||
// Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
|
||||
// Use reintepret_cast -- transmute would leak (forget) the closure.
|
||||
let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key);
|
||||
let pair: (*libc::c_void, *libc::c_void) = cast::transmute_copy(&key);
|
||||
pair.first()
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ pub extern "rust-intrinsic" {
|
||||
pub fn forget<T>(_: T) -> ();
|
||||
|
||||
// XXX: intrinsic uses legacy modes
|
||||
#[cfg(stage0)]
|
||||
fn reinterpret_cast<T,U>(&&src: T) -> U;
|
||||
|
||||
pub fn needs_drop<T>() -> bool;
|
||||
|
@ -716,35 +716,6 @@ pub fn trans_intrinsic(ccx: @CrateContext,
|
||||
}
|
||||
}
|
||||
~"forget" => {}
|
||||
~"reinterpret_cast" => {
|
||||
let tp_ty = substs.tys[0];
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let llout_ty = type_of::type_of(ccx, substs.tys[1]);
|
||||
let tp_sz = machine::llbitsize_of_real(ccx, lltp_ty),
|
||||
out_sz = machine::llbitsize_of_real(ccx, llout_ty);
|
||||
if tp_sz != out_sz {
|
||||
let sp = match *ccx.tcx.items.get(&ref_id.get()) {
|
||||
ast_map::node_expr(e) => e.span,
|
||||
_ => fail!(~"reinterpret_cast or forget has non-expr arg")
|
||||
};
|
||||
ccx.sess.span_fatal(
|
||||
sp, fmt!("reinterpret_cast called on types \
|
||||
with different size: %s (%u bit(s)) to %s \
|
||||
(%u bit(s))",
|
||||
ty_to_str(ccx.tcx, tp_ty), tp_sz,
|
||||
ty_to_str(ccx.tcx, substs.tys[1]), out_sz));
|
||||
}
|
||||
if !ty::type_is_nil(substs.tys[1]) {
|
||||
// NB: Do not use a Load and Store here. This causes
|
||||
// massive code bloat when reinterpret_cast is used on
|
||||
// large structural types.
|
||||
let llretptr = fcx.llretptr.get();
|
||||
let llretptr = PointerCast(bcx, llretptr, T_ptr(T_i8()));
|
||||
let llcast = get_param(decl, first_real_arg);
|
||||
let llcast = PointerCast(bcx, llcast, T_ptr(T_i8()));
|
||||
call_memcpy(bcx, llretptr, llcast, llsize_of(ccx, lltp_ty));
|
||||
}
|
||||
}
|
||||
~"transmute" => {
|
||||
let (in_type, out_type) = (substs.tys[0], substs.tys[1]);
|
||||
let llintype = type_of::type_of(ccx, in_type);
|
||||
|
@ -122,9 +122,9 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
|
||||
_) => {
|
||||
if abi.is_intrinsic() {
|
||||
let flags = match *cx.ccx.sess.str_of(i.ident) {
|
||||
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
|
||||
~"init" | ~"reinterpret_cast" | ~"transmute" |
|
||||
~"move_val" | ~"move_val_init" => use_repr,
|
||||
~"size_of" | ~"pref_align_of" | ~"min_align_of" |
|
||||
~"init" | ~"transmute" | ~"move_val" |
|
||||
~"move_val_init" => use_repr,
|
||||
|
||||
~"get_tydesc" | ~"needs_drop" => use_tydesc,
|
||||
|
||||
|
@ -3439,8 +3439,6 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||
~"init" => (1u, ~[], param(ccx, 0u)),
|
||||
~"forget" => (1u, ~[arg(ast::by_copy, param(ccx, 0u))],
|
||||
ty::mk_nil()),
|
||||
~"reinterpret_cast" => (2u, ~[arg(ast::by_ref, param(ccx, 0u))],
|
||||
param(ccx, 1u)),
|
||||
~"transmute" => (2, ~[arg(ast::by_copy, param(ccx, 0))], param(ccx, 1)),
|
||||
~"move_val" | ~"move_val_init" => {
|
||||
(1u, ~[arg(ast::by_copy,
|
||||
|
@ -13,7 +13,7 @@
|
||||
// the error points to the start of the file, not the line with the
|
||||
// transmute
|
||||
|
||||
// error-pattern: reinterpret_cast called on types with different size
|
||||
// error-pattern: transmute called on types with different size
|
||||
|
||||
#[packed]
|
||||
struct Foo<T,S> {
|
||||
|
@ -13,7 +13,7 @@
|
||||
// the error points to the start of the file, not the line with the
|
||||
// transmute
|
||||
|
||||
// error-pattern: reinterpret_cast called on types with different size
|
||||
// error-pattern: transmute called on types with different size
|
||||
|
||||
#[packed]
|
||||
struct Foo {
|
||||
|
@ -21,7 +21,7 @@ struct r {
|
||||
impl Drop for r {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
let _v2: ~int = cast::reinterpret_cast(&self.v);
|
||||
let _v2: ~int = cast::transmute(self.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,7 @@ fn r(v: *int) -> r {
|
||||
fn main() {
|
||||
unsafe {
|
||||
let i1 = ~0;
|
||||
let i1p = cast::reinterpret_cast(&i1);
|
||||
let i1p = cast::transmute_copy(&i1);
|
||||
cast::forget(i1);
|
||||
let x = @r(i1p);
|
||||
failfn();
|
||||
|
@ -64,9 +64,9 @@ fn test_box() {
|
||||
|
||||
fn test_ptr() {
|
||||
unsafe {
|
||||
let p1: *u8 = ::core::cast::reinterpret_cast(&0);
|
||||
let p2: *u8 = ::core::cast::reinterpret_cast(&0);
|
||||
let p3: *u8 = ::core::cast::reinterpret_cast(&1);
|
||||
let p1: *u8 = ::core::cast::transmute(0);
|
||||
let p2: *u8 = ::core::cast::transmute(0);
|
||||
let p3: *u8 = ::core::cast::transmute(1);
|
||||
|
||||
assert!(p1 == p2);
|
||||
assert!(p1 != p3);
|
||||
@ -107,8 +107,8 @@ fn test_class() {
|
||||
|
||||
unsafe {
|
||||
error!("q = %x, r = %x",
|
||||
(::core::cast::reinterpret_cast::<*p, uint>(& &q)),
|
||||
(::core::cast::reinterpret_cast::<*p, uint>(& &r)));
|
||||
(::core::cast::transmute::<*p, uint>(&q)),
|
||||
(::core::cast::transmute::<*p, uint>(&r)));
|
||||
}
|
||||
assert!((q == r));
|
||||
r.y = 17;
|
||||
|
@ -14,7 +14,7 @@ fn addr_of<T>(ptr: &T) -> uint {
|
||||
}
|
||||
|
||||
fn is_aligned<T>(ptr: &T) -> bool {
|
||||
(to_unsafe_ptr(ptr) % sys::min_align_of::<T>()) == 0
|
||||
(ptr::to_unsafe_ptr(ptr) % sys::min_align_of::<T>()) == 0
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
@ -16,7 +16,7 @@ use core::f64::*;
|
||||
|
||||
fn to_c_int(v: &mut int) -> &mut c_int {
|
||||
unsafe {
|
||||
cast::reinterpret_cast(&v)
|
||||
cast::transmute_copy(&v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ struct Ccx {
|
||||
|
||||
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
|
||||
unsafe {
|
||||
return cast::reinterpret_cast(
|
||||
&libc::malloc(sys::size_of::<Bcx<'blk>>() as libc::size_t));
|
||||
cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
|
||||
as libc::size_t));
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ fn g(fcx : &Fcx) {
|
||||
let bcx = Bcx { fcx: fcx };
|
||||
let bcx2 = h(&bcx);
|
||||
unsafe {
|
||||
libc::free(cast::reinterpret_cast(&bcx2));
|
||||
libc::free(cast::transmute(bcx2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,10 +18,10 @@ impl Drop for r {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
debug!("r's dtor: self = %x, self.v = %x, self.v's value = %x",
|
||||
cast::reinterpret_cast::<*r, uint>(&self),
|
||||
cast::reinterpret_cast::<**int, uint>(& &(self.v)),
|
||||
cast::reinterpret_cast::<*int, uint>(&self.v));
|
||||
let v2: ~int = cast::reinterpret_cast(&self.v);
|
||||
cast::transmute::<*r, uint>(self),
|
||||
cast::transmute::<**int, uint>(&(self.v)),
|
||||
cast::transmute::<*int, uint>(self.v));
|
||||
let v2: ~int = cast::transmute(self.v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,36 +44,36 @@ struct Node {
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let i1 = ~0;
|
||||
let i1p = cast::reinterpret_cast(&i1);
|
||||
let i1p = cast::transmute_copy(&i1);
|
||||
cast::forget(i1);
|
||||
let i2 = ~0;
|
||||
let i2p = cast::reinterpret_cast(&i2);
|
||||
let i2p = cast::transmute_copy(&i2);
|
||||
cast::forget(i2);
|
||||
|
||||
let mut x1 = @mut t(Node{
|
||||
next: None,
|
||||
r: {
|
||||
let rs = r(i1p);
|
||||
debug!("r = %x", cast::reinterpret_cast::<*r, uint>(& &rs));
|
||||
debug!("r = %x", cast::transmute::<*r, uint>(&rs));
|
||||
rs }
|
||||
});
|
||||
|
||||
debug!("x1 = %x, x1.r = %x",
|
||||
cast::reinterpret_cast::<@mut t, uint>(&x1),
|
||||
cast::reinterpret_cast::<*r, uint>(& &(x1.r)));
|
||||
cast::transmute::<@mut t, uint>(x1),
|
||||
cast::transmute::<*r, uint>(&x1.r));
|
||||
|
||||
let mut x2 = @mut t(Node{
|
||||
next: None,
|
||||
r: {
|
||||
let rs = r(i2p);
|
||||
debug!("r2 = %x", cast::reinterpret_cast::<*r, uint>(& &rs));
|
||||
debug!("r2 = %x", cast::transmute::<*r, uint>(&rs));
|
||||
rs
|
||||
}
|
||||
});
|
||||
|
||||
debug!("x2 = %x, x2.r = %x",
|
||||
cast::reinterpret_cast::<@mut t, uint>(&x2),
|
||||
cast::reinterpret_cast::<*r, uint>(& &(x2.r)));
|
||||
cast::transmute::<@mut t, uint>(x2),
|
||||
cast::transmute::<*r, uint>(&(x2.r)));
|
||||
|
||||
x1.next = Some(x2);
|
||||
x2.next = Some(x1);
|
||||
|
@ -23,7 +23,7 @@ struct r {
|
||||
impl Drop for r {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
let v2: ~int = cast::reinterpret_cast(&self.v.c);
|
||||
let v2: ~int = cast::transmute(self.v.c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,10 +44,10 @@ struct Node {
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let i1 = ~0xA;
|
||||
let i1p = cast::reinterpret_cast(&i1);
|
||||
let i1p = cast::transmute_copy(&i1);
|
||||
cast::forget(i1);
|
||||
let i2 = ~0xA;
|
||||
let i2p = cast::reinterpret_cast(&i2);
|
||||
let i2p = cast::transmute_copy(&i2);
|
||||
cast::forget(i2);
|
||||
|
||||
let u1 = U {a: 0xB, b: 0xC, c: i1p};
|
||||
|
@ -27,8 +27,8 @@ struct R {
|
||||
impl Drop for R {
|
||||
fn finalize(&self) {
|
||||
unsafe {
|
||||
let _v2: ~int = cast::reinterpret_cast(&self.v.c);
|
||||
// let _v3: ~int = unsafe::reinterpret_cast(self.x);
|
||||
let _v2: ~int = cast::transmute(self.v.c);
|
||||
// let _v3: ~int = cast::transmute_copy(self.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ fn r(v: U, w: int, _x: *int) -> R {
|
||||
R {
|
||||
v: v,
|
||||
w: w,
|
||||
x: cast::reinterpret_cast(&0)
|
||||
x: cast::transmute(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -53,10 +53,10 @@ struct Node {
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let i1 = ~0xA;
|
||||
let i1p = cast::reinterpret_cast(&i1);
|
||||
let i1p = cast::transmute_copy(&i1);
|
||||
cast::forget(i1);
|
||||
let i2 = ~0xA;
|
||||
let i2p = cast::reinterpret_cast(&i2);
|
||||
let i2p = cast::transmute_copy(&i2);
|
||||
cast::forget(i2);
|
||||
|
||||
let u1 = U {a: 0xB, b: 0xC, c: i1p};
|
||||
|
@ -48,7 +48,7 @@ pub fn main() {
|
||||
ch.send(());
|
||||
}
|
||||
};
|
||||
let fptr = cast::reinterpret_cast(& &f);
|
||||
let fptr = cast::transmute(&f);
|
||||
rustrt::start_task(new_task_id, fptr);
|
||||
cast::forget(f);
|
||||
po.recv();
|
||||
|
@ -38,7 +38,7 @@ pub fn main() {
|
||||
}
|
||||
|
||||
fn test_color(color: color, val: int, name: ~str) {
|
||||
//assert!(unsafe::reinterpret_cast(color) == val);
|
||||
//assert!(unsafe::transmute(color) == val);
|
||||
assert!(color as int == val);
|
||||
assert!(color as float == val as float);
|
||||
assert!(get_color_alt(color) == name);
|
||||
|
@ -15,7 +15,7 @@ extern mod std;
|
||||
|
||||
fn null<T>() -> *T {
|
||||
unsafe {
|
||||
cast::reinterpret_cast(&0)
|
||||
cast::transmute(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user