Compare commits
1 Commits
eevee-rewr
...
temp-unrea
Author | SHA1 | Date | |
---|---|---|---|
11494e9472 |
@@ -299,8 +299,7 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
|
||||
#endif
|
||||
default:
|
||||
/* Only accept "generic" custom data types used by the attribute system. */
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,8 +340,7 @@ static int attribute_domain_priority(const AttributeDomain domain)
|
||||
return 4;
|
||||
default:
|
||||
/* Domain not supported in nodes yet. */
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,8 +701,7 @@ bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain)
|
||||
|
||||
int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain)) const
|
||||
{
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
|
||||
|
@@ -65,8 +65,7 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
|
||||
case GEO_COMPONENT_TYPE_VOLUME:
|
||||
return new VolumeComponent();
|
||||
}
|
||||
BLI_assert(false);
|
||||
return nullptr;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
void GeometryComponent::user_add() const
|
||||
|
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_unreachable.h"
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
namespace blender {
|
||||
@@ -105,8 +106,7 @@ template<typename T> class ListBaseWrapper {
|
||||
}
|
||||
index++;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return -1;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
};
|
||||
|
||||
|
33
source/blender/blenlib/BLI_unreachable.h
Normal file
33
source/blender/blenlib/BLI_unreachable.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Is used to indicate that a line of code should never be reached at run-time. It is not necessary
|
||||
* to return a value after this. */
|
||||
#define BLI_UNREACHABLE_ABORT \
|
||||
BLI_assert(false); \
|
||||
abort()
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -28,6 +28,7 @@
|
||||
/* avoid many includes for now */
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_unreachable.h"
|
||||
#include "BLI_utildefines_variadic.h"
|
||||
|
||||
/* We could remove in future. */
|
||||
|
@@ -284,6 +284,7 @@ set(SRC
|
||||
BLI_timecode.h
|
||||
BLI_timeit.hh
|
||||
BLI_timer.h
|
||||
BLI_unreachable.h
|
||||
BLI_user_counter.hh
|
||||
BLI_utildefines.h
|
||||
BLI_utildefines_iter.h
|
||||
|
@@ -1920,14 +1920,12 @@ void add_edge_constraint(
|
||||
constexpr int unreasonably_large_crossings = 100000;
|
||||
if (!ok || crossings.size() == unreasonably_large_crossings) {
|
||||
/* Shouldn't happen but if does, just bail out. */
|
||||
BLI_assert(false);
|
||||
return;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
if (crossings[n].lambda == 0) {
|
||||
if (crossings[n].vert->visit_index == visit) {
|
||||
/* Shouldn't happen but if it does, just bail out. */
|
||||
BLI_assert(false);
|
||||
return;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
crossings[n].vert->visit_index = visit;
|
||||
}
|
||||
|
@@ -642,8 +642,7 @@ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *
|
||||
break;
|
||||
|
||||
default:
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
parse_add_op(state, code, 1 - args)->arg.ptr = funcptr;
|
||||
|
@@ -1936,8 +1936,7 @@ static IMesh extract_subdivided_tri(const CDT_data &cd,
|
||||
}
|
||||
if (t_in_cdt == -1) {
|
||||
std::cout << "Could not find " << t << " in cdt input tris\n";
|
||||
BLI_assert(false);
|
||||
return IMesh();
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
int t_orig = in_tm.face(t)->orig;
|
||||
constexpr int inline_buf_size = 20;
|
||||
|
@@ -83,8 +83,7 @@ static int oedge_cmp(const void *a1, const void *a2)
|
||||
return -1;
|
||||
}
|
||||
/* Should never get here, no two edges should be the same. */
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
BLI_INLINE bool is_boundary_edge(uint i_a, uint i_b, const uint coord_last)
|
||||
|
@@ -1199,8 +1199,7 @@ static bool edge_edge_angle_less_than_180(const BMEdge *e1, const BMEdge *e2, co
|
||||
v2 = e2->v1;
|
||||
}
|
||||
else {
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
sub_v3_v3v3(dir1, v1->co, v->co);
|
||||
sub_v3_v3v3(dir2, v2->co, v->co);
|
||||
|
@@ -83,8 +83,7 @@ static ListBase *fmodifier_list_space_specific(const bContext *C)
|
||||
}
|
||||
|
||||
/* This should not be called in any other space. */
|
||||
BLI_assert(false);
|
||||
return NULL;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -831,7 +831,7 @@ static const char *get_effector_defname(ePFieldType type)
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field");
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static int effector_add_exec(bContext *C, wmOperator *op)
|
||||
|
@@ -315,8 +315,7 @@ float *SCULPT_geodesic_distances_create(Object *ob,
|
||||
case PBVH_GRIDS:
|
||||
return SCULPT_geodesic_fallback_create(ob, initial_vertices);
|
||||
}
|
||||
BLI_assert(false);
|
||||
return NULL;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd,
|
||||
|
@@ -308,8 +308,7 @@ static const char *buttons_main_region_context_string(const short mainb)
|
||||
}
|
||||
|
||||
/* All the cases should be handled. */
|
||||
BLI_assert(false);
|
||||
return "";
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static void buttons_main_region_layout_properties(const bContext *C,
|
||||
|
@@ -1196,7 +1196,7 @@ static int node_error_type_to_icon(const NodeWarningType type)
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return ICON_ERROR;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static uint8_t node_error_type_priority(const NodeWarningType type)
|
||||
@@ -1209,9 +1209,7 @@ static uint8_t node_error_type_priority(const NodeWarningType type)
|
||||
case NodeWarningType::Info:
|
||||
return 1;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static NodeWarningType node_error_highest_priority(Span<NodeWarning> warnings)
|
||||
|
@@ -61,8 +61,7 @@ template<typename T> class VArraySpanBase {
|
||||
case VArraySpanCategory::StartsAndSizes:
|
||||
return virtual_size_ == 1;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
@@ -127,8 +126,7 @@ template<typename T> class VArraySpan : public VArraySpanBase<T> {
|
||||
return VSpan<T>(Span<T>(this->data_.starts_and_sizes.starts[index],
|
||||
this->data_.starts_and_sizes.sizes[index]));
|
||||
}
|
||||
BLI_assert(false);
|
||||
return {};
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -198,8 +196,7 @@ class GVArraySpan : public VArraySpanBase<void> {
|
||||
return GVSpan(GSpan(
|
||||
*type_, data_.starts_and_sizes.starts[index], data_.starts_and_sizes.sizes[index]));
|
||||
}
|
||||
BLI_assert(false);
|
||||
return GVSpan(*type_);
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -104,8 +104,7 @@ class MFDataType {
|
||||
case Vector:
|
||||
return type_->name() + " Vector";
|
||||
}
|
||||
BLI_assert(false);
|
||||
return "";
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
uint64_t hash() const
|
||||
|
@@ -129,8 +129,7 @@ class MFParamType {
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
return SingleInput;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
bool is_input_or_mutable() const
|
||||
|
@@ -213,8 +213,7 @@ template<typename T> struct VSpanBase {
|
||||
case VSpanCategory::FullPointerArray:
|
||||
return virtual_size_ == 1;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
bool is_full_array() const
|
||||
@@ -227,8 +226,7 @@ template<typename T> struct VSpanBase {
|
||||
case VSpanCategory::FullPointerArray:
|
||||
return virtual_size_ <= 1;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
bool is_empty() const
|
||||
@@ -304,8 +302,7 @@ template<typename T> class VSpan : public VSpanBase<T> {
|
||||
case VSpanCategory::FullPointerArray:
|
||||
return *this->data_.full_pointer_array.data[index];
|
||||
}
|
||||
BLI_assert(false);
|
||||
return *this->data_.single.data;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
const T &as_single_element() const
|
||||
@@ -417,8 +414,7 @@ class GVSpan : public VSpanBase<void> {
|
||||
case VSpanCategory::FullPointerArray:
|
||||
return this->data_.full_pointer_array.data[index];
|
||||
}
|
||||
BLI_assert(false);
|
||||
return this->data_.single.data;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
template<typename T> VSpan<T> typed() const
|
||||
|
@@ -572,8 +572,7 @@ bool MFNetworkEvaluationStorage::is_same_value_for_every_index(const MFOutputSoc
|
||||
case ValueType::OutputVector:
|
||||
return static_cast<OutputVectorValue *>(any_value)->vector_array->size() == 1;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
bool MFNetworkEvaluationStorage::socket_has_buffer_for_output(const MFOutputSocket &socket)
|
||||
@@ -967,9 +966,7 @@ GVSpan MFNetworkEvaluationStorage::get_single_input__full(const MFInputSocket &s
|
||||
BLI_assert(value->is_computed);
|
||||
return value->span;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return GVSpan(CPPType::get<float>());
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
GVSpan MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket)
|
||||
@@ -995,8 +992,7 @@ GVSpan MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket
|
||||
return value->span;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return GVSpan(CPPType::get<float>());
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
GVArraySpan MFNetworkEvaluationStorage::get_vector_input__full(const MFInputSocket &socket)
|
||||
@@ -1022,9 +1018,7 @@ GVArraySpan MFNetworkEvaluationStorage::get_vector_input__full(const MFInputSock
|
||||
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
|
||||
return *value->vector_array;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return GVArraySpan(CPPType::get<float>());
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
GVArraySpan MFNetworkEvaluationStorage::get_vector_input__single(const MFInputSocket &socket)
|
||||
@@ -1048,9 +1042,7 @@ GVArraySpan MFNetworkEvaluationStorage::get_vector_input__single(const MFInputSo
|
||||
BLI_assert(value->vector_array->size() == 1);
|
||||
return *value->vector_array;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return GVArraySpan(CPPType::get<float>());
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -352,8 +352,7 @@ static bool rna_idproperty_ui_set_default(PointerRNA *ptr,
|
||||
IDP_Double(item) = value->d;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@@ -277,8 +277,7 @@ struct DisplaceGridOp {
|
||||
return index_to_object * object_to_world * world_to_texture;
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
return {};
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -74,9 +74,7 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
|
||||
case NODE_BOOLEAN_MATH_NOT:
|
||||
return not_fn;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return blender::fn::dummy_multi_function;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static void node_boolean_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
|
||||
|
@@ -93,9 +93,7 @@ static const blender::fn::MultiFunction &get_multi_function(bNode &node)
|
||||
case NODE_FLOAT_COMPARE_NOT_EQUAL:
|
||||
return not_equal_fn;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return blender::fn::dummy_multi_function;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static void node_float_compare_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
|
||||
|
@@ -104,8 +104,7 @@ static bool operation_use_input_b(const NodeMathOperation operation)
|
||||
case NODE_MATH_TRUNC:
|
||||
return false;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return false;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||
|
@@ -138,9 +138,7 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op
|
||||
case NODE_VECTOR_MATH_LENGTH:
|
||||
return CD_PROP_FLOAT;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return CD_PROP_FLOAT3;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
namespace blender::nodes {
|
||||
|
@@ -67,8 +67,7 @@ static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, con
|
||||
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
|
||||
return verts_num + 1;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
|
||||
@@ -80,8 +79,7 @@ static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, con
|
||||
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
|
||||
return verts_num * 2;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
|
||||
@@ -94,8 +92,7 @@ static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, c
|
||||
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
|
||||
return verts_num * 3;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
|
||||
@@ -108,8 +105,7 @@ static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, con
|
||||
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
|
||||
return verts_num;
|
||||
}
|
||||
BLI_assert(false);
|
||||
return 0;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
static Mesh *create_circle_mesh(const float radius,
|
||||
|
@@ -97,8 +97,7 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
|
||||
return component.attribute_get_constant_for_read_converted(
|
||||
domain, CD_PROP_COLOR, type, &value);
|
||||
}
|
||||
BLI_assert(false);
|
||||
return component.attribute_get_constant_for_read(domain, type, default_value);
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
|
||||
@@ -133,8 +132,7 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
|
||||
return CD_PROP_BOOL;
|
||||
}
|
||||
|
||||
BLI_assert(false);
|
||||
return default_type;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -141,8 +141,7 @@ InputSocketRef &NodeTreeRef::find_input_socket(Map<bNode *, NodeRef *> &node_map
|
||||
return *socket;
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
return *node->inputs_[0];
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
OutputSocketRef &NodeTreeRef::find_output_socket(Map<bNode *, NodeRef *> &node_mapping,
|
||||
@@ -155,8 +154,7 @@ OutputSocketRef &NodeTreeRef::find_output_socket(Map<bNode *, NodeRef *> &node_m
|
||||
return *socket;
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
return *node->outputs_[0];
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
void NodeTreeRef::create_linked_socket_caches()
|
||||
|
@@ -265,8 +265,7 @@ static const blender::fn::MultiFunction &get_multi_function(
|
||||
}
|
||||
|
||||
default:
|
||||
BLI_assert(false);
|
||||
return builder.get_not_implemented_fn();
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -181,8 +181,7 @@ static const blender::fn::MultiFunction &get_multi_function(
|
||||
return fn;
|
||||
}
|
||||
default:
|
||||
BLI_assert(false);
|
||||
return builder.get_not_implemented_fn();
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2298,8 +2298,7 @@ static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatch
|
||||
return target.run(C, op);
|
||||
}
|
||||
}
|
||||
BLI_assert(false);
|
||||
return OPERATOR_CANCELLED;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -468,8 +468,7 @@ static void wm_xr_session_surface_free_data(wmSurface *surface)
|
||||
static wmSurface *wm_xr_session_surface_create(void)
|
||||
{
|
||||
if (g_xr_surface) {
|
||||
BLI_assert(false);
|
||||
return g_xr_surface;
|
||||
BLI_UNREACHABLE_ABORT;
|
||||
}
|
||||
|
||||
wmSurface *surface = MEM_callocN(sizeof(*surface), __func__);
|
||||
|
Reference in New Issue
Block a user