From: Jason Merrill <jason@redhat.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: Jonathan Wakely <jwakely@redhat.com>,
gcc-patches List <gcc-patches@gcc.gnu.org>
Subject: Re: [C++ PATCH] Implement LWG2296 helper intrinsic
Date: Fri, 07 Oct 2016 19:34:00 -0000 [thread overview]
Message-ID: <CADzB+2=rvoqiadu2E97--ggtuncK-Lwz3qKvrN8iiGaOcbr50g@mail.gmail.com> (raw)
In-Reply-To: <20161007192330.GJ7282@tucnak.redhat.com>
OK.
On Fri, Oct 7, 2016 at 3:23 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> The following patch adds __builtin_addressof with the semantics it has in
> clang, i.e. it is a constexpr & operator alternative that never uses the
> overloaded & operator.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2016-10-07 Jakub Jelinek <jakub@redhat.com>
>
> 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.
>
> --- gcc/c-family/c-common.h.jj 2016-10-06 23:16:43.347087129 +0200
> +++ gcc/c-family/c-common.h 2016-10-07 09:24:56.377835519 +0200
> @@ -146,6 +146,7 @@ enum rid
> RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
>
> /* C++ extensions */
> + RID_ADDRESSOF,
> RID_BASES, RID_DIRECT_BASES,
> RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR,
> RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN,
> --- gcc/c-family/c-common.c.jj 2016-10-06 23:16:43.351087082 +0200
> +++ gcc/c-family/c-common.c 2016-10-07 09:24:56.380835482 +0200
> @@ -463,6 +463,7 @@ const struct c_common_resword c_common_r
> { "__attribute__", RID_ATTRIBUTE, 0 },
> { "__auto_type", RID_AUTO_TYPE, D_CONLY },
> { "__bases", RID_BASES, D_CXXONLY },
> + { "__builtin_addressof", RID_ADDRESSOF, D_CXXONLY },
> { "__builtin_call_with_static_chain",
> RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
> { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
> --- gcc/cp/parser.c.jj 2016-10-06 23:16:43.362086951 +0200
> +++ gcc/cp/parser.c 2016-10-07 09:55:18.386923503 +0200
> @@ -6602,6 +6602,7 @@ cp_parser_postfix_expression (cp_parser
> break;
> }
>
> + case RID_ADDRESSOF:
> case RID_BUILTIN_SHUFFLE:
> {
> vec<tree, va_gc> *vec;
> @@ -6618,19 +6619,29 @@ cp_parser_postfix_expression (cp_parser
> FOR_EACH_VEC_ELT (*vec, i, p)
> mark_exp_read (p);
>
> - if (vec->length () == 2)
> - return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE, (*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);
> - else
> - {
> - error_at (loc, "wrong number of arguments to "
> - "%<__builtin_shuffle%>");
> - return error_mark_node;
> - }
> - break;
> + switch (keyword)
> + {
> + case RID_ADDRESSOF:
> + if (vec->length () == 1)
> + return cp_build_addressof (loc, (*vec)[0], tf_warning_or_error);
> + error_at (loc, "wrong number of arguments to "
> + "%<__builtin_addressof%>");
> + return error_mark_node;
> +
> + case RID_BUILTIN_SHUFFLE:
> + if (vec->length () == 2)
> + return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE,
> + (*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:
> --- gcc/cp/cp-objcp-common.c.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/cp-objcp-common.c 2016-10-07 09:55:18.391923440 +0200
> @@ -315,6 +315,7 @@ cp_common_init_ts (void)
> MARK_TS_TYPED (STMT_EXPR);
> MARK_TS_TYPED (OFFSET_REF);
> MARK_TS_TYPED (OFFSETOF_EXPR);
> + MARK_TS_TYPED (ADDRESSOF_EXPR);
> MARK_TS_TYPED (PTRMEM_CST);
> MARK_TS_TYPED (EMPTY_CLASS_EXPR);
> MARK_TS_TYPED (VEC_INIT_EXPR);
> --- gcc/cp/constexpr.c.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/constexpr.c 2016-10-07 09:55:18.395923390 +0200
> @@ -5025,6 +5025,11 @@ potential_constant_expression_1 (tree t,
> 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:
> /* -- a unary operator & that is applied to an lvalue that
> designates an object with thread or automatic storage
> @@ -5035,6 +5040,7 @@ potential_constant_expression_1 (tree t,
> /* A pointer-to-member constant. */
> return true;
>
> + handle_addr_expr:
> #if 0
> /* FIXME adjust when issue 1197 is fully resolved. For now don't do
> any checking here, as we might dereference the pointer later. If
> --- gcc/cp/error.c.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/error.c 2016-10-07 09:55:18.399923339 +0200
> @@ -2678,6 +2678,10 @@ dump_expr (cxx_pretty_printer *pp, tree
> pp_cxx_offsetof_expression (pp, t);
> break;
>
> + case ADDRESSOF_EXPR:
> + pp_cxx_addressof_expression (pp, t);
> + break;
> +
> case SCOPE_REF:
> dump_decl (pp, t, flags);
> break;
> --- gcc/cp/typeck.c.jj 2016-10-07 09:22:41.000000000 +0200
> +++ gcc/cp/typeck.c 2016-10-07 09:55:18.402923302 +0200
> @@ -5456,6 +5456,29 @@ build_x_unary_op (location_t loc, enum t
> 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
> constants, where a null value is represented by an INTEGER_CST of
> -1. */
> --- gcc/cp/cp-tree.h.jj 2016-10-07 09:22:41.124537407 +0200
> +++ gcc/cp/cp-tree.h 2016-10-07 09:43:15.705007420 +0200
> @@ -6658,6 +6658,8 @@ extern tree build_x_array_ref (locatio
> extern tree build_x_unary_op (location_t,
> enum tree_code, cp_expr,
> 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_unary_op (enum tree_code, tree, bool,
> tsubst_flags_t);
> --- gcc/cp/cxx-pretty-print.h.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/cxx-pretty-print.h 2016-10-07 09:32:00.381501689 +0200
> @@ -90,6 +90,7 @@ void pp_cxx_canonical_template_parameter
> void pp_cxx_trait_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_addressof_expression (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_expr (cxx_pretty_printer *, tree);
> --- gcc/cp/cp-tree.def.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/cp-tree.def 2016-10-07 09:26:39.947532646 +0200
> @@ -334,6 +334,11 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_e
> /* Represents an 'offsetof' expression during template expansion. */
> 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. */
> DEFTREECODE (ARROW_EXPR, "arrow_expr", tcc_expression, 1)
>
> --- gcc/cp/cxx-pretty-print.c.jj 2016-10-06 23:16:43.000000000 +0200
> +++ gcc/cp/cxx-pretty-print.c 2016-10-07 09:55:18.406923251 +0200
> @@ -380,6 +380,7 @@ pp_cxx_userdef_literal (cxx_pretty_print
> GNU Extensions:
> __builtin_va_arg ( assignment-expression , type-id )
> __builtin_offsetof ( type-id, offsetof-expression )
> + __builtin_addressof ( expression )
>
> __has_nothrow_assign ( type-id )
> __has_nothrow_constructor ( type-id )
> @@ -387,6 +388,7 @@ pp_cxx_userdef_literal (cxx_pretty_print
> __has_trivial_assign ( type-id )
> __has_trivial_constructor ( type-id )
> __has_trivial_copy ( type-id )
> + __has_unique_object_representations ( type-id )
> __has_trivial_destructor ( type-id )
> __has_virtual_destructor ( type-id )
> __is_abstract ( type-id )
> @@ -456,6 +458,10 @@ cxx_pretty_printer::primary_expression (
> pp_cxx_offsetof_expression (this, t);
> break;
>
> + case ADDRESSOF_EXPR:
> + pp_cxx_addressof_expression (this, t);
> + break;
> +
> case REQUIRES_EXPR:
> pp_cxx_requires_expr (this, t);
> break;
> @@ -2437,6 +2443,15 @@ pp_cxx_offsetof_expression (cxx_pretty_p
> 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*
> get_fold_operator (tree t)
> {
> --- gcc/cp/pt.c.jj 2016-10-06 17:46:29.000000000 +0200
> +++ gcc/cp/pt.c 2016-10-07 09:55:51.183511259 +0200
> @@ -17204,6 +17204,10 @@ tsubst_copy_and_build (tree t,
> RETURN (finish_offsetof (RECUR (TREE_OPERAND (t, 0)),
> EXPR_LOCATION (t)));
>
> + case ADDRESSOF_EXPR:
> + RETURN (cp_build_addressof (EXPR_LOCATION (t),
> + RECUR (TREE_OPERAND (t, 0)), complain));
> +
> case TRAIT_EXPR:
> {
> tree type1 = tsubst (TRAIT_EXPR_TYPE1 (t), args,
> --- gcc/testsuite/g++.dg/cpp0x/addressof1.C.jj 2016-10-07 10:45:09.797113801 +0200
> +++ gcc/testsuite/g++.dg/cpp0x/addressof1.C 2016-10-07 11:03:55.376874116 +0200
> @@ -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 ();
> +}
> --- gcc/testsuite/g++.dg/cpp0x/addressof2.C.jj 2016-10-07 11:08:38.481283997 +0200
> +++ gcc/testsuite/g++.dg/cpp0x/addressof2.C 2016-10-07 11:08:02.000000000 +0200
> @@ -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" }
> +}
>
> Jakub
next prev parent reply other threads:[~2016-10-07 19:34 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-07 19:23 Jakub Jelinek
2016-10-07 19:34 ` Jason Merrill [this message]
2017-01-01 14:27 ` Gerald Pfeifer
2017-01-01 14:53 ` Jakub Jelinek
2017-01-03 10:55 ` Jonathan Wakely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CADzB+2=rvoqiadu2E97--ggtuncK-Lwz3qKvrN8iiGaOcbr50g@mail.gmail.com' \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=jwakely@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).