typeck.c (complete_type_or_maybe_complain): Split out from...
authorJason Merrill <jason@redhat.com>
Fri, 6 Aug 2010 19:35:01 +0000 (15:35 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 6 Aug 2010 19:35:01 +0000 (15:35 -0400)
* typeck.c (complete_type_or_maybe_complain): Split out from...
(complete_type_or_else): Here.
(build_class_member_access_expr): Call it.
(finish_class_member_access_expr): Likewise.
* call.c (build_special_member_call): Likewise.
* cvt.c (build_expr_type_conversion): Likewise.
* init.c (build_new): Likewise.
* typeck2.c (build_functional_cast): Likewise.
* cp-tree.h: Declare it.

* init.c (build_value_init): Add complain parm.
(build_value_init_noctor): Likewise.
(perform_member_init): Pass it.
(expand_aggr_init_1): Likewise.
(build_new_1): Likewise.
(build_vec_init): Likewise.
* pt.c (tsubst_expr): Likewise.
* typeck2.c (build_functional_cast): Likewise.
* cp-tree.h: Adjust.
* tree.c (build_target_expr_with_type): Handle error_mark_node.

From-SVN: r162953

12 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/init.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/sfinae3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/sfinae4.C [new file with mode: 0644]

index c9cb173..b4eea19 100644 (file)
@@ -1,5 +1,26 @@
 2010-08-06  Jason Merrill  <jason@redhat.com>
 
+       * typeck.c (complete_type_or_maybe_complain): Split out from...
+       (complete_type_or_else): Here.
+       (build_class_member_access_expr): Call it.
+       (finish_class_member_access_expr): Likewise.
+       * call.c (build_special_member_call): Likewise.
+       * cvt.c (build_expr_type_conversion): Likewise.
+       * init.c (build_new): Likewise.
+       * typeck2.c (build_functional_cast): Likewise.
+       * cp-tree.h: Declare it.
+
+       * init.c (build_value_init): Add complain parm.
+       (build_value_init_noctor): Likewise.
+       (perform_member_init): Pass it.
+       (expand_aggr_init_1): Likewise.
+       (build_new_1): Likewise.
+       (build_vec_init): Likewise.
+       * pt.c (tsubst_expr): Likewise.
+       * typeck2.c (build_functional_cast): Likewise.
+       * cp-tree.h: Adjust.
+       * tree.c (build_target_expr_with_type): Handle error_mark_node.
+
        * typeck.c (decay_conversion): Any expression with type nullptr_t
        decays to nullptr.
 
index 0bc99bf..fbf98f1 100644 (file)
@@ -6189,7 +6189,7 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args,
   if (TYPE_P (binfo))
     {
       /* Resolve the name.  */
-      if (!complete_type_or_else (binfo, NULL_TREE))
+      if (!complete_type_or_maybe_complain (binfo, NULL_TREE, complain))
        return error_mark_node;
 
       binfo = TYPE_BINFO (binfo);
index 155db4c..baa6656 100644 (file)
@@ -4915,8 +4915,8 @@ extern tree build_aggr_init                       (tree, tree, int,
 extern int is_class_type                       (tree, int);
 extern tree get_type_value                     (tree);
 extern tree build_zero_init                    (tree, tree, bool);
-extern tree build_value_init                   (tree);
-extern tree build_value_init_noctor            (tree);
+extern tree build_value_init                   (tree, tsubst_flags_t);
+extern tree build_value_init_noctor            (tree, tsubst_flags_t);
 extern tree build_offset_ref                   (tree, tree, bool);
 extern tree build_new                          (VEC(tree,gc) **, tree, tree,
                                                 VEC(tree,gc) **, int,
@@ -5419,6 +5419,7 @@ extern tree condition_conversion          (tree);
 extern tree require_complete_type              (tree);
 extern tree complete_type                      (tree);
 extern tree complete_type_or_else              (tree, tree);
+extern tree complete_type_or_maybe_complain    (tree, tree, tsubst_flags_t);
 extern int type_unknown_p                      (const_tree);
 enum { ce_derived, ce_normal, ce_exact };
 extern bool comp_except_specs                  (const_tree, const_tree, int);
index 26c4442..ab2b6bf 100644 (file)
@@ -1468,7 +1468,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
 
   /* The code for conversions from class type is currently only used for
      delete expressions.  Other expressions are handled by build_new_op.  */
-  if (!complete_type_or_else (basetype, expr))
+  if (!complete_type_or_maybe_complain (basetype, expr, complain))
     return error_mark_node;
   if (!TYPE_HAS_CONVERSION (basetype))
     return NULL_TREE;
index 0edb800..8555fad 100644 (file)
@@ -269,7 +269,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
    TYPE, as described in [dcl.init].  */
 
 tree
-build_value_init (tree type)
+build_value_init (tree type, tsubst_flags_t complain)
 {
   /* [dcl.init]
 
@@ -302,7 +302,7 @@ build_value_init (tree type)
          (type,
           build_special_member_call (NULL_TREE, complete_ctor_identifier,
                                      NULL, type, LOOKUP_NORMAL,
-                                     tf_warning_or_error));
+                                     complain));
       else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
        {
          /* This is a class that needs constructing, but doesn't have
@@ -311,21 +311,21 @@ build_value_init (tree type)
             This will be handled in simplify_aggr_init_expr.  */
          tree ctor = build_special_member_call
            (NULL_TREE, complete_ctor_identifier,
-            NULL, type, LOOKUP_NORMAL, tf_warning_or_error);
+            NULL, type, LOOKUP_NORMAL, complain);
 
          ctor = build_aggr_init_expr (type, ctor);
          AGGR_INIT_ZERO_FIRST (ctor) = 1;
          return ctor;
        }
     }
-  return build_value_init_noctor (type);
+  return build_value_init_noctor (type, complain);
 }
 
 /* Like build_value_init, but don't call the constructor for TYPE.  Used
    for base initializers.  */
 
 tree
-build_value_init_noctor (tree type)
+build_value_init_noctor (tree type, tsubst_flags_t complain)
 {
   if (CLASS_TYPE_P (type))
     {
@@ -347,7 +347,12 @@ build_value_init_noctor (tree type)
              ftype = TREE_TYPE (field);
 
              if (TREE_CODE (ftype) == REFERENCE_TYPE)
-               error ("value-initialization of reference");
+               {
+                 if (complain & tf_error)
+                   error ("value-initialization of reference");
+                 else
+                   return error_mark_node;
+               }
 
              /* We could skip vfields and fields of types with
                 user-defined constructors, but I think that won't improve
@@ -359,7 +364,7 @@ build_value_init_noctor (tree type)
                 corresponding to base classes as well.  Thus, iterating
                 over TYPE_FIELDs will result in correct initialization of
                 all of the subobjects.  */
-             value = build_value_init (ftype);
+             value = build_value_init (ftype, complain);
 
              if (value)
                CONSTRUCTOR_APPEND_ELT(v, field, value);
@@ -401,7 +406,7 @@ build_value_init_noctor (tree type)
            ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
                                max_index);
 
-         ce->value = build_value_init (TREE_TYPE (type));
+         ce->value = build_value_init (TREE_TYPE (type), complain);
 
          /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs.  */
          gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
@@ -459,7 +464,8 @@ perform_member_init (tree member, tree init)
                       member);
          else
            {
-             init = build2 (INIT_EXPR, type, decl, build_value_init (type));
+             init = build2 (INIT_EXPR, type, decl,
+                            build_value_init (type, tf_warning_or_error));
              finish_expr_stmt (init);
            }
        }
@@ -1473,7 +1479,8 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
         then just zero out the object and we're done.  */
       else
        {
-         init = build2 (INIT_EXPR, type, exp, build_value_init_noctor (type));
+         init = build2 (INIT_EXPR, type, exp,
+                        build_value_init_noctor (type, complain));
          finish_expr_stmt (init);
          return;
        }
@@ -2314,8 +2321,10 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
          else if (explicit_value_init_p)
            {
              /* Something like `new int()'.  */
-             init_expr = build2 (INIT_EXPR, type,
-                                 init_expr, build_value_init (type));
+             tree val = build_value_init (type, complain);
+             if (val == error_mark_node)
+               return error_mark_node;
+             init_expr = build2 (INIT_EXPR, type, init_expr, val);
            }
          else
            {
@@ -2534,7 +2543,7 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts,
   /* The type allocated must be complete.  If the new-type-id was
      "T[N]" then we are just checking that "T" is complete here, but
      that is equivalent, since the value of "N" doesn't matter.  */
-  if (!complete_type_or_else (type, NULL_TREE))
+  if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
     return error_mark_node;
 
   rval = build_new_1 (placement, type, nelts, init, use_global_new, complain);
@@ -3041,8 +3050,13 @@ build_vec_init (tree base, tree maxindex, tree init,
                                     0, complain);
        }
       else if (explicit_value_init_p)
-       elt_init = build2 (INIT_EXPR, type, to,
-                          build_value_init (type));
+       {
+         elt_init = build_value_init (type, complain);
+         if (elt_init == error_mark_node)
+           return error_mark_node;
+         else
+           elt_init = build2 (INIT_EXPR, type, to, elt_init);
+       }
       else
        {
          gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
index 2777ab7..bb6b1a0 100644 (file)
@@ -11705,7 +11705,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
                               pack expansion where the parameter packs
                               used in that expansion were of length
                               zero.  */
-                           init = build_value_init (TREE_TYPE (decl));
+                           init = build_value_init (TREE_TYPE (decl),
+                                                    complain);
                            if (TREE_CODE (init) == AGGR_INIT_EXPR)
                              init = get_target_expr (init);
                          }
index 450b9e8..5441448 100644 (file)
@@ -477,7 +477,8 @@ build_target_expr_with_type (tree init, tree type)
 {
   gcc_assert (!VOID_TYPE_P (type));
 
-  if (TREE_CODE (init) == TARGET_EXPR)
+  if (TREE_CODE (init) == TARGET_EXPR
+      || init == error_mark_node)
     return init;
   else if (CLASS_TYPE_P (type) && type_has_nontrivial_copy_init (type)
           && !VOID_TYPE_P (TREE_TYPE (init))
index 177f4bb..03e7297 100644 (file)
@@ -135,7 +135,7 @@ complete_type (tree type)
    Returns NULL_TREE if the type cannot be made complete.  */
 
 tree
-complete_type_or_else (tree type, tree value)
+complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
 {
   type = complete_type (type);
   if (type == error_mark_node)
@@ -143,13 +143,20 @@ complete_type_or_else (tree type, tree value)
     return NULL_TREE;
   else if (!COMPLETE_TYPE_P (type))
     {
-      cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+      if (complain & tf_error)
+       cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
       return NULL_TREE;
     }
   else
     return type;
 }
 
+tree
+complete_type_or_else (tree type, tree value)
+{
+  return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+}
+
 /* Return truthvalue of whether type of EXP is instantiated.  */
 
 int
@@ -2209,7 +2216,7 @@ build_class_member_access_expr (tree object, tree member,
      complete type).  */
   object_type = TREE_TYPE (object);
   if (!currently_open_class (object_type)
-      && !complete_type_or_else (object_type, object))
+      && !complete_type_or_maybe_complain (object_type, object, complain))
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
@@ -2585,7 +2592,7 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
      The type of the first expression shall be "class object" (of a
      complete type).  */
   if (!currently_open_class (object_type)
-      && !complete_type_or_else (object_type, object))
+      && !complete_type_or_maybe_complain (object_type, object, complain))
     return error_mark_node;
   if (!CLASS_TYPE_P (object_type))
     {
index ce83d7c..59b9c40 100644 (file)
@@ -1606,7 +1606,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
 
      then the slot being initialized will be filled in.  */
 
-  if (!complete_type_or_else (type, NULL_TREE))
+  if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
     return error_mark_node;
   if (abstract_virtuals_error (NULL_TREE, type))
     return error_mark_node;
@@ -1631,7 +1631,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
         just calling the constructor, so fall through.  */
       && !TYPE_HAS_USER_CONSTRUCTOR (type))
     {
-      exp = build_value_init (type);
+      exp = build_value_init (type, complain);
       return get_target_expr (exp);
     }
 
index d2ba094..9013a05 100644 (file)
@@ -1,3 +1,8 @@
+2010-08-06  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/sfinae3.C: New.
+       * g++.dg/cpp0x/sfinae4.C: New.
+
 2010-08-06  Richard Guenther  <rguenther@suse.de>
 
        * gcc.dg/tree-ssa/ssa-dce-3.c: XFAIL.
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae3.C b/gcc/testsuite/g++.dg/cpp0x/sfinae3.C
new file mode 100644 (file)
index 0000000..8582ba7
--- /dev/null
@@ -0,0 +1,56 @@
+// { dg-options -std=c++0x }
+
+namespace std { template <class T> T&& declval(); }
+
+template<typename _Tp, typename... _Args>
+  class is_constructible_mini
+  {
+    typedef char __one;
+    typedef struct { char __arr[2]; } __two;
+
+    template<typename _Tp1, typename... _Args1>
+      static decltype(::new _Tp1(std::declval<_Args1>()...), __one())
+      __test(int);
+
+    template<typename, typename...>
+      static __two __test(...);
+
+  public:
+    static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1;
+  };
+
+/*
+template<typename _Tp>
+  class is_constructible_mini<_Tp>
+  {
+    typedef char __one;
+    typedef struct { char __arr[2]; } __two;
+
+    template<typename _Tp1>
+      static decltype(::new _Tp1, __one()) __test(int);
+
+    template<typename>
+      static __two __test(...);
+
+  public:
+    static const bool value
+    = sizeof(__test<typename std::remove_cv<_Tp>::type>(0)) == 1;
+  };
+*/
+
+struct A
+{
+  A(int);
+};
+
+struct B { };
+
+static_assert( is_constructible_mini<A, int>::value, "");
+static_assert( is_constructible_mini<A, A>::value, "");
+static_assert( !is_constructible_mini<A, int, double>::value, "");
+
+static_assert( !is_constructible_mini<A>::value, "");  // doesn't compile without the
+                                                       // partial specialization
+
+static_assert( is_constructible_mini<B>::value, "");
+static_assert( is_constructible_mini<const B>::value, "");
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae4.C b/gcc/testsuite/g++.dg/cpp0x/sfinae4.C
new file mode 100644 (file)
index 0000000..b664831
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-options -std=c++0x }
+
+namespace std { template <class T> T&& declval(); }
+
+template<typename _Tp, typename... _Args>
+  class is_constructible_mini
+  {
+    typedef char __one;
+    typedef struct { char __arr[2]; } __two;
+
+    template<typename _Tp1, typename... _Args1>
+      static decltype(::new _Tp1(std::declval<_Args1>()...), __one())
+      __test(int);
+
+    template<typename, typename...>
+      static __two __test(...);
+
+  public:
+    static const bool value = sizeof(__test<_Tp, _Args...>(0)) == 1;
+  };
+
+static_assert( !is_constructible_mini<int[], int>::value, "");
+static_assert( !is_constructible_mini<void, int>::value, "");