Revert the rustdoc box syntax removal
It turned out to cause (minor) perf regressions.
This commit is contained in:
@@ -114,7 +114,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||||||
attrs: Default::default(),
|
attrs: Default::default(),
|
||||||
visibility: Inherited,
|
visibility: Inherited,
|
||||||
def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
|
def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
|
||||||
kind: Box::new(ImplItem(Impl {
|
kind: box ImplItem(Impl {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
unsafety: hir::Unsafety::Normal,
|
unsafety: hir::Unsafety::Normal,
|
||||||
generics: new_generics,
|
generics: new_generics,
|
||||||
@@ -124,7 +124,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
|||||||
negative_polarity,
|
negative_polarity,
|
||||||
synthetic: true,
|
synthetic: true,
|
||||||
blanket_impl: None,
|
blanket_impl: None,
|
||||||
})),
|
}),
|
||||||
cfg: None,
|
cfg: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||||||
attrs: Default::default(),
|
attrs: Default::default(),
|
||||||
visibility: Inherited,
|
visibility: Inherited,
|
||||||
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
|
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
|
||||||
kind: Box::new(ImplItem(Impl {
|
kind: box ImplItem(Impl {
|
||||||
span: Span::new(self.cx.tcx.def_span(impl_def_id)),
|
span: Span::new(self.cx.tcx.def_span(impl_def_id)),
|
||||||
unsafety: hir::Unsafety::Normal,
|
unsafety: hir::Unsafety::Normal,
|
||||||
generics: (
|
generics: (
|
||||||
@@ -121,8 +121,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||||||
.clean(self.cx),
|
.clean(self.cx),
|
||||||
negative_polarity: false,
|
negative_polarity: false,
|
||||||
synthetic: false,
|
synthetic: false,
|
||||||
blanket_impl: Some(Box::new(trait_ref.self_ty().clean(self.cx))),
|
blanket_impl: Some(box trait_ref.self_ty().clean(self.cx)),
|
||||||
})),
|
}),
|
||||||
cfg: None,
|
cfg: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,14 +124,8 @@ crate fn try_inline(
|
|||||||
|
|
||||||
let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
|
let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
|
||||||
cx.inlined.insert(did.into());
|
cx.inlined.insert(did.into());
|
||||||
let mut item = clean::Item::from_def_id_and_attrs_and_parts(
|
let mut item =
|
||||||
did,
|
clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cx, cfg);
|
||||||
Some(name),
|
|
||||||
kind,
|
|
||||||
Box::new(attrs),
|
|
||||||
cx,
|
|
||||||
cfg,
|
|
||||||
);
|
|
||||||
if let Some(import_def_id) = import_def_id {
|
if let Some(import_def_id) = import_def_id {
|
||||||
// The visibility needs to reflect the one from the reexport and not from the "source" DefId.
|
// The visibility needs to reflect the one from the reexport and not from the "source" DefId.
|
||||||
item.visibility = cx.tcx.visibility(import_def_id).clean(cx);
|
item.visibility = cx.tcx.visibility(import_def_id).clean(cx);
|
||||||
@@ -464,7 +458,7 @@ crate fn build_impl(
|
|||||||
synthetic: false,
|
synthetic: false,
|
||||||
blanket_impl: None,
|
blanket_impl: None,
|
||||||
}),
|
}),
|
||||||
Box::new(merged_attrs),
|
box merged_attrs,
|
||||||
cx,
|
cx,
|
||||||
cfg,
|
cfg,
|
||||||
));
|
));
|
||||||
@@ -493,10 +487,10 @@ fn build_module(
|
|||||||
let prim_ty = clean::PrimitiveType::from(p);
|
let prim_ty = clean::PrimitiveType::from(p);
|
||||||
items.push(clean::Item {
|
items.push(clean::Item {
|
||||||
name: None,
|
name: None,
|
||||||
attrs: Box::new(clean::Attributes::default()),
|
attrs: box clean::Attributes::default(),
|
||||||
def_id: ItemId::Primitive(prim_ty, did.krate),
|
def_id: ItemId::Primitive(prim_ty, did.krate),
|
||||||
visibility: clean::Public,
|
visibility: clean::Public,
|
||||||
kind: Box::new(clean::ImportItem(clean::Import::new_simple(
|
kind: box clean::ImportItem(clean::Import::new_simple(
|
||||||
item.ident.name,
|
item.ident.name,
|
||||||
clean::ImportSource {
|
clean::ImportSource {
|
||||||
path: clean::Path {
|
path: clean::Path {
|
||||||
@@ -513,7 +507,7 @@ fn build_module(
|
|||||||
did: None,
|
did: None,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
))),
|
)),
|
||||||
cfg: None,
|
cfg: None,
|
||||||
});
|
});
|
||||||
} else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
|
} else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
|
||||||
|
|||||||
@@ -392,8 +392,8 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
|
|||||||
Type::QPath {
|
Type::QPath {
|
||||||
name: cx.tcx.associated_item(self.item_def_id).ident.name,
|
name: cx.tcx.associated_item(self.item_def_id).ident.name,
|
||||||
self_def_id: self_type.def_id(),
|
self_def_id: self_type.def_id(),
|
||||||
self_type: Box::new(self_type),
|
self_type: box self_type,
|
||||||
trait_: Box::new(trait_),
|
trait_: box trait_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1284,8 +1284,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
|||||||
Type::QPath {
|
Type::QPath {
|
||||||
name: p.segments.last().expect("segments were empty").ident.name,
|
name: p.segments.last().expect("segments were empty").ident.name,
|
||||||
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
|
self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
|
||||||
self_type: Box::new(qself.clean(cx)),
|
self_type: box qself.clean(cx),
|
||||||
trait_: Box::new(resolve_type(cx, trait_path)),
|
trait_: box resolve_type(cx, trait_path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::QPath::TypeRelative(ref qself, ref segment) => {
|
hir::QPath::TypeRelative(ref qself, ref segment) => {
|
||||||
@@ -1300,8 +1300,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
|||||||
Type::QPath {
|
Type::QPath {
|
||||||
name: segment.ident.name,
|
name: segment.ident.name,
|
||||||
self_def_id: res.opt_def_id(),
|
self_def_id: res.opt_def_id(),
|
||||||
self_type: Box::new(qself.clean(cx)),
|
self_type: box qself.clean(cx),
|
||||||
trait_: Box::new(resolve_type(cx, trait_path)),
|
trait_: box resolve_type(cx, trait_path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
|
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
|
||||||
@@ -1314,7 +1314,7 @@ impl Clean<Type> for hir::Ty<'_> {
|
|||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TyKind::Never => Never,
|
TyKind::Never => Never,
|
||||||
TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))),
|
TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)),
|
||||||
TyKind::Rptr(ref l, ref m) => {
|
TyKind::Rptr(ref l, ref m) => {
|
||||||
// There are two times a `Fresh` lifetime can be created:
|
// There are two times a `Fresh` lifetime can be created:
|
||||||
// 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
|
// 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
|
||||||
@@ -1326,9 +1326,9 @@ impl Clean<Type> for hir::Ty<'_> {
|
|||||||
let elided =
|
let elided =
|
||||||
l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
|
l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_)));
|
||||||
let lifetime = if elided { None } else { Some(l.clean(cx)) };
|
let lifetime = if elided { None } else { Some(l.clean(cx)) };
|
||||||
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) }
|
BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) }
|
||||||
}
|
}
|
||||||
TyKind::Slice(ref ty) => Slice(Box::new(ty.clean(cx))),
|
TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
|
||||||
TyKind::Array(ref ty, ref length) => {
|
TyKind::Array(ref ty, ref length) => {
|
||||||
let def_id = cx.tcx.hir().local_def_id(length.hir_id);
|
let def_id = cx.tcx.hir().local_def_id(length.hir_id);
|
||||||
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
|
||||||
@@ -1341,7 +1341,7 @@ impl Clean<Type> for hir::Ty<'_> {
|
|||||||
let ct = ty::Const::from_anon_const(cx.tcx, def_id);
|
let ct = ty::Const::from_anon_const(cx.tcx, def_id);
|
||||||
let param_env = cx.tcx.param_env(def_id);
|
let param_env = cx.tcx.param_env(def_id);
|
||||||
let length = print_const(cx, ct.eval(cx.tcx, param_env));
|
let length = print_const(cx, ct.eval(cx.tcx, param_env));
|
||||||
Array(Box::new(ty.clean(cx)), length)
|
Array(box ty.clean(cx), length)
|
||||||
}
|
}
|
||||||
TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
|
TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
|
||||||
TyKind::OpaqueDef(item_id, _) => {
|
TyKind::OpaqueDef(item_id, _) => {
|
||||||
@@ -1358,7 +1358,7 @@ impl Clean<Type> for hir::Ty<'_> {
|
|||||||
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
|
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
|
||||||
DynTrait(bounds, lifetime)
|
DynTrait(bounds, lifetime)
|
||||||
}
|
}
|
||||||
TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))),
|
TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
|
||||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||||
TyKind::Infer | TyKind::Err => Infer,
|
TyKind::Infer | TyKind::Err => Infer,
|
||||||
TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
|
TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind),
|
||||||
@@ -1409,29 +1409,27 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
|||||||
ty::Uint(uint_ty) => Primitive(uint_ty.into()),
|
ty::Uint(uint_ty) => Primitive(uint_ty.into()),
|
||||||
ty::Float(float_ty) => Primitive(float_ty.into()),
|
ty::Float(float_ty) => Primitive(float_ty.into()),
|
||||||
ty::Str => Primitive(PrimitiveType::Str),
|
ty::Str => Primitive(PrimitiveType::Str),
|
||||||
ty::Slice(ty) => Slice(Box::new(ty.clean(cx))),
|
ty::Slice(ty) => Slice(box ty.clean(cx)),
|
||||||
ty::Array(ty, n) => {
|
ty::Array(ty, n) => {
|
||||||
let mut n = cx.tcx.lift(n).expect("array lift failed");
|
let mut n = cx.tcx.lift(n).expect("array lift failed");
|
||||||
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
|
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
|
||||||
let n = print_const(cx, n);
|
let n = print_const(cx, n);
|
||||||
Array(Box::new(ty.clean(cx)), n)
|
Array(box ty.clean(cx), n)
|
||||||
|
}
|
||||||
|
ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)),
|
||||||
|
ty::Ref(r, ty, mutbl) => {
|
||||||
|
BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) }
|
||||||
}
|
}
|
||||||
ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))),
|
|
||||||
ty::Ref(r, ty, mutbl) => BorrowedRef {
|
|
||||||
lifetime: r.clean(cx),
|
|
||||||
mutability: mutbl,
|
|
||||||
type_: Box::new(ty.clean(cx)),
|
|
||||||
},
|
|
||||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||||
let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
|
let ty = cx.tcx.lift(*self).expect("FnPtr lift failed");
|
||||||
let sig = ty.fn_sig(cx.tcx);
|
let sig = ty.fn_sig(cx.tcx);
|
||||||
let def_id = DefId::local(CRATE_DEF_INDEX);
|
let def_id = DefId::local(CRATE_DEF_INDEX);
|
||||||
BareFunction(Box::new(BareFunctionDecl {
|
BareFunction(box BareFunctionDecl {
|
||||||
unsafety: sig.unsafety(),
|
unsafety: sig.unsafety(),
|
||||||
generic_params: Vec::new(),
|
generic_params: Vec::new(),
|
||||||
decl: (def_id, sig).clean(cx),
|
decl: (def_id, sig).clean(cx),
|
||||||
abi: sig.abi(),
|
abi: sig.abi(),
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
let did = def.did;
|
let did = def.did;
|
||||||
@@ -1974,10 +1972,10 @@ fn clean_extern_crate(
|
|||||||
// FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
|
// FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
|
||||||
vec![Item {
|
vec![Item {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
attrs: Box::new(attrs.clean(cx)),
|
attrs: box attrs.clean(cx),
|
||||||
def_id: crate_def_id.into(),
|
def_id: crate_def_id.into(),
|
||||||
visibility: krate.vis.clean(cx),
|
visibility: krate.vis.clean(cx),
|
||||||
kind: Box::new(ExternCrateItem { src: orig_name }),
|
kind: box ExternCrateItem { src: orig_name },
|
||||||
cfg: attrs.cfg(cx.sess()),
|
cfg: attrs.cfg(cx.sess()),
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ impl Item {
|
|||||||
def_id,
|
def_id,
|
||||||
name,
|
name,
|
||||||
kind,
|
kind,
|
||||||
Box::new(ast_attrs.clean(cx)),
|
box ast_attrs.clean(cx),
|
||||||
cx,
|
cx,
|
||||||
ast_attrs.cfg(cx.sess()),
|
ast_attrs.cfg(cx.sess()),
|
||||||
)
|
)
|
||||||
@@ -439,7 +439,7 @@ impl Item {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
def_id: def_id.into(),
|
def_id: def_id.into(),
|
||||||
kind: Box::new(kind),
|
kind: box kind,
|
||||||
name,
|
name,
|
||||||
attrs,
|
attrs,
|
||||||
visibility: cx.tcx.visibility(def_id).clean(cx),
|
visibility: cx.tcx.visibility(def_id).clean(cx),
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ crate fn create_config(
|
|||||||
stderr: None,
|
stderr: None,
|
||||||
lint_caps,
|
lint_caps,
|
||||||
parse_sess_created: None,
|
parse_sess_created: None,
|
||||||
register_lints: Some(Box::new(crate::lint::register_lints)),
|
register_lints: Some(box crate::lint::register_lints),
|
||||||
override_queries: Some(|_sess, providers, _external_providers| {
|
override_queries: Some(|_sess, providers, _external_providers| {
|
||||||
// Most lints will require typechecking, so just don't run them.
|
// Most lints will require typechecking, so just don't run them.
|
||||||
providers.lint_mod = |_, _| {};
|
providers.lint_mod = |_, _| {};
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
|
|||||||
stderr: None,
|
stderr: None,
|
||||||
lint_caps,
|
lint_caps,
|
||||||
parse_sess_created: None,
|
parse_sess_created: None,
|
||||||
register_lints: Some(Box::new(crate::lint::register_lints)),
|
register_lints: Some(box crate::lint::register_lints),
|
||||||
override_queries: None,
|
override_queries: None,
|
||||||
make_codegen_backend: None,
|
make_codegen_backend: None,
|
||||||
registry: rustc_driver::diagnostics_registry(),
|
registry: rustc_driver::diagnostics_registry(),
|
||||||
@@ -550,10 +550,10 @@ crate fn make_test(
|
|||||||
.supports_color();
|
.supports_color();
|
||||||
|
|
||||||
let emitter =
|
let emitter =
|
||||||
EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false);
|
EmitterWriter::new(box io::sink(), None, false, false, false, None, false);
|
||||||
|
|
||||||
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
|
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
|
||||||
let handler = Handler::with_emitter(false, None, Box::new(emitter));
|
let handler = Handler::with_emitter(false, None, box emitter);
|
||||||
let sess = ParseSess::with_span_handler(handler, sm);
|
let sess = ParseSess::with_span_handler(handler, sm);
|
||||||
|
|
||||||
let mut found_main = false;
|
let mut found_main = false;
|
||||||
@@ -963,7 +963,7 @@ impl Tester for Collector {
|
|||||||
no_run,
|
no_run,
|
||||||
test_type: test::TestType::DocTest,
|
test_type: test::TestType::DocTest,
|
||||||
},
|
},
|
||||||
testfn: test::DynTestFn(Box::new(move || {
|
testfn: test::DynTestFn(box move || {
|
||||||
let report_unused_externs = |uext| {
|
let report_unused_externs = |uext| {
|
||||||
unused_externs.lock().unwrap().push(uext);
|
unused_externs.lock().unwrap().push(uext);
|
||||||
};
|
};
|
||||||
@@ -1043,9 +1043,9 @@ impl Tester for Collector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic::resume_unwind(Box::new(()));
|
panic::resume_unwind(box ());
|
||||||
}
|
}
|
||||||
})),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::clean::*;
|
|||||||
|
|
||||||
crate fn strip_item(mut item: Item) -> Item {
|
crate fn strip_item(mut item: Item) -> Item {
|
||||||
if !matches!(*item.kind, StrippedItem(..)) {
|
if !matches!(*item.kind, StrippedItem(..)) {
|
||||||
item.kind = Box::new(StrippedItem(item.kind));
|
item.kind = box StrippedItem(item.kind);
|
||||||
}
|
}
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
@@ -69,10 +69,10 @@ crate trait DocFolder: Sized {
|
|||||||
|
|
||||||
/// don't override!
|
/// don't override!
|
||||||
fn fold_item_recur(&mut self, mut item: Item) -> Item {
|
fn fold_item_recur(&mut self, mut item: Item) -> Item {
|
||||||
item.kind = Box::new(match *item.kind {
|
item.kind = box match *item.kind {
|
||||||
StrippedItem(box i) => StrippedItem(Box::new(self.fold_inner_recur(i))),
|
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
|
||||||
_ => self.fold_inner_recur(*item.kind),
|
_ => self.fold_inner_recur(*item.kind),
|
||||||
});
|
};
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(control_flow_enum)]
|
#![feature(control_flow_enum)]
|
||||||
|
#![feature(box_syntax)]
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ enum ErrorKind<'a> {
|
|||||||
|
|
||||||
impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
|
impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
|
||||||
fn from(err: ResolutionFailure<'a>) -> Self {
|
fn from(err: ResolutionFailure<'a>) -> Self {
|
||||||
ErrorKind::Resolve(Box::new(err))
|
ErrorKind::Resolve(box err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user