Implement LWG2296 helper intrinsic c-family/
authorJakub Jelinek <jakub@redhat.com>
Fri, 7 Oct 2016 19:37:46 +0000 (21:37 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 7 Oct 2016 19:37:46 +0000 (21:37 +0200)
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

17 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/cp-objcp-common.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/cxx-pretty-print.h
gcc/cp/error.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/addressof1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/addressof2.C [new file with mode: 0644]

index 08535d0ba2b4365a2504ad1600ae59ebf0c19f20..52ba9b8fdebba22497185c67997abd53d073386d 100644 (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>
 
        PR c++/77700
index 19609a59d9ccce4a9575a054ec32e95aa6cf8e13..f7a5d62012bb84871f02a1e993f41738058a8a1b 100644 (file)
@@ -463,6 +463,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__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 },
index f9ebb5bca2f02df218bd3368fc5d942a783d4224..0a7b5ec5f9b97586e930224f5f8d443811292b7e 100644 (file)
@@ -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,
index 085e0a53c3874a5aa9f3b527244da4574f0eb0b3..ce875ce3b3e53c1b5ea6f317b733e4a0d40f29af 100644 (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>
 
        PR c++/77700
index 4acbb2600b4b5c293ea11a71450cf291c6529668..f5235fc21e6e49d38781a56898f812c362a25be9 100644 (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));
       }
 
+    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, bool want_rval, bool strict,
        /* 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
index 9cb9dd780fb2e2b879d29315baf94a3220593c3c..ac1bb63f8174da837266ca1d3e735022331fe350 100644 (file)
@@ -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);
index 6cb5a695ea50eeb1b1e1953650f770d1fc9e7816..9e4407650f543f4c39e8be3c3f5f675a0a073641 100644 (file)
@@ -334,6 +334,11 @@ DEFTREECODE (TAG_DEFN, "tag_defn", tcc_expression, 0)
 /* 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)
 
index 9282bbe388302a416ad1b5a0d8459ea86d1169b4..6a086277c34b6886ef1f0ca5c40cc66efba832f1 100644 (file)
@@ -6658,6 +6658,8 @@ extern tree build_x_array_ref                     (location_t, tree, tree,
 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);
index 68dcf58ea1ceaf264bcf61013ae61f39e382599f..5157faba23e5b69359c864143568c1329bf8764d 100644 (file)
@@ -380,6 +380,7 @@ pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t)
    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_printer *pp, tree t)
      __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 (tree t)
       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_printer *pp, tree t)
   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)
 {
index 2f0e35a274d5526778c9c140c7a0abc2c8840579..1eb55dfacc025824a7b657acc16650f4b6726dc7 100644 (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_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);
index 20b20b48e9689fc7e929cc4fca51537887bbfc9f..4cf00411b67e7b807024ca97e5995a4516492666 100644 (file)
@@ -2678,6 +2678,10 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
       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;
index 8728991af7393f74f959e1d8be5fe5dabe7a7001..643c1e7bfe90fc81cd217f66e51ea6d5d16d1d10 100644 (file)
@@ -6602,6 +6602,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
        break;
       }
 
+    case RID_ADDRESSOF:
     case RID_BUILTIN_SHUFFLE:
       {
        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)
          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:
index e6bacdfa5ae3636ed0c429a22bcb267e623d5083..f6cd3ea47ba0bffd23886c468e937b28a98594f9 100644 (file)
@@ -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,
index f1abb40a775edaa295215a80590804df97b3f591..64562698854124f5e485400f1b5780b292a39539 100644 (file)
@@ -5456,6 +5456,29 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
   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.  */
index 0aa90ee5d780b89dabf347ff533712ecc9a044c4..07cfac4aa86e5179f0c2b416e5e1fda0d93da533 100644 (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>
 
        * gcc.target/powerpc/float128-type-1.c: New test to check that
diff --git a/gcc/testsuite/g++.dg/cpp0x/addressof1.C b/gcc/testsuite/g++.dg/cpp0x/addressof1.C
new file mode 100644 (file)
index 0000000..027811a
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/addressof2.C b/gcc/testsuite/g++.dg/cpp0x/addressof2.C
new file mode 100644 (file)
index 0000000..28b71d8
--- /dev/null
@@ -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" }
+}