Ville asked for help with the necessary compiler intrinsics for the is_trivially_* C++11 library traits.

The first patch cleans up a few oddities I noticed with the existing intrinsics. __is_convertible_to was never implemented and isn't needed. There's no need for a second grokdeclarator in trait parsing since cp_parser_type_id already does a grokdeclarator. And the assert at the top of finish_trait_expr is redundant with the gcc_unreachable in the switch.

The second patch adds __is_trivially_copyable, which just uses the existing trivially_copyable_p predicate in the compiler.

The third patch adds __is_trivially_assignable and __is_trivially_constructible, which work by building up an expression representing assignment or object declaration and then scanning it for calls to functions other than trivial special member functions. Note that there are still bugs in trivial_fn_p that are exposed by this intrinsic.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 7a3d9e80fb97691115e574915fd632f85c0974b7
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Sep 25 12:34:43 2014 -0400

    c-family/
    	* c-common.h (enum rid): Remove RID_IS_CONVERTIBLE_TO.
    	* c-common.c (c_common_reswords): Remove __is_convertible_to.
    cp/
    	* cp-tree.h (cp_trait_kind): Remove CPTK_IS_CONVERTIBLE_TO.
    	* cxx-pretty-print.c (pp_cxx_trait_expression): Likewise.
    	* semantics.c (trait_expr_value): Likewise.
    	(finish_trait_expr): Likewise.
    	* parser.c (cp_parser_primary_expression): Likewise.
    	(cp_parser_trait_expr): Likewise. Remove redundant grokdeclarator.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index a9e0191..0324a0a 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -472,7 +472,6 @@ const struct c_common_resword c_common_reswords[] =
   { "__is_abstract",	RID_IS_ABSTRACT, D_CXXONLY },
   { "__is_base_of",	RID_IS_BASE_OF, D_CXXONLY },
   { "__is_class",	RID_IS_CLASS,	D_CXXONLY },
-  { "__is_convertible_to", RID_IS_CONVERTIBLE_TO, D_CXXONLY },
   { "__is_empty",	RID_IS_EMPTY,	D_CXXONLY },
   { "__is_enum",	RID_IS_ENUM,	D_CXXONLY },
   { "__is_final",	RID_IS_FINAL,	D_CXXONLY },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5ec79a0..5ba7859 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -138,7 +138,7 @@ enum rid
   RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY,
   RID_HAS_TRIVIAL_DESTRUCTOR,  RID_HAS_VIRTUAL_DESTRUCTOR,
   RID_IS_ABSTRACT,             RID_IS_BASE_OF,
-  RID_IS_CLASS,                RID_IS_CONVERTIBLE_TO,
+  RID_IS_CLASS,
   RID_IS_EMPTY,                RID_IS_ENUM,
   RID_IS_FINAL,                RID_IS_LITERAL_TYPE,
   RID_IS_POD,                  RID_IS_POLYMORPHIC,
diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index b4a72d6..e6e90f7 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -354,9 +354,9 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1)
    is applied.  */
 DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1)
 
-/** C++0x extensions. */
+/** C++11 extensions. */
 
-/* A static assertion.  This is a C++0x extension.
+/* A static assertion.  This is a C++11 extension.
    STATIC_ASSERT_CONDITION contains the condition that is being
    checked.  STATIC_ASSERT_MESSAGE contains the message (a string
    literal) to be displayed if the condition fails to hold.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5d8badc..0bb6ef9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -645,7 +645,6 @@ typedef enum cp_trait_kind
   CPTK_IS_ABSTRACT,
   CPTK_IS_BASE_OF,
   CPTK_IS_CLASS,
-  CPTK_IS_CONVERTIBLE_TO,
   CPTK_IS_EMPTY,
   CPTK_IS_ENUM,
   CPTK_IS_FINAL,
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index f5f91c8..f0734ec 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -388,7 +388,6 @@ pp_cxx_userdef_literal (cxx_pretty_printer *pp, tree t)
      __is_abstract ( type-id )
      __is_base_of ( type-id , type-id )
      __is_class ( type-id )
-     __is_convertible_to ( type-id , type-id )     
      __is_empty ( type-id )
      __is_enum ( type-id )
      __is_literal_type ( type-id )
@@ -2373,9 +2372,6 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
     case CPTK_IS_CLASS:
       pp_cxx_ws_string (pp, "__is_class");
       break;
-    case CPTK_IS_CONVERTIBLE_TO:
-      pp_cxx_ws_string (pp, "__is_convertible_to");
-      break;
     case CPTK_IS_EMPTY:
       pp_cxx_ws_string (pp, "__is_empty");
       break;
@@ -2411,7 +2407,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
   pp_cxx_left_paren (pp);
   pp->type_id (TRAIT_EXPR_TYPE1 (t));
 
-  if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
+  if (kind == CPTK_IS_BASE_OF)
     {
       pp_cxx_separate_with (pp, ',');
       pp->type_id (TRAIT_EXPR_TYPE2 (t));
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4563145..63cc0d3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4134,7 +4134,6 @@ complain_flags (bool decltype_p)
      __is_abstract ( type-id )
      __is_base_of ( type-id , type-id )
      __is_class ( type-id )
-     __is_convertible_to ( type-id , type-id )     
      __is_empty ( type-id )
      __is_enum ( type-id )
      __is_final ( type-id )
@@ -4483,7 +4482,6 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_IS_ABSTRACT:
 	case RID_IS_BASE_OF:
 	case RID_IS_CLASS:
-	case RID_IS_CONVERTIBLE_TO:
 	case RID_IS_EMPTY:
 	case RID_IS_ENUM:
 	case RID_IS_FINAL:
@@ -8665,7 +8663,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
   cp_trait_kind kind;
   tree type1, type2 = NULL_TREE;
   bool binary = false;
-  cp_decl_specifier_seq decl_specs;
 
   switch (keyword)
     {
@@ -8703,10 +8700,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     case RID_IS_CLASS:
       kind = CPTK_IS_CLASS;
       break;
-    case RID_IS_CONVERTIBLE_TO:
-      kind = CPTK_IS_CONVERTIBLE_TO;
-      binary = true;
-      break;
     case RID_IS_EMPTY:
       kind = CPTK_IS_EMPTY;
       break;
@@ -8757,14 +8750,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
   if (type1 == error_mark_node)
     return error_mark_node;
 
-  /* Build a trivial decl-specifier-seq.  */
-  clear_decl_specs (&decl_specs);
-  decl_specs.type = type1;
-
-  /* Call grokdeclarator to figure out what type this is.  */
-  type1 = grokdeclarator (NULL, &decl_specs, TYPENAME,
-			  /*initialized=*/0, /*attrlist=*/NULL);
-
   if (binary)
     {
       cp_parser_require (parser, CPP_COMMA, RT_COMMA);
@@ -8773,14 +8758,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
 
       if (type2 == error_mark_node)
 	return error_mark_node;
-
-      /* Build a trivial decl-specifier-seq.  */
-      clear_decl_specs (&decl_specs);
-      decl_specs.type = type2;
-
-      /* Call grokdeclarator to figure out what type this is.  */
-      type2 = grokdeclarator (NULL, &decl_specs, TYPENAME,
-			      /*initialized=*/0, /*attrlist=*/NULL);
     }
 
   cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index debd785..3fbbb17 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7355,10 +7355,6 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_CLASS:
       return (NON_UNION_CLASS_TYPE_P (type1));
 
-    case CPTK_IS_CONVERTIBLE_TO:
-      /* TODO  */
-      return false;
-
     case CPTK_IS_EMPTY:
       return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1));
 
@@ -7413,36 +7409,8 @@ check_trait_type (tree type)
 tree
 finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
 {
-  gcc_assert (kind == CPTK_HAS_NOTHROW_ASSIGN
-	      || kind == CPTK_HAS_NOTHROW_CONSTRUCTOR
-	      || kind == CPTK_HAS_NOTHROW_COPY
-	      || kind == CPTK_HAS_TRIVIAL_ASSIGN
-	      || kind == CPTK_HAS_TRIVIAL_CONSTRUCTOR
-	      || kind == CPTK_HAS_TRIVIAL_COPY
-	      || kind == CPTK_HAS_TRIVIAL_DESTRUCTOR
-	      || kind == CPTK_HAS_VIRTUAL_DESTRUCTOR	      
-	      || kind == CPTK_IS_ABSTRACT
-	      || kind == CPTK_IS_BASE_OF
-	      || kind == CPTK_IS_CLASS
-	      || kind == CPTK_IS_CONVERTIBLE_TO
-	      || kind == CPTK_IS_EMPTY
-	      || kind == CPTK_IS_ENUM
-	      || kind == CPTK_IS_FINAL
-	      || kind == CPTK_IS_LITERAL_TYPE
-	      || kind == CPTK_IS_POD
-	      || kind == CPTK_IS_POLYMORPHIC
-	      || kind == CPTK_IS_STD_LAYOUT
-	      || kind == CPTK_IS_TRIVIAL
-	      || kind == CPTK_IS_UNION);
-
-  if (kind == CPTK_IS_CONVERTIBLE_TO)
-    {
-      sorry ("__is_convertible_to");
-      return error_mark_node;
-    }
-
   if (type1 == error_mark_node
-      || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
+      || ((kind == CPTK_IS_BASE_OF)
 	  && type2 == error_mark_node))
     return error_mark_node;
 
@@ -7491,7 +7459,6 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_UNION:
       break;
     
-    case CPTK_IS_CONVERTIBLE_TO:
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/testsuite/g++.dg/ext/is_class_error2.C b/gcc/testsuite/g++.dg/ext/is_class_error2.C
index 8649dc4..b8c0385 100644
--- a/gcc/testsuite/g++.dg/ext/is_class_error2.C
+++ b/gcc/testsuite/g++.dg/ext/is_class_error2.C
@@ -13,7 +13,6 @@ template<int> void foo()
   __is_abstract(int)(); // { dg-error "'__is_abstract\\(int\\)' cannot be used" }
   __is_base_of(int, float)(); // { dg-error "'__is_base_of\\(int, float\\)' cannot be used" }
   __is_class(int)(); // { dg-error "'__is_class\\(int\\)' cannot be used" }
-  __is_convertible_to(int, float)(); // { dg-message "unimplemented" }
   __is_empty(int)(); // { dg-error "'__is_empty\\(int\\)' cannot be used" }
   __is_enum(int)(); // { dg-error "'__is_enum\\(int\\)' cannot be used" }
   __is_pod(int)(); // { dg-error "'__is_pod\\(int\\)' cannot be used" }
commit dc3e9ae069b4d55ca1d684fa5fa6f0757d997c60
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Sep 25 13:36:05 2014 -0400

    c-family/
    	* c-common.h (enum rid): Add RID_IS_TRIVIALLY_COPYABLE.
    	* c-common.c (c_common_reswords): Add __is_trivially_copyable.
    cp/
    	* 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.
    	(cp_parser_trait_expr): Likewise.
    	* semantics.c (trait_expr_value): Likewise.
    	(finish_trait_expr): Likewise.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 0324a0a..482dd44 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -480,6 +480,7 @@ 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_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY },
   { "__is_union",	RID_IS_UNION,	D_CXXONLY },
   { "__label__",	RID_LABEL,	0 },
   { "__null",		RID_NULL,	0 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5ba7859..b7e3385 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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_COPYABLE,
   RID_IS_UNION,                RID_UNDERLYING_TYPE,
 
   /* C++11 */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0bb6ef9..c22fbfa 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -653,6 +653,7 @@ typedef enum cp_trait_kind
   CPTK_IS_POLYMORPHIC,
   CPTK_IS_STD_LAYOUT,
   CPTK_IS_TRIVIAL,
+  CPTK_IS_TRIVIALLY_COPYABLE,
   CPTK_IS_UNION,
   CPTK_UNDERLYING_TYPE
 } cp_trait_kind;
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index f0734ec..7b2d7fd 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -2393,6 +2393,9 @@ 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_COPYABLE:
+      pp_cxx_ws_string (pp, "__is_trivially_copyable");
+      break;
     case CPTK_IS_UNION:
       pp_cxx_ws_string (pp, "__is_union");
       break;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 63cc0d3..b1feef5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4490,6 +4490,7 @@ cp_parser_primary_expression (cp_parser *parser,
 	case RID_IS_POLYMORPHIC:
 	case RID_IS_STD_LAYOUT:
 	case RID_IS_TRIVIAL:
+	case RID_IS_TRIVIALLY_COPYABLE:
 	case RID_IS_UNION:
 	  return cp_parser_trait_expr (parser, token->keyword);
 
@@ -8724,6 +8725,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     case RID_IS_TRIVIAL:
       kind = CPTK_IS_TRIVIAL;
       break;
+    case RID_IS_TRIVIALLY_COPYABLE:
+      kind = CPTK_IS_TRIVIALLY_COPYABLE;
+      break;
     case RID_IS_UNION:
       kind = CPTK_IS_UNION;
       break;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 3fbbb17..9bcc6d7 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7379,6 +7379,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_TRIVIAL:
       return (trivial_type_p (type1));
 
+    case CPTK_IS_TRIVIALLY_COPYABLE:
+      return (trivially_copyable_p (type1));
+
     case CPTK_IS_UNION:
       return (type_code1 == UNION_TYPE);
 
@@ -7442,6 +7445,7 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
     case CPTK_IS_POLYMORPHIC:
     case CPTK_IS_STD_LAYOUT:
     case CPTK_IS_TRIVIAL:
+    case CPTK_IS_TRIVIALLY_COPYABLE:
       if (!check_trait_type (type1))
 	return error_mark_node;
       break;
commit 6d2c4c2a1d74c455d2a0fc381965a859088de606
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Sep 29 16:39:55 2014 -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.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 482dd44..b16d030 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index b7e3385..1e3477f 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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,
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c22fbfa..cc11bba 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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
@@ -5522,6 +5524,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);
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 7b2d7fd..67e84c0 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -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;
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index b427d65..9a2bd0f 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -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.  */
 
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b1feef5..e4aaf53 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 9bcc6d7..7569826 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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
index 0000000..f558538
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C
@@ -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));

Reply via email to