From 342cfb3e736afcc7397b4199a4c96fb602f5d68b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 6 Oct 2016 23:17:44 +0200 Subject: [PATCH] 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 --- gcc/c-family/ChangeLog | 8 + gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 3 +- gcc/cp/ChangeLog | 21 +++ gcc/cp/cp-tree.h | 16 +- gcc/cp/cxx-pretty-print.c | 3 + gcc/cp/parser.c | 6 +- gcc/cp/semantics.c | 4 + gcc/cp/tree.c | 144 ++++++++++++++++++ gcc/testsuite/ChangeLog | 5 + .../cpp1z/has-unique-obj-representations1.C | 47 ++++++ .../cpp1z/has-unique-obj-representations2.C | 8 + 12 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6474a6dd6f6..7881233f94c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,11 @@ +2016-10-06 Jakub Jelinek + + 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 PR sanitizer/66343 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 035afbceeb8..f518c20797f 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -486,6 +486,8 @@ const struct c_common_resword c_common_reswords[] = { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY }, { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, 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 }, { "__imag", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 28aebec6e2e..f9ebb5bca2f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -150,7 +150,8 @@ enum rid RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, 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_CLASS, RID_IS_EMPTY, RID_IS_ENUM, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7bd7db64f4e..008d6461acf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2016-10-06 Jakub Jelinek + + 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 Implement P0135R1, Guaranteed copy elision. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 92e40170f5b..49cbdf26fcf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -723,6 +723,7 @@ enum cp_trait_kind CPTK_HAS_TRIVIAL_CONSTRUCTOR, CPTK_HAS_TRIVIAL_COPY, CPTK_HAS_TRIVIAL_DESTRUCTOR, + CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS, CPTK_HAS_VIRTUAL_DESTRUCTOR, CPTK_IS_ABSTRACT, CPTK_IS_BASE_OF, @@ -1713,6 +1714,8 @@ struct GTY(()) lang_type_class { unsigned has_complex_move_ctor : 1; unsigned has_complex_move_assign : 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 apply to a template instance if it applies to the template. If @@ -1721,7 +1724,7 @@ struct GTY(()) lang_type_class { /* 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 remove a flag. */ - unsigned dummy : 4; + unsigned dummy : 2; tree primary_base; vec *vcall_indices; @@ -2010,6 +2013,16 @@ struct GTY(()) lang_type { #define CLASSTYPE_NON_STD_LAYOUT(NODE) \ (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 initialization is not a zero initialization (namely, pointers to data members). */ @@ -6480,6 +6493,7 @@ extern bool layout_pod_type_p (const_tree); extern bool std_layout_type_p (const_tree); extern bool trivial_type_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 type_has_nontrivial_default_init (const_tree); extern bool type_has_nontrivial_copy_init (const_tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index a290c87a9dd..68dcf58ea1c 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2561,6 +2561,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_HAS_TRIVIAL_DESTRUCTOR: pp_cxx_ws_string (pp, "__has_trivial_destructor"); break; + case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: + pp_cxx_ws_string (pp, "__has_unique_object_representations"); + break; case CPTK_HAS_VIRTUAL_DESTRUCTOR: pp_cxx_ws_string (pp, "__has_virtual_destructor"); break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 60bbf49883c..c2bd4421e14 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5110,6 +5110,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_HAS_TRIVIAL_CONSTRUCTOR: case RID_HAS_TRIVIAL_COPY: case RID_HAS_TRIVIAL_DESTRUCTOR: + case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: case RID_HAS_VIRTUAL_DESTRUCTOR: case RID_IS_ABSTRACT: case RID_IS_BASE_OF: @@ -9521,6 +9522,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_HAS_TRIVIAL_DESTRUCTOR: kind = CPTK_HAS_TRIVIAL_DESTRUCTOR; break; + case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS: + kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS; + break; case RID_HAS_VIRTUAL_DESTRUCTOR: kind = CPTK_HAS_VIRTUAL_DESTRUCTOR; break; @@ -9635,7 +9639,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) /* Complete the trait expression, which may mean either processing the trait expr now or saving it for template instantiation. */ - switch(kind) + switch (kind) { case CPTK_UNDERLYING_TYPE: return finish_underlying_type (type1); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 1b19f600cb7..968f88b3c04 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9092,6 +9092,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_VIRTUAL_DESTRUCTOR: return type_has_virtual_destructor (type1); + case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: + return type_has_unique_obj_representations (type1); + case CPTK_IS_ABSTRACT: return (ABSTRACT_CLASS_TYPE_P (type1)); @@ -9199,6 +9202,7 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) case CPTK_HAS_NOTHROW_COPY: case CPTK_HAS_TRIVIAL_COPY: case CPTK_HAS_TRIVIAL_DESTRUCTOR: + case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS: case CPTK_HAS_VIRTUAL_DESTRUCTOR: case CPTK_IS_ABSTRACT: case CPTK_IS_EMPTY: diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c3853e370d1..03eef0030d0 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3575,6 +3575,150 @@ std_layout_type_p (const_tree 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, + 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. */ bool diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 24026c80d47..9aee1b289ea 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-10-06 Jakub Jelinek + + * 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 PR tree-optimization/77862 diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C new file mode 100644 index 00000000000..73d80bfc691 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C @@ -0,0 +1,47 @@ +// { 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, ""); diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C new file mode 100644 index 00000000000..c4ae555a92e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C @@ -0,0 +1,8 @@ +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); -- 2.30.2