From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28425 invoked by alias); 7 Oct 2016 19:23:46 -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 28356 invoked by uid 89); 7 Oct 2016 19:23:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.6 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=tp, 4566, ss, sk:tf_warn X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 07 Oct 2016 19:23:38 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 68A381E20 for ; Fri, 7 Oct 2016 19:23:37 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-116-44.ams2.redhat.com [10.36.116.44]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u97JNYP7027582 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 7 Oct 2016 15:23:36 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id u97JNWq7008679; Fri, 7 Oct 2016 21:23:33 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id u97JNUE9008678; Fri, 7 Oct 2016 21:23:30 +0200 Date: Fri, 07 Oct 2016 19:23:00 -0000 From: Jakub Jelinek To: Jason Merrill , Jonathan Wakely Cc: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] Implement LWG2296 helper intrinsic Message-ID: <20161007192330.GJ7282@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) X-IsSubscribed: yes X-SW-Source: 2016-10/txt/msg00514.txt.bz2 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