internal-fn.def (LAUNDER): New internal function.
authorJakub Jelinek <jakub@gcc.gnu.org>
Tue, 25 Oct 2016 08:47:15 +0000 (10:47 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 25 Oct 2016 08:47:15 +0000 (10:47 +0200)
* internal-fn.def (LAUNDER): New internal function.
* internal-fn.c (expand_LAUNDER): New function.
c-family/
* c-common.h (enum rid): Add RID_BUILTIN_LAUNDER.
* c-common.c (c_common_reswords): Add __builtin_launder.
cp/
* cp-tree.h (finish_builtin_launder): Declare.
* parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_LAUNDER.
* semantics.c (finish_builtin_launder): New function.
* pt.c (tsubst_copy_and_build): Handle instantiation of IFN_LAUNDER.
* constexpr.c (cxx_eval_internal_function): Handle IFN_LAUNDER.
(potential_constant_expression_1): Likewise.
testsuite/
* g++.dg/cpp1z/launder1.C: New test.
* g++.dg/cpp1z/launder2.C: New test.

From-SVN: r241506

15 files changed:
gcc/ChangeLog
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-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/internal-fn.c
gcc/internal-fn.def
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1z/launder1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/launder2.C [new file with mode: 0644]

index cb290f188187ddf3fdfb83973c5e187a8d53eb67..c8331867dc00c020e384a8e24a7bb7e877857982 100644 (file)
@@ -1,4 +1,10 @@
+2016-10-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * internal-fn.def (LAUNDER): New internal function.
+       * internal-fn.c (expand_LAUNDER): New function.
+
 2016-10-25  Georg-Johann Lay  <avr@gjlay.de>
+           Pitchumani Sivanupandi  <pitchumani.sivanupandi@microchip.com>
 
        New avr target pass to work around performance loss by PR fix.
 
@@ -18,7 +24,7 @@
        (avr_optimize_casesi): New functions.
 
 2016-10-25  Georg-Johann Lay  <avr@gjlay.de>
-           Pitchumani Sivanupandi <pitchumani.sivanupandi@microchip.com>
+           Pitchumani Sivanupandi  <pitchumani.sivanupandi@microchip.com>
 
        PR target/71676
        PR target/71678
index 6a6dba2859318d52980dd9b8ed37e93b3fc3a56a..15d7488ba041964c1b3ff6ccb34897ea45d975cf 100644 (file)
@@ -1,3 +1,8 @@
+2016-10-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * c-common.h (enum rid): Add RID_BUILTIN_LAUNDER.
+       * c-common.c (c_common_reswords): Add __builtin_launder.
+
 2016-10-24  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * c-common.c (c_common_truthvalue_conversion): Warn for
index c0dafc08652a81c0610951bf928cb6d2bccac898..307862b9c7c4d694acb5a42c7491ee8e3ecef80d 100644 (file)
@@ -375,6 +375,7 @@ const struct c_common_resword c_common_reswords[] =
     RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
   { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
+  { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
   { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
index bfdbda0898df275f2419eef766ea9b759e0c188f..547bab2ac4e457c23aac6e0c6aaa1ec1a61819b1 100644 (file)
@@ -146,8 +146,8 @@ enum rid
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* C++ extensions */
-  RID_ADDRESSOF,
-  RID_BASES,                   RID_DIRECT_BASES,
+  RID_ADDRESSOF,               RID_BASES,
+  RID_BUILTIN_LAUNDER,         RID_DIRECT_BASES,
   RID_HAS_NOTHROW_ASSIGN,      RID_HAS_NOTHROW_CONSTRUCTOR,
   RID_HAS_NOTHROW_COPY,        RID_HAS_TRIVIAL_ASSIGN,
   RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY,
index 744eb5288a2949b7b4c2c9936e0bc207236c887b..21c6408b1a0abaf1e499766b5b2c1e3c4c0cf731 100644 (file)
@@ -1,3 +1,12 @@
+2016-10-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * cp-tree.h (finish_builtin_launder): Declare.
+       * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_LAUNDER.
+       * semantics.c (finish_builtin_launder): New function.
+       * pt.c (tsubst_copy_and_build): Handle instantiation of IFN_LAUNDER.
+       * constexpr.c (cxx_eval_internal_function): Handle IFN_LAUNDER.
+       (potential_constant_expression_1): Likewise.
+
 2016-10-24  Jakub Jelinek  <jakub@redhat.com>
 
        * cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_reference
index 3c4fcfaeef931b0568ab0691d7b885ca22e6550e..8f7b7f34b647376b67e1bd4d938587c4e276d29b 100644 (file)
@@ -1330,6 +1330,10 @@ cxx_eval_internal_function (const constexpr_ctx *ctx, tree t,
       opcode = MULT_EXPR;
       break;
 
+    case IFN_LAUNDER:
+      return cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0),
+                                          false, non_constant_p, overflow_p);
+
     default:
       if (!ctx->quiet)
        error_at (EXPR_LOC_OR_LOC (t, input_location),
@@ -4920,6 +4924,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
                case IFN_ADD_OVERFLOW:
                case IFN_SUB_OVERFLOW:
                case IFN_MUL_OVERFLOW:
+               case IFN_LAUNDER:
                  bail = false;
 
                default:
index f4a8985b351121f3f6a54b44888308ee98244533..c58996925c3ca075223deebcf09988929f1af710 100644 (file)
@@ -6494,6 +6494,8 @@ extern bool generic_lambda_fn_p                   (tree);
 extern void maybe_add_lambda_conv_op            (tree);
 extern bool is_lambda_ignored_entity            (tree);
 extern bool lambda_static_thunk_p              (tree);
+extern tree finish_builtin_launder             (location_t, tree,
+                                                tsubst_flags_t);
 
 /* in tree.c */
 extern int cp_tree_operand_length              (const_tree);
index 643c1e7bfe90fc81cd217f66e51ea6d5d16d1d10..f962dfb0759a589f5b41d8ea33476f2f3bb25e87 100644 (file)
@@ -6604,6 +6604,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 
     case RID_ADDRESSOF:
     case RID_BUILTIN_SHUFFLE:
+    case RID_BUILTIN_LAUNDER:
       {
        vec<tree, va_gc> *vec;
        unsigned int i;
@@ -6628,6 +6629,18 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
                           "%<__builtin_addressof%>");
            return error_mark_node;
 
+         case RID_BUILTIN_LAUNDER:
+           if (vec->length () == 1)
+             postfix_expression = finish_builtin_launder (loc, (*vec)[0],
+                                                          tf_warning_or_error);
+           else
+             {
+               error_at (loc, "wrong number of arguments to "
+                              "%<__builtin_launder%>");
+               postfix_expression = error_mark_node;
+             }
+           break;
+
          case RID_BUILTIN_SHUFFLE:
            if (vec->length () == 2)
              return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE,
index aa126a0b94c62d0ec429f5fae7f982bd8711d230..c916e58482fa09941ecf46a97cc0850c7728a8d2 100644 (file)
@@ -16599,19 +16599,19 @@ tsubst_copy_and_build (tree t,
        tree ret;
 
        function = CALL_EXPR_FN (t);
-       if (function == NULL_TREE)
-         {
-           /* If you hit this assert, it means that you're trying to tsubst
-              an internal function with arguments.  This isn't yet supported,
-              so you need to build another internal call with the tsubsted
-              arguments after the arguments have been tsubsted down below.  */
-           gcc_assert (call_expr_nargs (t) == 0);
-           RETURN (t);
-         }
+       /* Internal function with no arguments.  */
+       if (function == NULL_TREE && call_expr_nargs (t) == 0)
+         RETURN (t);
+
        /* When we parsed the expression, we determined whether or
           not Koenig lookup should be performed.  */
        koenig_p = KOENIG_LOOKUP_P (t);
-       if (TREE_CODE (function) == SCOPE_REF)
+       if (function == NULL_TREE)
+         {
+           koenig_p = false;
+           qualified_p = false;
+         }
+       else if (TREE_CODE (function) == SCOPE_REF)
          {
            qualified_p = true;
            function = tsubst_qualified_id (function, args, complain, in_decl,
@@ -16709,7 +16709,8 @@ tsubst_copy_and_build (tree t,
            && !any_type_dependent_arguments_p (call_args))
          function = perform_koenig_lookup (function, call_args, tf_none);
 
-       if (identifier_p (function)
+       if (function != NULL_TREE
+           && identifier_p (function)
            && !any_type_dependent_arguments_p (call_args))
          {
            if (koenig_p && (complain & tf_warning_or_error))
@@ -16721,7 +16722,10 @@ tsubst_copy_and_build (tree t,
                            (function, args, complain, in_decl, true,
                             integral_constant_expression_p));
                if (unq == error_mark_node)
-                 RETURN (error_mark_node);
+                 {
+                   release_tree_vector (call_args);
+                   RETURN (error_mark_node);
+                 }
 
                if (unq != function)
                  {
@@ -16774,14 +16778,40 @@ tsubst_copy_and_build (tree t,
          }
 
        /* Remember that there was a reference to this entity.  */
-       if (DECL_P (function)
+       if (function != NULL_TREE
+           && DECL_P (function)
            && !mark_used (function, complain) && !(complain & tf_error))
-         RETURN (error_mark_node);
+         {
+           release_tree_vector (call_args);
+           RETURN (error_mark_node);
+         }
 
        /* Put back tf_decltype for the actual call.  */
        complain |= decltype_flag;
 
-       if (TREE_CODE (function) == OFFSET_REF)
+       if (function == NULL_TREE)
+         switch (CALL_EXPR_IFN (t))
+           {
+           case IFN_LAUNDER:
+             gcc_assert (nargs == 1);
+             if (vec_safe_length (call_args) != 1)
+               {
+                 error_at (EXPR_LOC_OR_LOC (t, input_location),
+                           "wrong number of arguments to "
+                           "%<__builtin_launder%>");
+                 ret = error_mark_node;
+               }
+             else
+               ret = finish_builtin_launder (EXPR_LOC_OR_LOC (t,
+                                                              input_location),
+                                             (*call_args)[0], complain);
+             break;
+
+           default:
+             /* Unsupported internal function with arguments.  */
+             gcc_unreachable ();
+           }
+       else if (TREE_CODE (function) == OFFSET_REF)
          ret = build_offset_ref_call_from_tree (function, &call_args,
                                                 complain);
        else if (TREE_CODE (function) == COMPONENT_REF)
index 968f88b3c04bf1dbb22e37c5faaebadc4fed3b69..1a7c478d4ecd1b253237fd0a927c58ca6002b8e5 100644 (file)
@@ -9449,4 +9449,26 @@ finish_binary_fold_expr (tree expr1, tree expr2, int op)
   return error_mark_node;
 }
 
+/* Finish __builtin_launder (arg).  */
+
+tree
+finish_builtin_launder (location_t loc, tree arg, tsubst_flags_t complain)
+{
+  tree orig_arg = arg;
+  if (!type_dependent_expression_p (arg))
+    arg = decay_conversion (arg, complain);
+  if (error_operand_p (arg))
+    return error_mark_node;
+  if (!type_dependent_expression_p (arg)
+      && TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+    {
+      error_at (loc, "non-pointer argument to %<__builtin_launder%>");
+      return error_mark_node;
+    }
+  if (processing_template_decl)
+    arg = orig_arg;
+  return build_call_expr_internal_loc (loc, IFN_LAUNDER,
+                                      TREE_TYPE (arg), 1, arg);
+}
+
 #include "gt-cp-semantics.h"
index 0b32d5f635bbcf1178a7ec27d341fd66ef1ced1b..44776976d2ad3aa2b50f9570cd4873d9bf7025f0 100644 (file)
@@ -2207,6 +2207,19 @@ expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
   expand_ifn_atomic_compare_exchange (call);
 }
 
+/* Expand LAUNDER to assignment, lhs = arg0.  */
+
+static void
+expand_LAUNDER (internal_fn, gcall *call)
+{
+  tree lhs = gimple_call_lhs (call);
+
+  if (!lhs)
+    return;
+
+  expand_assignment (lhs, gimple_call_arg (call, 0), false);
+}
+
 /* Expand a call to FN using the operands in STMT.  FN has a single
    output operand and NARGS input operands.  */
 
index d4fbdb286220797464d8b7e580da403d73474cb7..28863dfe4b3ff854ce475dbff31aebb3b69cc542 100644 (file)
@@ -198,6 +198,9 @@ DEF_INTERNAL_FN (ATOMIC_COMPARE_EXCHANGE, ECF_LEAF | ECF_NOTHROW, NULL)
 /* To implement [[fallthrough]].  */
 DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL)
 
+/* To implement __builtin_launder.  */
+DEF_INTERNAL_FN (LAUNDER, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
+
 #undef DEF_INTERNAL_INT_FN
 #undef DEF_INTERNAL_FLT_FN
 #undef DEF_INTERNAL_OPTAB_FN
index 4fa3b4f9b6491cf5c78ea6c14b04daeac3e942f0..1dc07326565d46380214914e836c64d3bb10004e 100644 (file)
@@ -1,11 +1,17 @@
+2016-10-25  Jakub Jelinek  <jakub@redhat.com>
+
+       * g++.dg/cpp1z/launder1.C: New test.
+       * g++.dg/cpp1z/launder2.C: New test.
+
 2016-10-25  Georg-Johann Lay  <avr@gjlay.de>
+           Pitchumani Sivanupandi  <pitchumani.sivanupandi@microchip.com>
 
        PR target/71676
        PR target/71678
        * gcc.target/avr/pr71676-2.c: New test.
 
 2016-10-25  Georg-Johann Lay  <avr@gjlay.de>
-           Pitchumani Sivanupandi <pitchumani.sivanupandi@microchip.com>
+           Pitchumani Sivanupandi  <pitchumani.sivanupandi@microchip.com>
 
        PR target/71676
        PR target/71678
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder1.C b/gcc/testsuite/g++.dg/cpp1z/launder1.C
new file mode 100644 (file)
index 0000000..8f3b022
--- /dev/null
@@ -0,0 +1,51 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-O2" }
+
+void *
+operator new (decltype (sizeof (0)), void *p)
+{
+  return p;
+}
+
+namespace std
+{
+  template <typename T>
+  T *
+  launder (T *p)
+  {
+    return __builtin_launder (p);
+  }
+}
+
+struct A
+{
+  virtual int f ();
+};
+
+struct B : A
+{
+  virtual int f ()
+  {
+    new (this) A;
+    return 1;
+  }
+};
+
+int
+A::f ()
+{
+  new (this) B;
+  return 2;
+}
+
+static_assert (sizeof (B) == sizeof (A), "");
+
+int
+main ()
+{
+  A a;
+  int n = a.f ();
+  int m = std::launder (&a)->f ();
+  if (n != 2 || m != 1)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder2.C b/gcc/testsuite/g++.dg/cpp1z/launder2.C
new file mode 100644 (file)
index 0000000..9cd1779
--- /dev/null
@@ -0,0 +1,42 @@
+// { dg-do compile { target c++11 } }
+
+int a;
+int *b = __builtin_launder ();         // { dg-error "wrong number of arguments to" }
+int *c = __builtin_launder (&a, 2);    // { dg-error "wrong number of arguments to" }
+int *d = __builtin_launder (&a);
+int e = __builtin_launder (a);         // { dg-error "non-pointer argument to" }
+int &f = a;
+int g = __builtin_launder (f);         // { dg-error "non-pointer argument to" }
+
+template <typename T> T f1 (T x) { return __builtin_launder (x); }     // { dg-error "non-pointer argument to" }
+template <typename T> T f2 (T x) { return __builtin_launder (x); }
+
+int h = f1 (a);
+int *i = f2 (&a);
+struct S { long s; int foo (); } *j;
+S *k = f2 (j);
+int l = __builtin_launder (j)->foo ();
+
+template <typename T> T *f3 (T *x) { return __builtin_launder (x); }
+
+long *m;
+long *n = f3 (m);
+int *o = f3 (&a);
+
+template <typename T, typename... U> T *f4 (U... x) { return __builtin_launder (x...); }
+template <typename T, typename... U> T *f5 (U... x) { return __builtin_launder (x...); }       // { dg-error "wrong number of arguments to" }
+template <typename T, typename... U> T *f6 (U... x) { return __builtin_launder (x...); }       // { dg-error "wrong number of arguments to" }
+template <typename T, typename... U> T f7 (T x, U... y) { return __builtin_launder (x, y...); }        // { dg-error "wrong number of arguments to" }
+
+long *p = f4<long, long *> (m);
+long *q = f5<long> ();
+long *r = f6<long, long *, int> (m, 1);
+S s;
+int t = __builtin_launder (&s)->foo ();
+
+constexpr const int *f8 (const int *x) { return __builtin_launder (x); }
+template <typename T> constexpr T f9 (T x) { return __builtin_launder (x); }
+constexpr int u = 6;
+constexpr const int *v = f8 (&u);
+constexpr const int *w = f9 (&u);
+static_assert (*f8 (&u) == 6 && *f9 (&u) == 6, "");