Commit 342cfb3e by Jakub Jelinek Committed by Jakub Jelinek

Implement P0258R2 - helper for C++17 std::has_unique_object_representations trait c-family/

	Implement P0258R2 - helper for C++17
	std::has_unique_object_representations trait
c-family/
	* c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* c-common.c (c_common_reswords): Add
	__has_unique_object_representations.
cp/
	* cp-tree.h (enum cp_trait_kind): Add
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(struct lang_type_class): Add unique_obj_representations
	and unique_obj_representations_set bitfields.
	(CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS,
	CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET): Define.
	(type_has_unique_obj_representations): Declare.
	* parser.c (cp_parser_primary_expression): Handle
	RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(cp_parser_trait_expr): Likewise.  Formatting fix.
	* semantics.c (trait_expr_value, finish_trait_expr): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* tree.c (type_has_unique_obj_representations): New function.
	(record_has_unique_obj_representations): New function.
	* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
testsuite/
	* g++.dg/cpp1z/has-unique-obj-representations1.C: New test.
	* g++.dg/cpp1z/has-unique-obj-representations2.C: New test.

From-SVN: r240843
parent 48057089
2016-10-06 Jakub Jelinek <jakub@redhat.com>
Implement P0258R2 - helper for C++17
std::has_unique_object_representations trait
* c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
* c-common.c (c_common_reswords): Add
__has_unique_object_representations.
2016-10-05 Jakub Jelinek <jakub@redhat.com> 2016-10-05 Jakub Jelinek <jakub@redhat.com>
PR sanitizer/66343 PR sanitizer/66343
......
...@@ -486,6 +486,8 @@ const struct c_common_resword c_common_reswords[] = ...@@ -486,6 +486,8 @@ const struct c_common_resword c_common_reswords[] =
{ "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY },
{ "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY }, { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY },
{ "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY }, { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY },
{ "__has_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
D_CXXONLY },
{ "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY }, { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY },
{ "__imag", RID_IMAGPART, 0 }, { "__imag", RID_IMAGPART, 0 },
{ "__imag__", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 },
......
...@@ -150,7 +150,8 @@ enum rid ...@@ -150,7 +150,8 @@ enum rid
RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR,
RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN,
RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY,
RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_VIRTUAL_DESTRUCTOR, RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
RID_HAS_VIRTUAL_DESTRUCTOR,
RID_IS_ABSTRACT, RID_IS_BASE_OF, RID_IS_ABSTRACT, RID_IS_BASE_OF,
RID_IS_CLASS, RID_IS_CLASS,
RID_IS_EMPTY, RID_IS_ENUM, RID_IS_EMPTY, RID_IS_ENUM,
......
2016-10-06 Jakub Jelinek <jakub@redhat.com>
Implement P0258R2 - helper for C++17
std::has_unique_object_representations trait
* cp-tree.h (enum cp_trait_kind): Add
CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
(struct lang_type_class): Add unique_obj_representations
and unique_obj_representations_set bitfields.
(CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS,
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET): Define.
(type_has_unique_obj_representations): Declare.
* parser.c (cp_parser_primary_expression): Handle
RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
(cp_parser_trait_expr): Likewise. Formatting fix.
* semantics.c (trait_expr_value, finish_trait_expr): Handle
CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
* tree.c (type_has_unique_obj_representations): New function.
(record_has_unique_obj_representations): New function.
* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
2016-10-05 Jason Merrill <jason@redhat.com> 2016-10-05 Jason Merrill <jason@redhat.com>
Implement P0135R1, Guaranteed copy elision. Implement P0135R1, Guaranteed copy elision.
......
...@@ -723,6 +723,7 @@ enum cp_trait_kind ...@@ -723,6 +723,7 @@ enum cp_trait_kind
CPTK_HAS_TRIVIAL_CONSTRUCTOR, CPTK_HAS_TRIVIAL_CONSTRUCTOR,
CPTK_HAS_TRIVIAL_COPY, CPTK_HAS_TRIVIAL_COPY,
CPTK_HAS_TRIVIAL_DESTRUCTOR, CPTK_HAS_TRIVIAL_DESTRUCTOR,
CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS,
CPTK_HAS_VIRTUAL_DESTRUCTOR, CPTK_HAS_VIRTUAL_DESTRUCTOR,
CPTK_IS_ABSTRACT, CPTK_IS_ABSTRACT,
CPTK_IS_BASE_OF, CPTK_IS_BASE_OF,
...@@ -1713,6 +1714,8 @@ struct GTY(()) lang_type_class { ...@@ -1713,6 +1714,8 @@ struct GTY(()) lang_type_class {
unsigned has_complex_move_ctor : 1; unsigned has_complex_move_ctor : 1;
unsigned has_complex_move_assign : 1; unsigned has_complex_move_assign : 1;
unsigned has_constexpr_ctor : 1; unsigned has_constexpr_ctor : 1;
unsigned unique_obj_representations : 1;
unsigned unique_obj_representations_set : 1;
/* When adding a flag here, consider whether or not it ought to /* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If apply to a template instance if it applies to the template. If
...@@ -1721,7 +1724,7 @@ struct GTY(()) lang_type_class { ...@@ -1721,7 +1724,7 @@ struct GTY(()) lang_type_class {
/* There are some bits left to fill out a 32-bit word. Keep track /* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or of this by updating the size of this bitfield whenever you add or
remove a flag. */ remove a flag. */
unsigned dummy : 4; unsigned dummy : 2;
tree primary_base; tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices; vec<tree_pair_s, va_gc> *vcall_indices;
...@@ -2010,6 +2013,16 @@ struct GTY(()) lang_type { ...@@ -2010,6 +2013,16 @@ struct GTY(()) lang_type {
#define CLASSTYPE_NON_STD_LAYOUT(NODE) \ #define CLASSTYPE_NON_STD_LAYOUT(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->non_std_layout) (LANG_TYPE_CLASS_CHECK (NODE)->non_std_layout)
/* Nonzero means that this class type does have unique object
representations. */
#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations)
/* Nonzero means that this class type has
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS computed. */
#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations_set)
/* Nonzero means that this class contains pod types whose default /* Nonzero means that this class contains pod types whose default
initialization is not a zero initialization (namely, pointers to initialization is not a zero initialization (namely, pointers to
data members). */ data members). */
...@@ -6480,6 +6493,7 @@ extern bool layout_pod_type_p (const_tree); ...@@ -6480,6 +6493,7 @@ extern bool layout_pod_type_p (const_tree);
extern bool std_layout_type_p (const_tree); extern bool std_layout_type_p (const_tree);
extern bool trivial_type_p (const_tree); extern bool trivial_type_p (const_tree);
extern bool trivially_copyable_p (const_tree); extern bool trivially_copyable_p (const_tree);
extern bool type_has_unique_obj_representations (const_tree);
extern bool scalarish_type_p (const_tree); extern bool scalarish_type_p (const_tree);
extern bool type_has_nontrivial_default_init (const_tree); extern bool type_has_nontrivial_default_init (const_tree);
extern bool type_has_nontrivial_copy_init (const_tree); extern bool type_has_nontrivial_copy_init (const_tree);
......
...@@ -2561,6 +2561,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) ...@@ -2561,6 +2561,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
case CPTK_HAS_TRIVIAL_DESTRUCTOR: case CPTK_HAS_TRIVIAL_DESTRUCTOR:
pp_cxx_ws_string (pp, "__has_trivial_destructor"); pp_cxx_ws_string (pp, "__has_trivial_destructor");
break; break;
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
pp_cxx_ws_string (pp, "__has_unique_object_representations");
break;
case CPTK_HAS_VIRTUAL_DESTRUCTOR: case CPTK_HAS_VIRTUAL_DESTRUCTOR:
pp_cxx_ws_string (pp, "__has_virtual_destructor"); pp_cxx_ws_string (pp, "__has_virtual_destructor");
break; break;
......
...@@ -5110,6 +5110,7 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -5110,6 +5110,7 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_HAS_TRIVIAL_CONSTRUCTOR: case RID_HAS_TRIVIAL_CONSTRUCTOR:
case RID_HAS_TRIVIAL_COPY: case RID_HAS_TRIVIAL_COPY:
case RID_HAS_TRIVIAL_DESTRUCTOR: case RID_HAS_TRIVIAL_DESTRUCTOR:
case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
case RID_HAS_VIRTUAL_DESTRUCTOR: case RID_HAS_VIRTUAL_DESTRUCTOR:
case RID_IS_ABSTRACT: case RID_IS_ABSTRACT:
case RID_IS_BASE_OF: case RID_IS_BASE_OF:
...@@ -9521,6 +9522,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) ...@@ -9521,6 +9522,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
case RID_HAS_TRIVIAL_DESTRUCTOR: case RID_HAS_TRIVIAL_DESTRUCTOR:
kind = CPTK_HAS_TRIVIAL_DESTRUCTOR; kind = CPTK_HAS_TRIVIAL_DESTRUCTOR;
break; break;
case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS;
break;
case RID_HAS_VIRTUAL_DESTRUCTOR: case RID_HAS_VIRTUAL_DESTRUCTOR:
kind = CPTK_HAS_VIRTUAL_DESTRUCTOR; kind = CPTK_HAS_VIRTUAL_DESTRUCTOR;
break; break;
...@@ -9635,7 +9639,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) ...@@ -9635,7 +9639,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
/* Complete the trait expression, which may mean either processing /* Complete the trait expression, which may mean either processing
the trait expr now or saving it for template instantiation. */ the trait expr now or saving it for template instantiation. */
switch(kind) switch (kind)
{ {
case CPTK_UNDERLYING_TYPE: case CPTK_UNDERLYING_TYPE:
return finish_underlying_type (type1); return finish_underlying_type (type1);
...@@ -9092,6 +9092,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) ...@@ -9092,6 +9092,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_HAS_VIRTUAL_DESTRUCTOR: case CPTK_HAS_VIRTUAL_DESTRUCTOR:
return type_has_virtual_destructor (type1); return type_has_virtual_destructor (type1);
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
return type_has_unique_obj_representations (type1);
case CPTK_IS_ABSTRACT: case CPTK_IS_ABSTRACT:
return (ABSTRACT_CLASS_TYPE_P (type1)); return (ABSTRACT_CLASS_TYPE_P (type1));
...@@ -9199,6 +9202,7 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) ...@@ -9199,6 +9202,7 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
case CPTK_HAS_NOTHROW_COPY: case CPTK_HAS_NOTHROW_COPY:
case CPTK_HAS_TRIVIAL_COPY: case CPTK_HAS_TRIVIAL_COPY:
case CPTK_HAS_TRIVIAL_DESTRUCTOR: case CPTK_HAS_TRIVIAL_DESTRUCTOR:
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
case CPTK_HAS_VIRTUAL_DESTRUCTOR: case CPTK_HAS_VIRTUAL_DESTRUCTOR:
case CPTK_IS_ABSTRACT: case CPTK_IS_ABSTRACT:
case CPTK_IS_EMPTY: case CPTK_IS_EMPTY:
......
...@@ -3575,6 +3575,150 @@ std_layout_type_p (const_tree t) ...@@ -3575,6 +3575,150 @@ std_layout_type_p (const_tree t)
return scalarish_type_p (t); return scalarish_type_p (t);
} }
static bool record_has_unique_obj_representations (const_tree, const_tree);
/* Returns true iff T satisfies std::has_unique_object_representations<T>,
as defined in [meta.unary.prop]. */
bool
type_has_unique_obj_representations (const_tree t)
{
bool ret;
t = strip_array_types (CONST_CAST_TREE (t));
if (!trivially_copyable_p (t))
return false;
if (CLASS_TYPE_P (t) && CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t))
return CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t);
switch (TREE_CODE (t))
{
case INTEGER_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
/* If some backend has any paddings in these types, we should add
a target hook for this and handle it there. */
return true;
case BOOLEAN_TYPE:
/* For bool values other than 0 and 1 should only appear with
undefined behavior. */
return true;
case ENUMERAL_TYPE:
return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));
case REAL_TYPE:
/* XFmode certainly contains padding on x86, which the CPU doesn't store
when storing long double values, so for that we have to return false.
Other kinds of floating point values are questionable due to +.0/-.0
and NaNs, let's play safe for now. */
return false;
case FIXED_POINT_TYPE:
return false;
case OFFSET_TYPE:
return true;
case COMPLEX_TYPE:
case VECTOR_TYPE:
return type_has_unique_obj_representations (TREE_TYPE (t));
case RECORD_TYPE:
ret = record_has_unique_obj_representations (t, TYPE_SIZE (t));
if (CLASS_TYPE_P (t))
{
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
}
return ret;
case UNION_TYPE:
ret = true;
bool any_fields;
any_fields = false;
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
any_fields = true;
if (!type_has_unique_obj_representations (TREE_TYPE (field))
|| simple_cst_equal (DECL_SIZE (field), TYPE_SIZE (t)) != 1)
{
ret = false;
break;
}
}
if (!any_fields && !integer_zerop (TYPE_SIZE (t)))
ret = false;
if (CLASS_TYPE_P (t))
{
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
}
return ret;
case NULLPTR_TYPE:
return false;
case ERROR_MARK:
return false;
default:
gcc_unreachable ();
}
}
/* Helper function for type_has_unique_obj_representations. */
static bool
record_has_unique_obj_representations (const_tree t, const_tree sz)
{
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) != FIELD_DECL)
;
/* For bases, can't use type_has_unique_obj_representations here, as in
struct S { int i : 24; S (); };
struct T : public S { int j : 8; T (); };
S doesn't have unique obj representations, but T does. */
else if (DECL_FIELD_IS_BASE (field))
{
if (!record_has_unique_obj_representations (TREE_TYPE (field),
DECL_SIZE (field)))
return false;
}
else if (DECL_C_BIT_FIELD (field))
{
tree btype = DECL_BIT_FIELD_TYPE (field);
if (!type_has_unique_obj_representations (btype))
return false;
}
else if (!type_has_unique_obj_representations (TREE_TYPE (field)))
return false;
offset_int cur = 0;
for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
offset_int fld = wi::to_offset (DECL_FIELD_OFFSET (field));
offset_int bitpos = wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
fld = fld * BITS_PER_UNIT + bitpos;
if (cur != fld)
return false;
if (DECL_SIZE (field))
{
offset_int size = wi::to_offset (DECL_SIZE (field));
cur += size;
}
}
if (cur != wi::to_offset (sz))
return false;
return true;
}
/* Nonzero iff type T is a class template implicit specialization. */ /* Nonzero iff type T is a class template implicit specialization. */
bool bool
......
2016-10-06 Jakub Jelinek <jakub@redhat.com>
* g++.dg/cpp1z/has-unique-obj-representations1.C: New test.
* g++.dg/cpp1z/has-unique-obj-representations2.C: New test.
2016-10-06 Kugan Vivekanandarajah <kuganv@linaro.org> 2016-10-06 Kugan Vivekanandarajah <kuganv@linaro.org>
PR tree-optimization/77862 PR tree-optimization/77862
......
// { dg-do compile { target c++11 } }
#define INTB (__SIZEOF_INT__ * __CHAR_BIT__)
struct S { int i : INTB * 3 / 4; S (); };
struct T : public S { int j : INTB / 4; T (); };
struct U { int i : INTB * 3 / 4; int j : INTB / 4; };
struct V { int i : INTB * 3 / 4; int j : INTB / 4 + 1; };
struct W {};
struct X : public W { int i; void bar (); };
struct Y { char a[3]; char b[]; };
struct Z { int a; float b; };
struct A { int i : INTB * 2; int j; }; // { dg-warning "exceeds its type" }
union B { long a; unsigned long b; };
union C { int a; int b : INTB - 1; };
struct D { int a : INTB + 1; int b : INTB - 1; }; // { dg-warning "exceeds its type" }
static_assert (__has_unique_object_representations (char) == true, "");
static_assert (__has_unique_object_representations (unsigned char) == true, "");
static_assert (__has_unique_object_representations (int) == true, "");
static_assert (__has_unique_object_representations (unsigned int) == true, "");
static_assert (__has_unique_object_representations (bool) == true, "");
static_assert (sizeof (S) != sizeof (int) || __has_unique_object_representations (S) == false, "");
static_assert (sizeof (T) != sizeof (int) || __has_unique_object_representations (T) == true, "");
static_assert (sizeof (U) != sizeof (int) || __has_unique_object_representations (U) == true, "");
static_assert (__has_unique_object_representations (V) == false, "");
static_assert (__has_unique_object_representations (W) == false, "");
static_assert (sizeof (X) != sizeof (int) || __has_unique_object_representations (X) == true, "");
static_assert (__has_unique_object_representations (float) == false, "");
static_assert (__has_unique_object_representations (double) == false, "");
static_assert (__has_unique_object_representations (long double) == false, "");
static_assert (__has_unique_object_representations (void) == false, "");
static_assert (__has_unique_object_representations (_Complex int) == true, "");
static_assert (__has_unique_object_representations (_Complex float) == false, "");
static_assert (__has_unique_object_representations (_Complex double) == false, "");
static_assert (__has_unique_object_representations (_Complex long double) == false, "");
static_assert (__has_unique_object_representations (int __attribute__((vector_size (16)))) == true, "");
static_assert (__has_unique_object_representations (float __attribute__((vector_size (16)))) == false, "");
static_assert (__has_unique_object_representations (int X::*) == true, "");
static_assert (__has_unique_object_representations (void (X::*) ()) == true, "");
static_assert (__has_unique_object_representations (int *) == true, "");
static_assert (__has_unique_object_representations (int (*) ()) == true, "");
static_assert (__has_unique_object_representations (decltype (nullptr)) == false, "");
static_assert (__has_unique_object_representations (Y) == (sizeof (Y) == 3 * sizeof (char)), "");
static_assert (__has_unique_object_representations (Z) == false, "");
static_assert (__has_unique_object_representations (A) == false, "");
static_assert (sizeof (B) != sizeof (long) || __has_unique_object_representations (B) == true, "");
static_assert (__has_unique_object_representations (C) == false, "");
static_assert (__has_unique_object_representations (D) == false, "");
struct S;
struct T { S t; }; // { dg-error "incomplete type" }
struct U { int u[sizeof (S)]; }; // { dg-error "incomplete type" }
union V { char c; char d[]; }; // { dg-error "flexible array member in union" }
bool a = __has_unique_object_representations (S); // { dg-error "incomplete type" }
bool b = __has_unique_object_representations (T);
bool c = __has_unique_object_representations (U);
bool d = __has_unique_object_representations (V);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment