From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 52845 invoked by alias); 7 Oct 2016 19:34:15 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 52665 invoked by uid 89); 7 Oct 2016 19:34:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=tp X-HELO: mail-oi0-f49.google.com Received: from mail-oi0-f49.google.com (HELO mail-oi0-f49.google.com) (209.85.218.49) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 07 Oct 2016 19:34:09 +0000 Received: by mail-oi0-f49.google.com with SMTP id d132so68359205oib.2 for ; Fri, 07 Oct 2016 12:34:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=XDMPgWRrFEjm9ObDhIkcqNr2oqLezCDmQS6q+v+lBUg=; b=Zuv5H/h9sBAi6EcI+WWkA7jVg+gojFIpRJavzNanHPsf+VzbnCAtECWGkhjnH3niMx R1IFi/tziPjowr06pz7PkvmGUNQEb+UELKNFbYwN51yNLdCpFFM4+/hD2QkIET2A06hT AofAOIVRMYRCnuY25xQAQiSb8aPvYjaTTbHW7LcJMx5x1aWZHNA7Wq1sG9/VxPhj3fGu z+wwlh7iJZwSBvxwcU1y1gj39FeFJaAm4UVE0bxao/iurnO9FguozpGkopsuXZD9ZJtM MGM65BC6aTgRTwcc7UzogooZqhI7AcBLhd/3GBx22uegCsuwSal98kwfhaJN+SKiRtxZ VTTQ== X-Gm-Message-State: AA6/9RmkDTnkgVQwWVA9ieQK24OgWXgx0F71+qU2hECS+VDyUVTtxiNQYra9essoOITOrYJ+c5gwFlouVaYtZI4q X-Received: by 10.202.177.135 with SMTP id a129mr15704310oif.48.1475868847800; Fri, 07 Oct 2016 12:34:07 -0700 (PDT) MIME-Version: 1.0 Received: by 10.182.87.231 with HTTP; Fri, 7 Oct 2016 12:33:47 -0700 (PDT) In-Reply-To: <20161007192330.GJ7282@tucnak.redhat.com> References: <20161007192330.GJ7282@tucnak.redhat.com> From: Jason Merrill Date: Fri, 07 Oct 2016 19:34:00 -0000 Message-ID: Subject: Re: [C++ PATCH] Implement LWG2296 helper intrinsic To: Jakub Jelinek Cc: Jonathan Wakely , gcc-patches List Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2016-10/txt/msg00516.txt.bz2 OK. On Fri, Oct 7, 2016 at 3:23 PM, Jakub Jelinek 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 > > 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 *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 > +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 > +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