c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and RID_IS_TRIVIALLY_CONSTRUCT...
authorJason Merrill <jason@redhat.com>
Tue, 30 Sep 2014 17:13:10 +0000 (13:13 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 30 Sep 2014 17:13:10 +0000 (13:13 -0400)
c-family/
* c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and
RID_IS_TRIVIALLY_CONSTRUCTIBLE.
* c-common.c (c_common_reswords): Add __is_trivially_copyable.
cp/
* cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_ASSIGNABLE and
CPTK_IS_TRIVIALLY_CONSTRUCTIBLE.
* cxx-pretty-print.c (pp_cxx_trait_expression): Likewise.
* parser.c (cp_parser_primary_expression): Likewise.
(cp_parser_trait_expr): Likewise.  Handle variadic trait.
* semantics.c (trait_expr_value): Likewise.
(finish_trait_expr): Likewise.
(check_trait_type): Handle variadic trait.  Return bool.
* method.c (build_stub_object): Add rvalue reference here.
(locate_fn_flags): Not here.
(check_nontriv, assignable_expr, constructible_expr): New.
(is_trivially_xible): New.

From-SVN: r215738

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/method.c
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C [new file with mode: 0644]

index 8c44b18a85984ad4ebdcb67d1a78596191d1c4d7..b3a71312ad6357e494f177877327b23e170df556 100644 (file)
@@ -1,5 +1,9 @@
 2014-09-30  Jason Merrill  <jason@redhat.com>
 
+       * c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and
+       RID_IS_TRIVIALLY_CONSTRUCTIBLE.
+       * c-common.c (c_common_reswords): Add __is_trivially_copyable.
+
        * c-common.h (enum rid): Add RID_IS_TRIVIALLY_COPYABLE.
        * c-common.c (c_common_reswords): Add __is_trivially_copyable.
 
index 482dd44961161206e90c13983a79dc5bae40f41e..b16d030ae2bcba16ee4ab0d814727035a6f7a0d6 100644 (file)
@@ -480,6 +480,8 @@ const struct c_common_resword c_common_reswords[] =
   { "__is_polymorphic",        RID_IS_POLYMORPHIC, D_CXXONLY },
   { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY },
   { "__is_trivial",     RID_IS_TRIVIAL, D_CXXONLY },
+  { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY },
+  { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, D_CXXONLY },
   { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY },
   { "__is_union",      RID_IS_UNION,   D_CXXONLY },
   { "__label__",       RID_LABEL,      0 },
index b7e3385ab7a47e61b29b2b0e68815c55e20caf82..1e3477f7058597abdca2c0e5f00fd7f2024f8e8e 100644 (file)
@@ -143,6 +143,7 @@ enum rid
   RID_IS_FINAL,                RID_IS_LITERAL_TYPE,
   RID_IS_POD,                  RID_IS_POLYMORPHIC,
   RID_IS_STD_LAYOUT,           RID_IS_TRIVIAL,
+  RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
   RID_IS_TRIVIALLY_COPYABLE,
   RID_IS_UNION,                RID_UNDERLYING_TYPE,
 
index d44d67a387576840b3372e583f8161cbda665fa6..2fedd372a48fb1605ec46c50defdd6917cffabbf 100644 (file)
@@ -1,5 +1,18 @@
 2014-09-30  Jason Merrill  <jason@redhat.com>
 
+       * cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_ASSIGNABLE and
+       CPTK_IS_TRIVIALLY_CONSTRUCTIBLE.
+       * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise.
+       * parser.c (cp_parser_primary_expression): Likewise.
+       (cp_parser_trait_expr): Likewise.  Handle variadic trait.
+       * semantics.c (trait_expr_value): Likewise.
+       (finish_trait_expr): Likewise.
+       (check_trait_type): Handle variadic trait.  Return bool.
+       * method.c (build_stub_object): Add rvalue reference here.
+       (locate_fn_flags): Not here.
+       (check_nontriv, assignable_expr, constructible_expr): New.
+       (is_trivially_xible): New.
+
        * cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_COPYABLE.
        * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise.
        * parser.c (cp_parser_primary_expression): Likewise.
index 8e5c3b7909fb3689fc4b72ac586815d8d4d2e47f..b2b9063a3655605bdaa8aeb4f12bcd402151c115 100644 (file)
@@ -653,6 +653,8 @@ typedef enum cp_trait_kind
   CPTK_IS_POLYMORPHIC,
   CPTK_IS_STD_LAYOUT,
   CPTK_IS_TRIVIAL,
+  CPTK_IS_TRIVIALLY_ASSIGNABLE,
+  CPTK_IS_TRIVIALLY_CONSTRUCTIBLE,
   CPTK_IS_TRIVIALLY_COPYABLE,
   CPTK_IS_UNION,
   CPTK_UNDERLYING_TYPE
@@ -5521,6 +5523,7 @@ extern tree make_thunk                            (tree, bool, tree, tree);
 extern void finish_thunk                       (tree);
 extern void use_thunk                          (tree, bool);
 extern bool trivial_fn_p                       (tree);
+extern bool is_trivially_xible                 (enum tree_code, tree, tree);
 extern tree get_defaulted_eh_spec              (tree);
 extern tree unevaluated_noexcept_spec          (void);
 extern void after_nsdmi_defaulted_late_checks   (tree);
index 7b2d7fd205b3de3bcc0d7f9c7690ca374dcd7e5c..67e84c0a2405301ee473aea21a447387e42ed167 100644 (file)
@@ -2393,6 +2393,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
     case CPTK_IS_TRIVIAL:
       pp_cxx_ws_string (pp, "__is_trivial");
       break;
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+      pp_cxx_ws_string (pp, "__is_trivially_assignable");
+      break;
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+      pp_cxx_ws_string (pp, "__is_trivially_constructible");
+      break;
     case CPTK_IS_TRIVIALLY_COPYABLE:
       pp_cxx_ws_string (pp, "__is_trivially_copyable");
       break;
index b427d65d642955d6ac4a0ecb9e78d87a32845874..9a2bd0f1055c8561f9640ab52228bd5c3748d345 100644 (file)
@@ -852,6 +852,8 @@ build_stub_type (tree type, int quals, bool rvalue)
 static tree
 build_stub_object (tree reftype)
 {
+  if (TREE_CODE (reftype) != REFERENCE_TYPE)
+    reftype = cp_build_reference_type (reftype, /*rval*/true);
   tree stub = build1 (CONVERT_EXPR, reftype, integer_one_node);
   return convert_from_reference (stub);
 }
@@ -889,8 +891,6 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
               elt = TREE_CHAIN (elt))
            {
              tree type = TREE_VALUE (elt);
-             if (TREE_CODE (type) != REFERENCE_TYPE)
-               type = cp_build_reference_type (type, /*rval*/true);
              tree arg = build_stub_object (type);
              vec_safe_push (args, arg);
            }
@@ -1001,6 +1001,113 @@ get_inherited_ctor (tree ctor)
   return fn;
 }
 
+/* walk_tree helper function for is_trivially_xible.  If *TP is a call,
+   return it if it calls something other than a trivial special member
+   function.  */
+
+static tree
+check_nontriv (tree *tp, int *, void *)
+{
+  tree fn;
+  if (TREE_CODE (*tp) == CALL_EXPR)
+    fn = CALL_EXPR_FN (*tp);
+  else if (TREE_CODE (*tp) == AGGR_INIT_EXPR)
+    fn = AGGR_INIT_EXPR_FN (*tp);
+  else
+    return NULL_TREE;
+
+  if (TREE_CODE (fn) == ADDR_EXPR)
+    fn = TREE_OPERAND (fn, 0);
+
+  if (TREE_CODE (fn) != FUNCTION_DECL
+      || !trivial_fn_p (fn))
+    return fn;
+  return NULL_TREE;
+}
+
+/* Return declval<T>() = declval<U>() treated as an unevaluated operand.  */
+
+static tree
+assignable_expr (tree to, tree from)
+{
+  ++cp_unevaluated_operand;
+  to = build_stub_object (to);
+  from = build_stub_object (from);
+  tree r = cp_build_modify_expr (to, NOP_EXPR, from, tf_none);
+  --cp_unevaluated_operand;
+  return r;
+}
+
+/* The predicate condition for a template specialization
+   is_constructible<T, Args...> shall be satisfied if and only if the
+   following variable definition would be well-formed for some invented
+   variable t: T t(create<Args>()...);
+
+   Return something equivalent in well-formedness and triviality.  */
+
+static tree
+constructible_expr (tree to, tree from)
+{
+  tree expr;
+  if (CLASS_TYPE_P (to))
+    {
+      tree ctype = to;
+      vec<tree, va_gc> *args = NULL;
+      if (TREE_CODE (to) != REFERENCE_TYPE)
+       to = cp_build_reference_type (to, /*rval*/false);
+      tree ob = build_stub_object (to);
+      for (; from; from = TREE_CHAIN (from))
+       vec_safe_push (args, build_stub_object (TREE_VALUE (from)));
+      expr = build_special_member_call (ob, complete_ctor_identifier, &args,
+                                       ctype, LOOKUP_NORMAL, tf_none);
+      if (expr == error_mark_node)
+       return error_mark_node;
+      /* The current state of the standard vis-a-vis LWG 2116 is that
+        is_*constructible involves destruction as well.  */
+      if (type_build_dtor_call (ctype))
+       {
+         tree dtor = build_special_member_call (ob, complete_dtor_identifier,
+                                                NULL, ctype, LOOKUP_NORMAL,
+                                                tf_none);
+         if (dtor == error_mark_node)
+           return error_mark_node;
+         if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype))
+           expr = build2 (COMPOUND_EXPR, void_type_node, expr, dtor);
+       }
+    }
+  else
+    {
+      if (TREE_CHAIN (from))
+       return error_mark_node; // too many initializers
+      from = build_stub_object (TREE_VALUE (from));
+      expr = perform_direct_initialization_if_possible (to, from,
+                                                       /*cast*/false,
+                                                       tf_none);
+    }
+  return expr;
+}
+
+/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
+   constructible (otherwise) from FROM, which is a single type for
+   assignment or a list of types for construction.  */
+
+bool
+is_trivially_xible (enum tree_code code, tree to, tree from)
+{
+  tree expr;
+  if (code == MODIFY_EXPR)
+    expr = assignable_expr (to, from);
+  else if (from && TREE_CHAIN (from))
+    return false; // only 0- and 1-argument ctors can be trivial
+  else
+    expr = constructible_expr (to, from);
+
+  if (expr == error_mark_node)
+    return false;
+  tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
+  return !nt;
+}
+
 /* Subroutine of synthesized_method_walk.  Update SPEC_P, TRIVIAL_P and
    DELETED_P or give an error message MSG with argument ARG.  */
 
index b1feef52b93ad89c86b8525e8c467c088c17e7b1..e4aaf53fa6c8759cd6efbcd0012135b1cf35540d 100644 (file)
@@ -4490,6 +4490,8 @@ cp_parser_primary_expression (cp_parser *parser,
        case RID_IS_POLYMORPHIC:
        case RID_IS_STD_LAYOUT:
        case RID_IS_TRIVIAL:
+       case RID_IS_TRIVIALLY_ASSIGNABLE:
+       case RID_IS_TRIVIALLY_CONSTRUCTIBLE:
        case RID_IS_TRIVIALLY_COPYABLE:
        case RID_IS_UNION:
          return cp_parser_trait_expr (parser, token->keyword);
@@ -8664,6 +8666,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
   cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
   bool binary = false;
+  bool variadic = false;
 
   switch (keyword)
     {
@@ -8725,6 +8728,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     case RID_IS_TRIVIAL:
       kind = CPTK_IS_TRIVIAL;
       break;
+    case RID_IS_TRIVIALLY_ASSIGNABLE:
+      kind = CPTK_IS_TRIVIALLY_ASSIGNABLE;
+      binary = true;
+      break;
+    case RID_IS_TRIVIALLY_CONSTRUCTIBLE:
+      kind = CPTK_IS_TRIVIALLY_CONSTRUCTIBLE;
+      variadic = true;
+      break;
     case RID_IS_TRIVIALLY_COPYABLE:
       kind = CPTK_IS_TRIVIALLY_COPYABLE;
       break;
@@ -8763,6 +8774,17 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
       if (type2 == error_mark_node)
        return error_mark_node;
     }
+  else if (variadic)
+    {
+      while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       {
+         cp_lexer_consume_token (parser->lexer);
+         tree elt = cp_parser_type_id (parser);
+         if (elt == error_mark_node)
+           return error_mark_node;
+         type2 = tree_cons (NULL_TREE, elt, type2);
+       }
+    }
 
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 
index 9bcc6d73c78a1cda76f60de8e9991f9c3a952cfc..756982667b1b02abbfa9016b4647be904dd70abb 100644 (file)
@@ -7379,6 +7379,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIAL:
       return (trivial_type_p (type1));
 
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+      return is_trivially_xible (MODIFY_EXPR, type1, type2);
+
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+      return is_trivially_xible (INIT_EXPR, type1, type2);
+
     case CPTK_IS_TRIVIALLY_COPYABLE:
       return (trivially_copyable_p (type1));
 
@@ -7392,19 +7398,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
 }
 
 /* If TYPE is an array of unknown bound, or (possibly cv-qualified)
-   void, or a complete type, returns it, otherwise NULL_TREE.  */
+   void, or a complete type, returns true, otherwise false.  */
 
-static tree
+static bool
 check_trait_type (tree type)
 {
+  if (type == NULL_TREE)
+    return true;
+
+  if (TREE_CODE (type) == TREE_LIST)
+    return (check_trait_type (TREE_VALUE (type))
+           && check_trait_type (TREE_CHAIN (type)));
+
   if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type)
       && COMPLETE_TYPE_P (TREE_TYPE (type)))
-    return type;
+    return true;
 
   if (VOID_TYPE_P (type))
-    return type;
+    return true;
 
-  return complete_type_or_else (strip_array_types (type), NULL_TREE);
+  return !!complete_type_or_else (strip_array_types (type), NULL_TREE);
 }
 
 /* Process a trait expression.  */
@@ -7413,8 +7426,7 @@ tree
 finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
 {
   if (type1 == error_mark_node
-      || ((kind == CPTK_IS_BASE_OF)
-         && type2 == error_mark_node))
+      || type2 == error_mark_node)
     return error_mark_node;
 
   if (processing_template_decl)
@@ -7450,6 +7462,13 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
        return error_mark_node;
       break;
 
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+      if (!check_trait_type (type1)
+         || !check_trait_type (type2))
+       return error_mark_node;
+      break;
+
     case CPTK_IS_BASE_OF:
       if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
          && !same_type_ignoring_top_level_qualifiers_p (type1, type2)
diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C
new file mode 100644 (file)
index 0000000..f558538
--- /dev/null
@@ -0,0 +1,35 @@
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B { B(); operator int(); };
+struct C {
+  C() = default;
+  C(const C&);
+  C(C&&) = default;
+  C& operator=(C&&);
+  C& operator= (const C&) = default;
+};
+struct D { ~D() {} };
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_trivially_constructible(A));
+SA(__is_trivially_constructible(A,A));
+SA(!__is_trivially_constructible(B));
+SA(__is_trivially_constructible(B,B));
+
+SA(!__is_trivially_constructible(A,B));
+SA(!__is_trivially_constructible(B,A));
+
+SA(__is_trivially_constructible(C));
+SA(__is_trivially_constructible(C,C));
+SA(!__is_trivially_constructible(C,C&));
+SA(__is_trivially_assignable(C,C&));
+SA(!__is_trivially_assignable(C,C));
+SA(!__is_trivially_assignable(C,C&&));
+
+SA(__is_trivially_constructible(int,int));
+SA(__is_trivially_constructible(int,double));
+SA(!__is_trivially_constructible(int,B));
+
+SA(!__is_trivially_constructible(D));