Implement LWG2296 helper intrinsic c-family/

Implement LWG2296 helper intrinsic
c-family/
	* c-common.h (enum rid): Add RID_ADDRESSOF.
	* c-common.c (c_common_reswords): Add __builtin_addressof.
cp/
	* parser.c (cp_parser_postfix_expression): Handle RID_ADDRESSOF.
	* cp-objcp-common.c (cp_common_init_ts): Handle ADDRESSOF_EXPR.
	* constexpr.c (potential_constant_expression_1): Likewise.
	* error.c (dump_expr): Likewise.
	* typeck.c (cp_build_addressof): New function.
	* cp-tree.h (cp_build_addressof): Declare.
	* cxx-pretty-print.h (pp_cxx_addressof_expression): Declare.
	* cp-tree.def (ADDRESSOF_EXPR): New tree code.
	* cxx-pretty-print.c (cxx_pretty_printer::primary_expression): Handle
	ADDRESSOF_EXPR.  Add __builtin_addressof and
	__has_unique_object_representations into syntax in function comment.
	(pp_cxx_addressof_expression): New function.
	* pt.c (tsubst_copy_and_build): Handle ADDRESSOF_EXPR.
testsuite/
	* g++.dg/cpp0x/addressof1.C: New test.
	* g++.dg/cpp0x/addressof2.C: New test.

From-SVN: r240873
This commit is contained in:
Jakub Jelinek 2016-10-07 21:37:46 +02:00 committed by Jakub Jelinek
parent 082139830a
commit be845b04a8
17 changed files with 244 additions and 13 deletions

View File

@ -1,3 +1,9 @@
2016-10-07 Jakub Jelinek <jakub@redhat.com>
Implement LWG2296 helper intrinsic
* c-common.h (enum rid): Add RID_ADDRESSOF.
* c-common.c (c_common_reswords): Add __builtin_addressof.
2016-10-07 Bernd Edlinger <bernd.edlinger@hotmail.de> 2016-10-07 Bernd Edlinger <bernd.edlinger@hotmail.de>
PR c++/77700 PR c++/77700

View File

@ -463,6 +463,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__attribute__", RID_ATTRIBUTE, 0 }, { "__attribute__", RID_ATTRIBUTE, 0 },
{ "__auto_type", RID_AUTO_TYPE, D_CONLY }, { "__auto_type", RID_AUTO_TYPE, D_CONLY },
{ "__bases", RID_BASES, D_CXXONLY }, { "__bases", RID_BASES, D_CXXONLY },
{ "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY },
{ "__builtin_call_with_static_chain", { "__builtin_call_with_static_chain",
RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY }, RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
{ "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },

View File

@ -146,6 +146,7 @@ enum rid
RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
/* C++ extensions */ /* C++ extensions */
RID_ADDRESSOF,
RID_BASES, RID_DIRECT_BASES, RID_BASES, RID_DIRECT_BASES,
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,

View File

@ -1,3 +1,20 @@
2016-10-07 Jakub Jelinek <jakub@redhat.com>
Implement LWG2296 helper intrinsic
* parser.c (cp_parser_postfix_expression): Handle RID_ADDRESSOF.
* cp-objcp-common.c (cp_common_init_ts): Handle ADDRESSOF_EXPR.
* constexpr.c (potential_constant_expression_1): Likewise.
* error.c (dump_expr): Likewise.
* typeck.c (cp_build_addressof): New function.
* cp-tree.h (cp_build_addressof): Declare.
* cxx-pretty-print.h (pp_cxx_addressof_expression): Declare.
* cp-tree.def (ADDRESSOF_EXPR): New tree code.
* cxx-pretty-print.c (cxx_pretty_printer::primary_expression): Handle
ADDRESSOF_EXPR. Add __builtin_addressof and
__has_unique_object_representations into syntax in function comment.
(pp_cxx_addressof_expression): New function.
* pt.c (tsubst_copy_and_build): Handle ADDRESSOF_EXPR.
2016-10-07 Bernd Edlinger <bernd.edlinger@hotmail.de> 2016-10-07 Bernd Edlinger <bernd.edlinger@hotmail.de>
PR c++/77700 PR c++/77700

View File

@ -5025,6 +5025,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR)); return (RECUR (from, TREE_CODE (t) != VIEW_CONVERT_EXPR));
} }
case ADDRESSOF_EXPR:
/* This is like ADDR_EXPR, except it won't form pointer-to-member. */
t = TREE_OPERAND (t, 0);
goto handle_addr_expr;
case ADDR_EXPR: case ADDR_EXPR:
/* -- a unary operator & that is applied to an lvalue that /* -- a unary operator & that is applied to an lvalue that
designates an object with thread or automatic storage designates an object with thread or automatic storage
@ -5035,6 +5040,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
/* A pointer-to-member constant. */ /* A pointer-to-member constant. */
return true; return true;
handle_addr_expr:
#if 0 #if 0
/* FIXME adjust when issue 1197 is fully resolved. For now don't do /* FIXME adjust when issue 1197 is fully resolved. For now don't do
any checking here, as we might dereference the pointer later. If any checking here, as we might dereference the pointer later. If

View File

@ -315,6 +315,7 @@ cp_common_init_ts (void)
MARK_TS_TYPED (STMT_EXPR); MARK_TS_TYPED (STMT_EXPR);
MARK_TS_TYPED (OFFSET_REF); MARK_TS_TYPED (OFFSET_REF);
MARK_TS_TYPED (OFFSETOF_EXPR); MARK_TS_TYPED (OFFSETOF_EXPR);
MARK_TS_TYPED (ADDRESSOF_EXPR);
MARK_TS_TYPED (PTRMEM_CST); MARK_TS_TYPED (PTRMEM_CST);
MARK_TS_TYPED (EMPTY_CLASS_EXPR); MARK_TS_TYPED (EMPTY_CLASS_EXPR);
MARK_TS_TYPED (VEC_INIT_EXPR); MARK_TS_TYPED (VEC_INIT_EXPR);

View File

@ -334,6 +334,11 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_expression, 0)
/* Represents an 'offsetof' expression during template expansion. */ /* Represents an 'offsetof' expression during template expansion. */
DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", tcc_expression, 1) DEFTREECODE (OFFSETOF_EXPR, "offsetof_expr", tcc_expression, 1)
/* Represents an '__builtin_addressof' expression during template
expansion. This is similar to ADDR_EXPR, but it doesn't invoke
overloaded & operators. */
DEFTREECODE (ADDRESSOF_EXPR, "addressof_expr", tcc_expression, 1)
/* Represents the -> operator during template expansion. */ /* Represents the -> operator during template expansion. */
DEFTREECODE (ARROW_EXPR, "arrow_expr", tcc_expression, 1) DEFTREECODE (ARROW_EXPR, "arrow_expr", tcc_expression, 1)

View File

@ -6658,6 +6658,8 @@ extern tree build_x_array_ref (location_t, tree, tree,
extern tree build_x_unary_op (location_t, extern tree build_x_unary_op (location_t,
enum tree_code, cp_expr, enum tree_code, cp_expr,
tsubst_flags_t); tsubst_flags_t);
extern tree cp_build_addressof (location_t, tree,
tsubst_flags_t);
extern tree cp_build_addr_expr (tree, tsubst_flags_t); extern tree cp_build_addr_expr (tree, tsubst_flags_t);
extern tree cp_build_unary_op (enum tree_code, tree, bool, extern tree cp_build_unary_op (enum tree_code, tree, bool,
tsubst_flags_t); tsubst_flags_t);

View File

@ -380,6 +380,7 @@ pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t)
GNU Extensions: GNU Extensions:
__builtin_va_arg ( assignment-expression , type-id ) __builtin_va_arg ( assignment-expression , type-id )
__builtin_offsetof ( type-id, offsetof-expression ) __builtin_offsetof ( type-id, offsetof-expression )
__builtin_addressof ( expression )
__has_nothrow_assign ( type-id ) __has_nothrow_assign ( type-id )
__has_nothrow_constructor ( type-id ) __has_nothrow_constructor ( type-id )
@ -387,6 +388,7 @@ pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t)
__has_trivial_assign ( type-id ) __has_trivial_assign ( type-id )
__has_trivial_constructor ( type-id ) __has_trivial_constructor ( type-id )
__has_trivial_copy ( type-id ) __has_trivial_copy ( type-id )
__has_unique_object_representations ( type-id )
__has_trivial_destructor ( type-id ) __has_trivial_destructor ( type-id )
__has_virtual_destructor ( type-id ) __has_virtual_destructor ( type-id )
__is_abstract ( type-id ) __is_abstract ( type-id )
@ -456,6 +458,10 @@ cxx_pretty_printer::primary_expression (tree t)
pp_cxx_offsetof_expression (this, t); pp_cxx_offsetof_expression (this, t);
break; break;
case ADDRESSOF_EXPR:
pp_cxx_addressof_expression (this, t);
break;
case REQUIRES_EXPR: case REQUIRES_EXPR:
pp_cxx_requires_expr (this, t); pp_cxx_requires_expr (this, t);
break; break;
@ -2437,6 +2443,15 @@ pp_cxx_offsetof_expression (cxx_pretty_printer *pp, tree t)
pp_cxx_right_paren (pp); pp_cxx_right_paren (pp);
} }
void
pp_cxx_addressof_expression (cxx_pretty_printer *pp, tree t)
{
pp_cxx_ws_string (pp, "__builtin_addressof");
pp_cxx_left_paren (pp);
pp->expression (TREE_OPERAND (t, 0));
pp_cxx_right_paren (pp);
}
static char const* static char const*
get_fold_operator (tree t) get_fold_operator (tree t)
{ {

View File

@ -90,6 +90,7 @@ void pp_cxx_canonical_template_parameter (cxx_pretty_printer *, tree);
void pp_cxx_trait_expression (cxx_pretty_printer *, tree); void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree); void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree); void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
void pp_cxx_addressof_expression (cxx_pretty_printer *, tree);
void pp_cxx_userdef_literal (cxx_pretty_printer *, tree); void pp_cxx_userdef_literal (cxx_pretty_printer *, tree);
void pp_cxx_requires_clause (cxx_pretty_printer *, tree); void pp_cxx_requires_clause (cxx_pretty_printer *, tree);
void pp_cxx_requires_expr (cxx_pretty_printer *, tree); void pp_cxx_requires_expr (cxx_pretty_printer *, tree);

View File

@ -2678,6 +2678,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_offsetof_expression (pp, t); pp_cxx_offsetof_expression (pp, t);
break; break;
case ADDRESSOF_EXPR:
pp_cxx_addressof_expression (pp, t);
break;
case SCOPE_REF: case SCOPE_REF:
dump_decl (pp, t, flags); dump_decl (pp, t, flags);
break; break;

View File

@ -6602,6 +6602,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
break; break;
} }
case RID_ADDRESSOF:
case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLE:
{ {
vec<tree, va_gc> *vec; vec<tree, va_gc> *vec;
@ -6618,19 +6619,29 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
FOR_EACH_VEC_ELT (*vec, i, p) FOR_EACH_VEC_ELT (*vec, i, p)
mark_exp_read (p); mark_exp_read (p);
if (vec->length () == 2) switch (keyword)
return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE, (*vec)[1], {
tf_warning_or_error); case RID_ADDRESSOF:
else if (vec->length () == 3) if (vec->length () == 1)
return build_x_vec_perm_expr (loc, (*vec)[0], (*vec)[1], (*vec)[2], return cp_build_addressof (loc, (*vec)[0], tf_warning_or_error);
tf_warning_or_error); error_at (loc, "wrong number of arguments to "
else "%<__builtin_addressof%>");
{ return error_mark_node;
error_at (loc, "wrong number of arguments to "
"%<__builtin_shuffle%>"); case RID_BUILTIN_SHUFFLE:
return error_mark_node; if (vec->length () == 2)
} return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE,
break; (*vec)[1], tf_warning_or_error);
else if (vec->length () == 3)
return build_x_vec_perm_expr (loc, (*vec)[0], (*vec)[1],
(*vec)[2], tf_warning_or_error);
error_at (loc, "wrong number of arguments to "
"%<__builtin_shuffle%>");
return error_mark_node;
default:
gcc_unreachable ();
}
} }
default: default:

View File

@ -17204,6 +17204,10 @@ tsubst_copy_and_build (tree t,
RETURN (finish_offsetof (RECUR (TREE_OPERAND (t, 0)), RETURN (finish_offsetof (RECUR (TREE_OPERAND (t, 0)),
EXPR_LOCATION (t))); EXPR_LOCATION (t)));
case ADDRESSOF_EXPR:
RETURN (cp_build_addressof (EXPR_LOCATION (t),
RECUR (TREE_OPERAND (t, 0)), complain));
case TRAIT_EXPR: case TRAIT_EXPR:
{ {
tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args, tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args,

View File

@ -5456,6 +5456,29 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
return exp; return exp;
} }
/* Construct and perhaps optimize a tree representation
for __builtin_addressof operation. ARG specifies the operand. */
tree
cp_build_addressof (location_t loc, tree arg, tsubst_flags_t complain)
{
tree orig_expr = arg;
if (processing_template_decl)
{
if (type_dependent_expression_p (arg))
return build_min_nt_loc (loc, ADDRESSOF_EXPR, arg, NULL_TREE);
arg = build_non_dependent_expr (arg);
}
tree exp = cp_build_addr_expr_strict (arg, complain);
if (processing_template_decl && exp != error_mark_node)
exp = build_min_non_dep (ADDRESSOF_EXPR, exp, orig_expr, NULL_TREE);
return exp;
}
/* Like c_common_truthvalue_conversion, but handle pointer-to-member /* Like c_common_truthvalue_conversion, but handle pointer-to-member
constants, where a null value is represented by an INTEGER_CST of constants, where a null value is represented by an INTEGER_CST of
-1. */ -1. */

View File

@ -1,3 +1,8 @@
2016-10-07 Jakub Jelinek <jakub@redhat.com>
* g++.dg/cpp0x/addressof1.C: New test.
* g++.dg/cpp0x/addressof2.C: New test.
2016-10-06 Michael Meissner <meissner@linux.vnet.ibm.com> 2016-10-06 Michael Meissner <meissner@linux.vnet.ibm.com>
* gcc.target/powerpc/float128-type-1.c: New test to check that * gcc.target/powerpc/float128-type-1.c: New test to check that

View File

@ -0,0 +1,96 @@
// LWG2296 - addressof should be constexpr
// { dg-do run { target c++11 } }
template <typename T>
constexpr inline T *
addressof (T &x) noexcept
{
return __builtin_addressof (x);
}
int i;
static_assert (__builtin_addressof (i) == &i, "");
static_assert (addressof (i) == &i, "");
constexpr int &j = i;
static_assert (__builtin_addressof (j) == &i, "");
static_assert (addressof (j) == &i, "");
struct S { int s; } s;
static_assert (__builtin_addressof (s) == &s, "");
static_assert ((int *) __builtin_addressof (s) == &s.s, "");
static_assert (addressof (s) == &s, "");
static_assert ((int *) addressof (s) == &s.s, "");
struct T
{
static T tt;
constexpr T () : p (addressof (tt)) {}
constexpr T *operator & () const { return p; }
T *p;
};
constexpr T t;
T T::tt;
static_assert (__builtin_addressof (t) == (const T *) &t.p, "");
static_assert (&t == __builtin_addressof (T::tt), "");
static_assert (addressof (t) == (const T *) &t.p, "");
static_assert (&t == addressof (T::tt), "");
struct S x, y;
constexpr S *
foo (bool b)
{
return __builtin_addressof (b ? x : y);
}
constexpr S *
bar (bool b, S &c, S &d)
{
return __builtin_addressof (b ? c : d);
}
static_assert (foo (false) == &y, "");
static_assert (foo (true) == &x, "");
static_assert (bar (false, y, x) == &x, "");
static_assert (bar (true, y, x) == &y, "");
constexpr S *
foo2 (bool b)
{
return addressof (b ? x : y);
}
constexpr S *
bar2 (bool b, S &c, S &d)
{
return addressof (b ? c : d);
}
static_assert (foo2 (false) == &y, "");
static_assert (foo2 (true) == &x, "");
static_assert (bar2 (false, y, x) == &x, "");
static_assert (bar2 (true, y, x) == &y, "");
constexpr int a = 1;
static_assert (__builtin_addressof (a) == &a, "");
static_assert (addressof (a) == &a, "");
constexpr int c[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
static_assert ((const int *) __builtin_addressof (c) == &c[0], "");
static_assert ((const int *) addressof (c) == &c[0], "");
void
baz ()
{
}
int
main ()
{
if (__builtin_addressof (T::tt) == __builtin_addressof (t)
|| addressof (T::tt) == addressof (t)
|| &T::tt != &t
|| __builtin_addressof (baz) != baz
|| addressof (baz) != baz)
__builtin_abort ();
}

View File

@ -0,0 +1,33 @@
// LWG2296 - addressof should be constexpr
// { dg-do compile { target c++11 } }
template <typename T>
constexpr inline T *
addressof (T &x) noexcept
{
return __builtin_addressof (x);
}
auto a = __builtin_addressof (1); // { dg-error "lvalue required as unary" }
auto b = addressof (1); // { dg-error "cannot bind non-const lvalue reference of type" }
struct S { int s : 5; int t; void foo (); } s;
auto c = __builtin_addressof (s);
auto d = addressof (s);
auto e = __builtin_addressof (s.s); // { dg-error "attempt to take address of bit-field structure member" }
auto f = addressof (s.s); // { dg-error "cannot bind bitfield" }
auto g = __builtin_addressof (S{}); // { dg-error "taking address of temporary" }
auto h = addressof (S{}); // { dg-error "cannot bind non-const lvalue reference of type" }
auto i = __builtin_addressof (S::t); // { dg-error "invalid use of non-static data member" }
auto j = __builtin_addressof (S::foo); // { dg-error "invalid use of non-static member function" }
void
foo (bool b)
{
lab:;
char c;
long long int d;
auto k = __builtin_addressof (lab); // { dg-error "was not declared in this scope" }
auto l = __builtin_addressof (b ? c : d); // { dg-error "lvalue required as unary" }
}