Machinery to support implicit delete/move.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 Jun 2010 00:50:57 +0000 (00:50 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 30 Jun 2010 00:50:57 +0000 (00:50 +0000)
* cp-tree.h: (struct lang_type_class): Add lazy_move_assign,
has_complex_move_ctor, has_complex_move_assign bitfields.
(CLASSTYPE_LAZY_MOVE_ASSIGN): New.
(TYPE_HAS_COMPLEX_MOVE_ASSIGN): New.
(TYPE_HAS_COMPLEX_MOVE_CTOR): New.
(enum special_function_kind): Add sfk_move_assignment.
(LOOKUP_SPECULATIVE): New.
* call.c (build_over_call): Return early if it's set.
(build_over_call): Use trivial_fn_p.
* class.c (check_bases): If the base has no default constructor,
the derived one is non-trivial.  Handle move ctor/op=.
(check_field_decl): Likewise.
(check_bases_and_members): Handle move ctor/op=.
(add_implicitly_declared_members): Handle CLASSTYPE_LAZY_MOVE_ASSIGN.
(type_has_move_constructor, type_has_move_assign): New.
* decl.c (grok_special_member_properties): Handle move ctor/op=.
* method.c (type_has_trivial_fn, type_set_nontrivial_flag): New.
(trivial_fn_p): New.
(do_build_copy_constructor): Use it.
(do_build_assign_ref): Likewise.  Handle move assignment.
(build_stub_type, build_stub_object, locate_fn_flags): New.
(locate_ctor): Use locate_fn_flags.
(locate_copy, locate_dtor): Remove.
(get_dtor, get_default_ctor, get_copy_ctor, get_copy_assign): New.
(process_subob_fn, synthesized_method_walk): New.
(maybe_explain_implicit_delete): New.
(implicitly_declare_fn): Use synthesized_method_walk,
type_has_trivial_fn, and type_set_nontrivial_flag.
(defaulted_late_check): Set DECL_DELETED_FN.
(defaultable_fn_check): Handle sfk_move_assignment.
(lazily_declare_fn): Clear CLASSTYPE_LAZY_* early.  Don't declare
implicitly deleted move ctor/op=.
* search.c (lookup_fnfields_1): Handle sfk_move_assignment.
(lookup_fnfields_slot): New.
* semantics.c (omp_clause_info_fndecl): Remove.
(cxx_omp_create_clause_info): Use get_default_ctor, get_copy_ctor,
get_copy_assign, trivial_fn_p.
(trait_expr_value): Adjust call to locate_ctor.
* tree.c (special_function_p): Handle sfk_move_assignment.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@161579 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/method.c
gcc/cp/search.c
gcc/cp/semantics.c
gcc/cp/tree.c

index bc02bd0..a8df233 100644 (file)
@@ -1,5 +1,46 @@
 2010-06-29  Jason Merrill  <jason@redhat.com>
 
+       Machinery to support implicit delete/move.
+       * cp-tree.h: (struct lang_type_class): Add lazy_move_assign,
+       has_complex_move_ctor, has_complex_move_assign bitfields.
+       (CLASSTYPE_LAZY_MOVE_ASSIGN): New.
+       (TYPE_HAS_COMPLEX_MOVE_ASSIGN): New.
+       (TYPE_HAS_COMPLEX_MOVE_CTOR): New.
+       (enum special_function_kind): Add sfk_move_assignment.
+       (LOOKUP_SPECULATIVE): New.
+       * call.c (build_over_call): Return early if it's set.
+       (build_over_call): Use trivial_fn_p.
+       * class.c (check_bases): If the base has no default constructor,
+       the derived one is non-trivial.  Handle move ctor/op=.
+       (check_field_decl): Likewise.
+       (check_bases_and_members): Handle move ctor/op=.
+       (add_implicitly_declared_members): Handle CLASSTYPE_LAZY_MOVE_ASSIGN.
+       (type_has_move_constructor, type_has_move_assign): New.
+       * decl.c (grok_special_member_properties): Handle move ctor/op=.
+       * method.c (type_has_trivial_fn, type_set_nontrivial_flag): New.
+       (trivial_fn_p): New.
+       (do_build_copy_constructor): Use it.
+       (do_build_assign_ref): Likewise.  Handle move assignment.
+       (build_stub_type, build_stub_object, locate_fn_flags): New.
+       (locate_ctor): Use locate_fn_flags.
+       (locate_copy, locate_dtor): Remove.
+       (get_dtor, get_default_ctor, get_copy_ctor, get_copy_assign): New.
+       (process_subob_fn, synthesized_method_walk): New.
+       (maybe_explain_implicit_delete): New.
+       (implicitly_declare_fn): Use synthesized_method_walk,
+       type_has_trivial_fn, and type_set_nontrivial_flag.
+       (defaulted_late_check): Set DECL_DELETED_FN.
+       (defaultable_fn_check): Handle sfk_move_assignment.
+       (lazily_declare_fn): Clear CLASSTYPE_LAZY_* early.  Don't declare
+       implicitly deleted move ctor/op=.
+       * search.c (lookup_fnfields_1): Handle sfk_move_assignment.
+       (lookup_fnfields_slot): New.
+       * semantics.c (omp_clause_info_fndecl): Remove.
+       (cxx_omp_create_clause_info): Use get_default_ctor, get_copy_ctor,
+       get_copy_assign, trivial_fn_p.
+       (trait_expr_value): Adjust call to locate_ctor.
+       * tree.c (special_function_p): Handle sfk_move_assignment.
+
        * class.c (type_has_virtual_destructor): New.
        * cp-tree.h: Declare it.
        * semantics.c (trait_expr_value): Use it.
index 852c7ea..9f4a520 100644 (file)
@@ -5613,6 +5613,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 
   if (DECL_FUNCTION_MEMBER_P (fn))
     {
+      tree access_fn;
       /* If FN is a template function, two cases must be considered.
         For example:
 
@@ -5640,10 +5641,41 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
         different access.  */
       if (DECL_TEMPLATE_INFO (fn)
          && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn)))
-       perform_or_defer_access_check (cand->access_path,
-                                      DECL_TI_TEMPLATE (fn), fn);
+       access_fn = DECL_TI_TEMPLATE (fn);
       else
-       perform_or_defer_access_check (cand->access_path, fn, fn);
+       access_fn = fn;
+      if (flags & LOOKUP_SPECULATIVE)
+       {
+         /* If we're checking for implicit delete, we don't want access
+            control errors.  */
+         if (!accessible_p (cand->access_path, access_fn, true))
+           {
+             /* Unless we're under maybe_explain_implicit_delete.  */
+             if (flags & LOOKUP_COMPLAIN)
+               enforce_access (cand->access_path, access_fn, fn);
+             return error_mark_node;
+           }
+       }
+      else
+       perform_or_defer_access_check (cand->access_path, access_fn, fn);
+    }
+
+  /* If we're checking for implicit delete, don't bother with argument
+     conversions.  */
+  if (flags & LOOKUP_SPECULATIVE)
+    {
+      if (DECL_DELETED_FN (fn))
+       {
+         if (flags & LOOKUP_COMPLAIN)
+           mark_used (fn);
+         return error_mark_node;
+       }
+      if (cand->viable == 1)
+       return fn;
+      else if (!(flags & LOOKUP_COMPLAIN))
+       /* Reject bad conversions now.  */
+       return error_mark_node;
+      /* else continue to get conversion error.  */
     }
 
   /* Find maximum size of vector to hold converted arguments.  */
@@ -5824,6 +5856,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       tree targ;
       tree arg = argarray[num_artificial_parms_for (fn)];
       tree fa;
+      bool trivial = trivial_fn_p (fn);
 
       /* Pull out the real argument, disregarding const-correctness.  */
       targ = arg;
@@ -5848,13 +5881,12 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       if (TREE_CODE (arg) == TARGET_EXPR
          && TARGET_EXPR_LIST_INIT_P (arg))
        {
-         /* Copy-list-initialization doesn't require the copy constructor
+         /* Copy-list-initialization doesn't require the constructor
             to be defined.  */
        }
       /* [class.copy]: the copy constructor is implicitly defined even if
         the implementation elided its use.  */
-      else if (TYPE_HAS_COMPLEX_COPY_CTOR (DECL_CONTEXT (fn))
-              || move_fn_p (fn))
+      else if (!trivial)
        {
          mark_used (fn);
          already_used = true;
@@ -5872,13 +5904,10 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        {
          if (TREE_CODE (arg) == TARGET_EXPR)
            return arg;
-         else if (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn))
-                  && !move_fn_p (fn))
+         else if (trivial)
            return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
        }
-      else if (TREE_CODE (arg) == TARGET_EXPR
-              || (TYPE_HAS_TRIVIAL_COPY_CTOR (DECL_CONTEXT (fn))
-                  && !move_fn_p (fn)))
+      else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
        {
          tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL,
                                                                complain));
@@ -5888,8 +5917,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
        }
     }
   else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
-          && copy_fn_p (fn)
-          && TYPE_HAS_TRIVIAL_COPY_ASSIGN (DECL_CONTEXT (fn)))
+          && trivial_fn_p (fn))
     {
       tree to = stabilize_reference
        (cp_build_indirect_ref (argarray[0], RO_NULL, complain));
index bfd3113..6f6aab6 100644 (file)
@@ -1314,10 +1314,14 @@ check_bases (tree t,
       TYPE_HAS_COMPLEX_COPY_ASSIGN (t)
        |= TYPE_HAS_COMPLEX_COPY_ASSIGN (basetype);
       TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (basetype);
+      TYPE_HAS_COMPLEX_MOVE_ASSIGN (t)
+       |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (basetype);
+      TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (basetype);
       TYPE_POLYMORPHIC_P (t) |= TYPE_POLYMORPHIC_P (basetype);
       CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t)
        |= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype);
-      TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (basetype);      
+      TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
+                                   || TYPE_HAS_COMPLEX_DFLT (basetype));
 
       /*  A standard-layout class is a class that:
          ...
@@ -2670,6 +2674,7 @@ add_implicitly_declared_members (tree t,
      a virtual function from a base class.  */
   if (TYPE_POLYMORPHIC_P (t)
       && (CLASSTYPE_LAZY_COPY_ASSIGN (t)
+         || CLASSTYPE_LAZY_MOVE_ASSIGN (t)
          || CLASSTYPE_LAZY_DESTRUCTOR (t)))
     {
       tree binfo = TYPE_BINFO (t);
@@ -2686,6 +2691,8 @@ add_implicitly_declared_members (tree t,
                {
                  if (CLASSTYPE_LAZY_COPY_ASSIGN (t))
                    lazily_declare_fn (sfk_copy_assignment, t);
+                 if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+                   lazily_declare_fn (sfk_move_assignment, t);
                }
              else if (DECL_DESTRUCTOR_P (fn)
                       && CLASSTYPE_LAZY_DESTRUCTOR (t))
@@ -2848,6 +2855,8 @@ check_field_decl (tree field,
          if (TYPE_HAS_COMPLEX_COPY_ASSIGN (type))
            error ("member %q+#D with copy assignment operator not allowed in union",
                   field);
+         /* Don't bother diagnosing move assop now; C++0x has more
+            flexible unions.  */
        }
       else
        {
@@ -2856,7 +2865,10 @@ check_field_decl (tree field,
            |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type);
          TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_HAS_COMPLEX_COPY_ASSIGN (type);
          TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_HAS_COMPLEX_COPY_CTOR (type);
-         TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (type);
+         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_HAS_COMPLEX_MOVE_ASSIGN (type);
+         TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_HAS_COMPLEX_MOVE_CTOR (type);
+         TYPE_HAS_COMPLEX_DFLT (t) |= (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
+                                       || TYPE_HAS_COMPLEX_DFLT (type));
        }
 
       if (!TYPE_HAS_CONST_COPY_CTOR (type))
@@ -3022,6 +3034,7 @@ check_field_decls (tree t, tree *access_decls,
             only way to initialize nonstatic const and reference
             members.  */
          TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
+         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
        }
 
       type = strip_array_types (type);
@@ -3108,6 +3121,7 @@ check_field_decls (tree t, tree *access_decls,
             only way to initialize nonstatic const and reference
             members.  */
          TYPE_HAS_COMPLEX_COPY_ASSIGN (t) = 1;
+         TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) = 1;
        }
       /* A field that is pseudo-const makes the structure likewise.  */
       else if (CLASS_TYPE_P (type))
@@ -4277,6 +4291,50 @@ type_has_virtual_destructor (tree type)
   return (dtor && DECL_VIRTUAL_P (dtor));
 }
 
+/* Returns true iff class T has a move constructor.  */
+
+bool
+type_has_move_constructor (tree t)
+{
+  tree fns;
+
+  if (CLASSTYPE_LAZY_MOVE_CTOR (t))
+    {
+      gcc_assert (COMPLETE_TYPE_P (t));
+      lazily_declare_fn (sfk_move_constructor, t);
+    }
+
+  if (!CLASSTYPE_METHOD_VEC (t))
+    return false;
+
+  for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+    if (move_fn_p (OVL_CURRENT (fns)))
+      return true;
+
+  return false;
+}
+
+/* Returns true iff class T has a move assignment operator.  */
+
+bool
+type_has_move_assign (tree t)
+{
+  tree fns;
+
+  if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
+    {
+      gcc_assert (COMPLETE_TYPE_P (t));
+      lazily_declare_fn (sfk_move_assignment, t);
+    }
+
+  for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
+       fns; fns = OVL_NEXT (fns))
+    if (move_fn_p (OVL_CURRENT (fns)))
+      return true;
+
+  return false;
+}
+
 /* Remove all zero-width bit-fields from T.  */
 
 static void
@@ -4411,6 +4469,7 @@ check_bases_and_members (tree t)
   /* Do some bookkeeping that will guide the generation of implicitly
      declared member functions.  */
   TYPE_HAS_COMPLEX_COPY_CTOR (t) |= TYPE_CONTAINS_VPTR_P (t);
+  TYPE_HAS_COMPLEX_MOVE_CTOR (t) |= TYPE_CONTAINS_VPTR_P (t);
   /* We need to call a constructor for this class if it has a
      user-provided constructor, or if the default constructor is going
      to initialize the vptr.  (This is not an if-and-only-if;
@@ -4434,6 +4493,7 @@ check_bases_and_members (tree t)
        || saved_nontrivial_dtor || saved_complex_asn_ref);
   CLASSTYPE_NON_STD_LAYOUT (t) |= TYPE_CONTAINS_VPTR_P (t);
   TYPE_HAS_COMPLEX_COPY_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t);
+  TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t);
   TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t);
 
   /* If the class has no user-declared constructor, but does have
index bfdf036..1d9077c 100644 (file)
@@ -1307,10 +1307,13 @@ struct GTY(()) lang_type_class {
   unsigned has_complex_dflt : 1;
   unsigned has_list_ctor : 1;
   unsigned non_std_layout : 1;
-  unsigned lazy_move_ctor : 1;
-
   unsigned is_literal : 1;
 
+  unsigned lazy_move_ctor : 1;
+  unsigned lazy_move_assign : 1;
+  unsigned has_complex_move_ctor : 1;
+  unsigned has_complex_move_assign : 1;
+
   /* When adding a flag here, consider whether or not it ought to
      apply to a template instance if it applies to the template.  If
      so, make sure to copy it in instantiate_class_template!  */
@@ -1318,7 +1321,7 @@ struct GTY(()) lang_type_class {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 7;
+  unsigned dummy : 4;
 
   tree primary_base;
   VEC(tree_pair_s,gc) *vcall_indices;
@@ -1416,6 +1419,11 @@ struct GTY((variable_size)) lang_type {
 #define CLASSTYPE_LAZY_COPY_ASSIGN(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->lazy_copy_assign)
 
+/* Nonzero means that NODE (a class type) has an assignment operator
+   -- but that it has not yet been declared.  */
+#define CLASSTYPE_LAZY_MOVE_ASSIGN(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->lazy_move_assign)
+
 /* Nonzero means that NODE (a class type) has a destructor -- but that
    it has not yet been declared.  */
 #define CLASSTYPE_LAZY_DESTRUCTOR(NODE) \
@@ -3166,6 +3174,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
 /* Nonzero if there is a non-trivial X::X(cv X&) for this class.  */
 #define TYPE_HAS_COMPLEX_COPY_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_copy_ctor)
 
+/* Nonzero if there is a non-trivial X::op=(X&&) for this class.  */
+#define TYPE_HAS_COMPLEX_MOVE_ASSIGN(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_move_assign)
+
+/* Nonzero if there is a non-trivial X::X(X&&) for this class.  */
+#define TYPE_HAS_COMPLEX_MOVE_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_move_ctor)
+
 /* Nonzero if there is a non-trivial default constructor for this class.  */
 #define TYPE_HAS_COMPLEX_DFLT(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt)
 
@@ -3869,6 +3883,7 @@ typedef enum special_function_kind {
   sfk_copy_constructor,    /* A copy constructor.  */
   sfk_move_constructor,    /* A move constructor.  */
   sfk_copy_assignment,     /* A copy assignment operator.  */
+  sfk_move_assignment,     /* A move assignment operator.  */
   sfk_destructor,         /* A destructor.  */
   sfk_complete_destructor, /* A destructor for complete objects.  */
   sfk_base_destructor,     /* A destructor for base subobjects.  */
@@ -4163,12 +4178,21 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
 /* We're inside an init-list, so narrowing conversions are ill-formed.  */
 #define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
 /* Avoid user-defined conversions for the first parameter of a copy
-   constructor.  */
+   constructor (or move constructor).  */
 #define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
 /* This is the first parameter of a copy constructor.  */
 #define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
 /* We only want to consider list constructors.  */
 #define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
+/* Return after determining which function to call and checking access.
+   Used by sythesized_method_walk to determine which functions will
+   be called to initialize subobjects, in order to determine exception
+   specification and possible implicit delete.
+   This is kind of a hack, but since access control doesn't respect SFINAE
+   we can't just use tf_none to avoid access control errors, we need
+   another mechanism.  Exiting early also avoids problems with trying
+   to perform argument conversions when the class isn't complete yet.  */
+#define LOOKUP_SPECULATIVE (LOOKUP_LIST_ONLY << 1)
 
 #define LOOKUP_NAMESPACES_ONLY(F)  \
   (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -4656,6 +4680,8 @@ extern bool user_provided_p                       (tree);
 extern bool type_has_user_provided_constructor  (tree);
 extern bool type_has_user_provided_default_constructor (tree);
 extern bool type_has_virtual_destructor                (tree);
+extern bool type_has_move_constructor          (tree);
+extern bool type_has_move_assign               (tree);
 extern void defaulted_late_check               (tree);
 extern bool defaultable_fn_check               (tree);
 extern void fixup_type_variants                        (tree);
@@ -4921,15 +4947,19 @@ extern void init_method                         (void);
 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 maybe_explain_implicit_delete      (tree);
 extern void synthesize_method                  (tree);
 extern tree lazily_declare_fn                  (special_function_kind,
                                                 tree);
 extern tree skip_artificial_parms_for          (const_tree, tree);
 extern int num_artificial_parms_for            (const_tree);
 extern tree make_alias_for                     (tree, tree);
-extern tree locate_copy                                (tree, void *);
-extern tree locate_ctor                                (tree, void *);
-extern tree locate_dtor                                (tree, void *);
+extern tree get_copy_ctor                      (tree);
+extern tree get_copy_assign                    (tree);
+extern tree get_default_ctor                   (tree);
+extern tree get_dtor                           (tree);
+extern tree locate_ctor                                (tree);
 
 /* In optimize.c */
 extern bool maybe_clone_body                   (tree);
@@ -5070,6 +5100,7 @@ extern int accessible_p                           (tree, tree, bool);
 extern tree lookup_field_1                     (tree, tree, bool);
 extern tree lookup_field                       (tree, tree, int, bool);
 extern int lookup_fnfields_1                   (tree, tree);
+extern tree lookup_fnfields_slot               (tree, tree);
 extern int class_method_index_for_fn           (tree, tree);
 extern tree lookup_fnfields                    (tree, tree, int);
 extern tree lookup_member                      (tree, tree, int, bool);
index 0c2f7e5..153bd53 100644 (file)
@@ -10273,6 +10273,8 @@ grok_special_member_properties (tree decl)
          if (user_provided_p (decl))
            TYPE_HAS_COMPLEX_DFLT (class_type) = 1;
        }
+      else if (move_fn_p (decl) && user_provided_p (decl))
+       TYPE_HAS_COMPLEX_MOVE_CTOR (class_type) = 1;
       else if (is_list_ctor (decl))
        TYPE_HAS_LIST_CTOR (class_type) = 1;
     }
@@ -10294,6 +10296,8 @@ grok_special_member_properties (tree decl)
          if (assop != 1)
            TYPE_HAS_CONST_COPY_ASSIGN (class_type) = 1;
        }
+      else if (move_fn_p (decl) && user_provided_p (decl))
+       TYPE_HAS_COMPLEX_MOVE_ASSIGN (class_type) = 1;
     }
   /* Destructors are handled in check_methods.  */
 }
index 96a1d54..64f7b7f 100644 (file)
@@ -59,7 +59,6 @@ typedef enum mangling_flags mangling_flags;
 
 static void do_build_copy_assign (tree);
 static void do_build_copy_constructor (tree);
-static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *);
 static tree make_alias_for_thunk (tree);
 
 /* Called once to initialize method.c.  */
@@ -400,6 +399,74 @@ use_thunk (tree thunk_fndecl, bool emit_p)
 \f
 /* Code for synthesizing methods which have default semantics defined.  */
 
+/* True iff CTYPE has a trivial SFK.  */
+
+static bool
+type_has_trivial_fn (tree ctype, special_function_kind sfk)
+{
+  switch (sfk)
+    {
+    case sfk_constructor:
+      return !TYPE_HAS_COMPLEX_DFLT (ctype);
+    case sfk_copy_constructor:
+      return !TYPE_HAS_COMPLEX_COPY_CTOR (ctype);
+    case sfk_move_constructor:
+      return !TYPE_HAS_COMPLEX_MOVE_CTOR (ctype);
+    case sfk_copy_assignment:
+      return !TYPE_HAS_COMPLEX_COPY_ASSIGN (ctype);
+    case sfk_move_assignment:
+      return !TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype);
+    case sfk_destructor:
+      return !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype);
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Note that CTYPE has a non-trivial SFK even though we previously thought
+   it was trivial.  */
+
+static void
+type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
+{
+  switch (sfk)
+    {
+    case sfk_constructor:
+      TYPE_HAS_COMPLEX_DFLT (ctype) = true;
+      return;
+    case sfk_copy_constructor:
+      TYPE_HAS_COMPLEX_COPY_CTOR (ctype) = true;
+      return;
+    case sfk_move_constructor:
+      TYPE_HAS_COMPLEX_MOVE_CTOR (ctype) = true;
+      return;
+    case sfk_copy_assignment:
+      TYPE_HAS_COMPLEX_COPY_ASSIGN (ctype) = true;
+      return;
+    case sfk_move_assignment:
+      TYPE_HAS_COMPLEX_MOVE_ASSIGN (ctype) = true;
+      return;
+    case sfk_destructor:
+      TYPE_HAS_NONTRIVIAL_DESTRUCTOR (ctype) = true;
+      return;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* True iff FN is a trivial defaulted member function ([cd]tor, op=).  */
+
+bool
+trivial_fn_p (tree fn)
+{
+  if (!DECL_DEFAULTED_FN (fn))
+    return false;
+
+  /* If fn is a clone, get the primary variant.  */
+  fn = DECL_ORIGIN (fn);
+  return type_has_trivial_fn (DECL_CONTEXT (fn), special_function_p (fn));
+}
+
 /* Generate code for default X(X&) or X(X&&) constructor.  */
 
 static void
@@ -407,14 +474,15 @@ do_build_copy_constructor (tree fndecl)
 {
   tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
   bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
+  bool trivial = trivial_fn_p (fndecl);
 
   parm = convert_from_reference (parm);
 
-  if (TYPE_HAS_TRIVIAL_COPY_CTOR (current_class_type)
+  if (trivial
       && is_empty_class (current_class_type))
     /* Don't copy the padding byte; it might not have been allocated
        if *this is a base subobject.  */;
-  else if (TYPE_HAS_TRIVIAL_COPY_CTOR (current_class_type))
+  else if (trivial)
     {
       tree t = build2 (INIT_EXPR, void_type_node, current_class_ref, parm);
       finish_expr_stmt (t);
@@ -512,15 +580,17 @@ do_build_copy_assign (tree fndecl)
 {
   tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
   tree compound_stmt;
+  bool move_p = move_fn_p (fndecl);
+  bool trivial = trivial_fn_p (fndecl);
 
   compound_stmt = begin_compound_stmt (0);
   parm = convert_from_reference (parm);
 
-  if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (current_class_type)
+  if (trivial
       && is_empty_class (current_class_type))
     /* Don't copy the padding byte; it might not have been allocated
        if *this is a base subobject.  */;
-  else if (TYPE_HAS_TRIVIAL_COPY_ASSIGN (current_class_type))
+  else if (trivial)
     {
       tree t = build2 (MODIFY_EXPR, void_type_node, current_class_ref, parm);
       finish_expr_stmt (t);
@@ -542,6 +612,8 @@ do_build_copy_assign (tree fndecl)
          /* We must convert PARM directly to the base class
             explicitly since the base class may be ambiguous.  */
          converted_parm = build_base_path (PLUS_EXPR, parm, base_binfo, 1);
+         if (move_p)
+           converted_parm = move (converted_parm);
          /* Call the base class assignment operator.  */
          parmvec = make_tree_vector_single (converted_parm);
          finish_expr_stmt
@@ -604,6 +676,8 @@ do_build_copy_assign (tree fndecl)
          expr_type = cp_build_qualified_type (expr_type, quals);
 
          init = build3 (COMPONENT_REF, expr_type, init, field, NULL_TREE);
+         if (move_p && TREE_CODE (expr_type) != REFERENCE_TYPE)
+           init = move (init);
 
          if (DECL_NAME (field))
            init = cp_build_modify_expr (comp, NOP_EXPR, init, 
@@ -695,163 +769,505 @@ synthesize_method (tree fndecl)
            fndecl);
 }
 
-/* Use EXTRACTOR to locate the relevant function called for each base &
-   class field of TYPE. CLIENT allows additional information to be passed
-   to EXTRACTOR.  Generates the union of all exceptions generated by those
-   functions.  Note that we haven't updated TYPE_FIELDS and such of any
-   variants yet, so we need to look at the main one.  */
+/* Build a reference to type TYPE with cv-quals QUALS, which is an
+   rvalue if RVALUE is true.  */
 
 static tree
-synthesize_exception_spec (tree type, tree (*extractor) (tree, void*),
-                          void *client)
+build_stub_type (tree type, int quals, bool rvalue)
 {
-  tree raises = empty_except_spec;
-  tree fields = TYPE_FIELDS (type);
-  tree binfo, base_binfo;
-  int i;
+  tree argtype = cp_build_qualified_type (type, quals);
+  return cp_build_reference_type (argtype, rvalue);
+}
 
-  for (binfo = TYPE_BINFO (type), i = 0;
-       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
-    {
-      tree fn = (*extractor) (BINFO_TYPE (base_binfo), client);
-      if (fn)
-       {
-         tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+/* Build a dummy glvalue from dereferencing a dummy reference of type
+   REFTYPE.  */
 
-         raises = merge_exception_specifiers (raises, fn_raises);
-       }
-    }
-  for (; fields; fields = TREE_CHAIN (fields))
-    {
-      tree type = TREE_TYPE (fields);
-      tree fn;
+static tree
+build_stub_object (tree reftype)
+{
+  tree stub = build1 (NOP_EXPR, reftype, integer_one_node);
+  return convert_from_reference (stub);
+}
 
-      if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
-       continue;
-      while (TREE_CODE (type) == ARRAY_TYPE)
-       type = TREE_TYPE (type);
-      if (!CLASS_TYPE_P (type))
-       continue;
+/* Determine which function will be called when looking up NAME in TYPE,
+   called with a single ARGTYPE argument, or no argument if ARGTYPE is
+   null.  FLAGS and COMPLAIN are as for build_new_method_call.
 
-      fn = (*extractor) (type, client);
-      if (fn)
-       {
-         tree fn_raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+   Returns a FUNCTION_DECL if all is well.
+   Returns NULL_TREE if overload resolution failed.
+   Returns error_mark_node if the chosen function cannot be called.  */
 
-         raises = merge_exception_specifiers (raises, fn_raises);
-       }
+static tree
+locate_fn_flags (tree type, tree name, tree argtype, int flags,
+                tsubst_flags_t complain)
+{
+  tree ob, fn, fns, binfo, rval;
+  VEC(tree,gc) *args;
+
+  if (TYPE_P (type))
+    binfo = TYPE_BINFO (type);
+  else
+    {
+      binfo = type;
+      type = BINFO_TYPE (binfo);
+    }
+
+  ob = build_stub_object (cp_build_reference_type (type, false));
+  args = make_tree_vector ();
+  if (argtype)
+    {
+      tree arg = build_stub_object (argtype);
+      VEC_quick_push (tree, args, arg);
     }
-  return raises;
+
+  fns = lookup_fnfields (binfo, name, 0);
+  rval = build_new_method_call (ob, fns, &args, binfo, flags, &fn, complain);
+
+  release_tree_vector (args);
+  if (fn && rval == error_mark_node)
+    return rval;
+  else
+    return fn;
 }
 
 /* Locate the dtor of TYPE.  */
 
 tree
-locate_dtor (tree type, void *client ATTRIBUTE_UNUSED)
+get_dtor (tree type)
 {
-  return CLASSTYPE_DESTRUCTORS (type);
+  tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE,
+                            LOOKUP_NORMAL, tf_warning_or_error);
+  if (fn == error_mark_node)
+    return NULL_TREE;
+  return fn;
 }
 
 /* Locate the default ctor of TYPE.  */
 
 tree
-locate_ctor (tree type, void *client ATTRIBUTE_UNUSED)
+locate_ctor (tree type)
 {
-  tree fns;
+  tree fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE,
+                            LOOKUP_SPECULATIVE, tf_none);
+  if (fn == error_mark_node)
+    return NULL_TREE;
+  return fn;
+}
+
+/* Likewise, but give any appropriate errors.  */
 
-  if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+tree
+get_default_ctor (tree type)
+{
+  tree fn = locate_fn_flags (type, complete_ctor_identifier, NULL_TREE,
+                            LOOKUP_NORMAL, tf_warning_or_error);
+  if (fn == error_mark_node)
+    return NULL_TREE;
+  return fn;
+}
+
+/* Locate the copy ctor of TYPE.  */
+
+tree
+get_copy_ctor (tree type)
+{
+  int quals = (TYPE_HAS_CONST_COPY_CTOR (type)
+              ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
+  tree argtype = build_stub_type (type, quals, false);
+  tree fn = locate_fn_flags (type, complete_ctor_identifier, argtype,
+                            LOOKUP_NORMAL, tf_warning_or_error);
+  if (fn == error_mark_node)
     return NULL_TREE;
+  return fn;
+}
 
-  /* Call lookup_fnfields_1 to create the constructor declarations, if
-     necessary.  */
-  if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
-    return lazily_declare_fn (sfk_constructor, type);
+/* Locate the copy assignment operator of TYPE.  */
 
-  for (fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
+tree
+get_copy_assign (tree type)
+{
+  int quals = (TYPE_HAS_CONST_COPY_ASSIGN (type)
+              ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
+  tree argtype = build_stub_type (type, quals, false);
+  tree fn = locate_fn_flags (type, ansi_assopname (NOP_EXPR), argtype,
+                            LOOKUP_NORMAL, tf_warning_or_error);
+  if (fn == error_mark_node)
+    return NULL_TREE;
+  return fn;
+}
+
+/* Subroutine of synthesized_method_walk.  Update SPEC_P, TRIVIAL_P and
+   DELETED_P or give an error message MSG with argument ARG.  */
+
+static void
+process_subob_fn (tree fn, bool move_p, tree *spec_p, bool *trivial_p,
+                 bool *deleted_p, const char *msg, tree arg)
+{
+  if (!fn || fn == error_mark_node)
+    goto bad;
+
+  if (spec_p)
     {
-      tree fn = OVL_CURRENT (fns);
-      tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+      tree raises = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn));
+      *spec_p = merge_exception_specifiers (*spec_p, raises);
+    }
 
-      parms = skip_artificial_parms_for (fn, parms);
+  if (trivial_p && !trivial_fn_p (fn))
+    *trivial_p = false;
 
-      if (sufficient_parms_p (parms))
-       return fn;
+  if (move_p && !move_fn_p (fn) && !trivial_fn_p (fn))
+    {
+      if (msg)
+       error (msg, arg);
+      goto bad;
     }
-  gcc_unreachable ();
+
+  return;
+
+ bad:
+  if (deleted_p)
+    *deleted_p = true;
 }
 
-struct copy_data
+/* The caller wants to generate an implicit declaration of SFK for CTYPE
+   which is const if relevant and CONST_P is set.  If spec_p, trivial_p and
+   deleted_p are non-null, set their referent appropriately.  If diag is
+   true, we're being called from maybe_explain_implicit_delete to give
+   errors.  */
+
+static void
+synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
+                        tree *spec_p, bool *trivial_p, bool *deleted_p,
+                        bool diag)
 {
-  tree name;
-  int quals;
-};
+  tree binfo, base_binfo, field, scope, fnname, rval, argtype;
+  bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
+  VEC(tree,gc) *vbases;
+  int i, quals, flags;
+  tsubst_flags_t complain;
+  const char *msg;
+
+  if (spec_p)
+    *spec_p = (cxx_dialect >= cxx0x
+              ? noexcept_true_spec : empty_except_spec);
+
+  if (deleted_p)
+    {
+      /* "The closure type associated with a lambda-expression has a deleted
+        default constructor and a deleted copy assignment operator."
+         This is diagnosed in maybe_explain_implicit_delete.  */
+      if (LAMBDA_TYPE_P (ctype)
+         && (sfk == sfk_constructor
+             || sfk == sfk_copy_assignment))
+       {
+         *deleted_p = true;
+         return;
+       }
 
-/* Locate the copy ctor or copy assignment of TYPE. CLIENT_
-   points to a COPY_DATA holding the name (NULL for the ctor)
-   and desired qualifiers of the source operand.  */
+      *deleted_p = false;
+    }
 
-tree
-locate_copy (tree type, void *client_)
-{
-  struct copy_data *client = (struct copy_data *)client_;
-  tree fns;
-  tree best = NULL_TREE;
-  bool excess_p = false;
+  move_p = false;
+  switch (sfk)
+    {
+    case sfk_constructor:
+    case sfk_destructor:
+      copy_arg_p = false;
+      break;
+
+    case sfk_move_constructor:
+    case sfk_move_assignment:
+      move_p = true;
+    case sfk_copy_constructor:
+    case sfk_copy_assignment:
+      copy_arg_p = true;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  expected_trivial = type_has_trivial_fn (ctype, sfk);
+  if (trivial_p)
+    *trivial_p = expected_trivial;
+
+#ifndef ENABLE_CHECKING
+  /* The TYPE_HAS_COMPLEX_* flags tell us about constraints from base
+     class versions and other properties of the type.  But a subobject
+     class can be trivially copyable and yet have overload resolution
+     choose a template constructor for initialization, depending on
+     rvalueness and cv-quals.  So we can't exit early for copy/move
+     methods in C++0x.  */
+  if (expected_trivial
+      && (!copy_arg_p || cxx_dialect < cxx0x))
+    return;
+#endif
 
-  if (client->name)
+  assign_p = false;
+  switch (sfk)
     {
-      int ix;
-      ix = lookup_fnfields_1 (type, client->name);
-      if (ix < 0)
-       return NULL_TREE;
-      fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
+    case sfk_move_assignment:
+    case sfk_copy_assignment:
+      assign_p = true;
+      fnname = ansi_assopname (NOP_EXPR);
+      break;
+
+    case sfk_destructor:
+      check_vdtor = true;
+      /* The synthesized method will call base dtors, but check complete
+        here to avoid having to deal with VTT.  */
+      fnname = complete_dtor_identifier;
+      break;
+
+    case sfk_constructor:
+    case sfk_move_constructor:
+    case sfk_copy_constructor:
+      fnname = complete_ctor_identifier;
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  else if (TYPE_HAS_COPY_CTOR (type))
+
+  ++cp_unevaluated_operand;
+  ++c_inhibit_evaluation_warnings;
+
+  scope = push_scope (ctype);
+
+  if (diag)
     {
-      /* If construction of the copy constructor was postponed, create
-        it now.  */
-      if (CLASSTYPE_LAZY_COPY_CTOR (type))
-       lazily_declare_fn (sfk_copy_constructor, type);
-      if (CLASSTYPE_LAZY_MOVE_CTOR (type))
-       lazily_declare_fn (sfk_move_constructor, type);
-      fns = CLASSTYPE_CONSTRUCTORS (type);
+      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
+      complain = tf_warning_or_error;
     }
   else
-    return NULL_TREE;
-  for (; fns; fns = OVL_NEXT (fns))
     {
-      tree fn = OVL_CURRENT (fns);
-      tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
-      tree src_type;
-      int excess;
-      int quals;
-
-      parms = skip_artificial_parms_for (fn, parms);
-      if (!parms)
-       continue;
-      src_type = non_reference (TREE_VALUE (parms));
+      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE;
+      complain = tf_none;
+    }
 
-      if (src_type == error_mark_node)
-        return NULL_TREE;
+  if (const_p)
+    quals = TYPE_QUAL_CONST;
+  else
+    quals = TYPE_UNQUALIFIED;
+  argtype = NULL_TREE;
 
-      if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
-       continue;
-      if (!sufficient_parms_p (TREE_CHAIN (parms)))
+  for (binfo = TYPE_BINFO (ctype), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i)
+    {
+      tree basetype = BINFO_TYPE (base_binfo);
+      if (copy_arg_p)
+       argtype = build_stub_type (basetype, quals, move_p);
+      rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+
+      if (!diag)
+       msg = NULL;
+      else if (assign_p)
+       msg = ("base %qT does not have a move assignment operator or trivial "
+              "copy assignment operator");
+      else
+       msg = ("base %qT does not have a move constructor or trivial "
+              "copy constructor");
+
+      process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
+                       msg, BINFO_TYPE (base_binfo));
+
+      if (check_vdtor && type_has_virtual_destructor (basetype))
+       {
+         rval = locate_fn_flags (ctype, ansi_opname (DELETE_EXPR),
+                                 ptr_type_node, flags, complain);
+         /* Unlike for base ctor/op=/dtor, for operator delete it's fine
+            to have a null rval (no class-specific op delete).  */
+         if (rval && rval == error_mark_node && deleted_p)
+           *deleted_p = true;
+       }
+    }
+
+  vbases = CLASSTYPE_VBASECLASSES (ctype);
+  if (vbases && assign_p && move_p)
+    {
+      /* Should the spec be changed to allow vbases that only occur once?  */
+      if (diag)
+       error ("%qT has virtual bases, default move assignment operator "
+              "cannot be generated", ctype);
+      else if (deleted_p)
+       *deleted_p = true;
+    }
+  else if (!assign_p)
+    for (i = 0; VEC_iterate (tree, vbases, i, base_binfo); ++i)
+      {
+       if (copy_arg_p)
+         argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
+       rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+
+       if (!diag)
+         msg = NULL;
+       else if (assign_p)
+         msg = ("virtual base %qT does not have a move assignment "
+                "operator or trivial copy assignment operator");
+       else
+         msg = ("virtual base %qT does not have a move constructor "
+                "or trivial copy constructor");
+
+       process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
+                         msg, BINFO_TYPE (base_binfo));
+      }
+
+  for (field = TYPE_FIELDS (ctype); field; field = TREE_CHAIN (field))
+    {
+      tree mem_type;
+
+      if (TREE_CODE (field) != FIELD_DECL
+         || DECL_ARTIFICIAL (field))
        continue;
-      quals = cp_type_quals (src_type);
-      if (client->quals & ~quals)
+
+      mem_type = strip_array_types (TREE_TYPE (field));
+      if (assign_p)
+       {
+         bool bad = true;
+         if (CP_TYPE_CONST_P (mem_type) && !CLASS_TYPE_P (mem_type))
+           {
+             if (diag)
+               error ("non-static const member %q#D, can't use default "
+                      "assignment operator", field);
+           }
+         else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
+           {
+             if (diag)
+               error ("non-static reference member %q#D, can't use "
+                      "default assignment operator", field);
+           }
+         else
+           bad = false;
+
+         if (bad && deleted_p)
+           *deleted_p = true;
+       }
+      else if (sfk == sfk_constructor)
+       {
+         bool bad = true;
+         if (CP_TYPE_CONST_P (mem_type)
+             && (!CLASS_TYPE_P (mem_type)
+                 || !type_has_user_provided_default_constructor (mem_type)))
+           {
+             if (diag)
+               error ("uninitialized non-static const member %q#D",
+                      field);
+           }
+         else if (TREE_CODE (mem_type) == REFERENCE_TYPE)
+           {
+             if (diag)
+               error ("uninitialized non-static reference member %q#D",
+                      field);
+           }
+         else
+           bad = false;
+
+         if (bad && deleted_p)
+           *deleted_p = true;
+       }
+
+      if (!CLASS_TYPE_P (mem_type)
+         || ANON_AGGR_TYPE_P (mem_type))
        continue;
-      excess = quals & ~client->quals;
-      if (!best || (excess_p && !excess))
+
+      if (copy_arg_p)
        {
-         best = fn;
-         excess_p = excess;
+         int mem_quals = cp_type_quals (mem_type) | quals;
+         if (DECL_MUTABLE_P (field))
+           mem_quals &= ~TYPE_QUAL_CONST;
+         argtype = build_stub_type (mem_type, mem_quals, move_p);
        }
+
+      rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
+
+      if (!diag)
+       msg = NULL;
+      else if (assign_p)
+       msg = ("non-static data member %qD does not have a move "
+              "assignment operator or trivial copy assignment operator");
       else
-       /* Ambiguous */
-       return NULL_TREE;
+       msg = ("non-static data member %qD does not have a move "
+              "constructor or trivial copy constructor");
+
+      process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
+                       msg, field);
     }
-  return best;
+
+  pop_scope (scope);
+
+  --cp_unevaluated_operand;
+  --c_inhibit_evaluation_warnings;
+
+#ifdef ENABLE_CHECKING
+  /* If we expected this to be trivial but it isn't, then either we're in
+     C++0x mode and this is a copy/move ctor/op= or there's an error.  */
+  gcc_assert (!(trivial_p && expected_trivial && !*trivial_p)
+             || (copy_arg_p && cxx_dialect >= cxx0x)
+             || errorcount);
+#endif
+}
+
+/* DECL is a deleted function.  If it's implicitly deleted, explain why and
+   return true; else return false.  */
+
+bool
+maybe_explain_implicit_delete (tree decl)
+{
+  /* If decl is a clone, get the primary variant.  */
+  decl = DECL_ORIGIN (decl);
+  gcc_assert (DECL_DELETED_FN (decl));
+  if (DECL_DEFAULTED_FN (decl)
+      && DECL_INITIAL (decl) == NULL_TREE)
+    {
+      /* Not marked GTY; it doesn't need to be GC'd or written to PCH.  */
+      static htab_t explained_htab;
+      void **slot;
+
+      special_function_kind sfk;
+      location_t loc;
+      bool informed;
+      tree ctype;
+
+      if (!explained_htab)
+       explained_htab = htab_create (37, htab_hash_pointer,
+                                     htab_eq_pointer, NULL);
+      slot = htab_find_slot (explained_htab, decl, INSERT);
+      if (*slot)
+       return true;
+      *slot = decl;
+
+      sfk = special_function_p (decl);
+      ctype = DECL_CONTEXT (decl);
+      loc = input_location;
+      input_location = DECL_SOURCE_LOCATION (decl);
+
+      informed = false;
+      if (LAMBDA_TYPE_P (ctype))
+       {
+         informed = true;
+         if (sfk == sfk_constructor)
+           error ("a lambda closure type has a deleted default constructor");
+         else if (sfk == sfk_copy_assignment)
+           error ("a lambda closure type has a deleted copy assignment operator");
+         else
+           informed = false;
+       }
+      if (!informed)
+       {
+         tree parm_type = TREE_VALUE (FUNCTION_FIRST_USER_PARMTYPE (decl));
+         bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
+         tree scope = push_scope (ctype);
+         error ("%qD is implicitly deleted because the default "
+                "definition would be ill-formed:", decl);
+         pop_scope (scope);
+         synthesized_method_walk (ctype, sfk, const_p,
+                                  NULL, NULL, NULL, true);
+       }
+
+      input_location = loc;
+      return true;
+    }
+  return false;
 }
 
 /* Implicitly declare the special function indicated by KIND, as a
@@ -872,6 +1288,8 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
   tree this_parm;
   tree name;
   HOST_WIDE_INT saved_processing_template_decl;
+  bool deleted_p;
+  bool trivial_p;
 
   /* Because we create declarations for implicitly declared functions
      lazily, we may be creating the declaration for a member of TYPE
@@ -903,50 +1321,49 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p)
     case sfk_destructor:
       /* Destructor.  */
       name = constructor_name (type);
-      raises = synthesize_exception_spec (type, &locate_dtor, 0);
       break;
 
     case sfk_constructor:
       /* Default constructor.  */
       name = constructor_name (type);
-      raises = synthesize_exception_spec (type, &locate_ctor, 0);
       break;
 
     case sfk_copy_constructor:
     case sfk_copy_assignment:
     case sfk_move_constructor:
+    case sfk_move_assignment:
     {
-      struct copy_data data;
-
-      data.name = NULL;
-      data.quals = 0;
-      if (kind == sfk_copy_assignment)
+      bool move_p;
+      if (kind == sfk_copy_assignment
+         || kind == sfk_move_assignment)
        {
          return_type = build_reference_type (type);
          name = ansi_assopname (NOP_EXPR);
-         data.name = name;
        }
       else
        name = constructor_name (type);
 
       if (const_p)
-       {
-         data.quals = TYPE_QUAL_CONST;
-         rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
-       }
+       rhs_parm_type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
       else
        rhs_parm_type = type;
-      rhs_parm_type
-       = cp_build_reference_type (rhs_parm_type,
-                                  kind == sfk_move_constructor);
+      move_p = (kind == sfk_move_assignment
+               || kind == sfk_move_constructor);
+      rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
+
       parameter_types = tree_cons (NULL_TREE, rhs_parm_type, parameter_types);
-      raises = synthesize_exception_spec (type, &locate_copy, &data);
       break;
     }
     default:
       gcc_unreachable ();
     }
 
+  synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
+                          &deleted_p, false);
+
+  if (!trivial_p && type_has_trivial_fn (type, kind))
+    type_set_nontrivial_flag (type, kind);
+
   /* Create the function.  */
   fn_type = build_method_type_directly (type, return_type, parameter_types);
   if (raises)
@@ -1031,6 +1448,9 @@ defaulted_late_check (tree fn)
       tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn));
       TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec);
     }
+
+  if (DECL_DELETED_FN (implicit_fn))
+    DECL_DELETED_FN (fn) = 1;
 }
 
 /* Returns true iff FN can be explicitly defaulted, and gives any
@@ -1055,9 +1475,13 @@ defaultable_fn_check (tree fn)
   else if (DECL_DESTRUCTOR_P (fn))
     kind = sfk_destructor;
   else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
-          && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
-          && copy_fn_p (fn))
-    kind = sfk_copy_assignment;
+          && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR)
+    {
+      if (copy_fn_p (fn))
+       kind = sfk_copy_assignment;
+      else if (move_fn_p (fn))
+       kind = sfk_move_assignment;
+    }
 
   if (kind == sfk_none)
     {
@@ -1103,21 +1527,48 @@ tree
 lazily_declare_fn (special_function_kind sfk, tree type)
 {
   tree fn;
-  bool const_p;
-
-  /* Figure out whether or not the argument has a const reference
-     type.  */
-  if (sfk == sfk_copy_constructor)
-    const_p = TYPE_HAS_CONST_COPY_CTOR (type);
-  else if (sfk == sfk_copy_assignment)
-    const_p = TYPE_HAS_CONST_COPY_ASSIGN (type);
-  else
-    /* In this case, CONST_P will be ignored.  */
-    const_p = false;
+  /* Whether or not the argument has a const reference type.  */
+  bool const_p = false;
+
+  switch (sfk)
+    {
+    case sfk_constructor:
+      CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
+      break;
+    case sfk_copy_constructor:
+      const_p = TYPE_HAS_CONST_COPY_CTOR (type);
+      CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
+      break;
+    case sfk_move_constructor:
+      CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
+      break;
+    case sfk_copy_assignment:
+      const_p = TYPE_HAS_CONST_COPY_ASSIGN (type);
+      CLASSTYPE_LAZY_COPY_ASSIGN (type) = 0;
+      break;
+    case sfk_move_assignment:
+      CLASSTYPE_LAZY_MOVE_ASSIGN (type) = 0;
+      break;
+    case sfk_destructor:
+      CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
   /* Declare the function.  */
   fn = implicitly_declare_fn (sfk, type, const_p);
+
+  /* For move variants, rather than declare them as deleted we just
+     don't declare them at all.  */
+  if (DECL_DELETED_FN (fn)
+      && (sfk == sfk_move_constructor
+         || sfk == sfk_move_assignment))
+    return NULL_TREE;
+
   /* A destructor may be virtual.  */
   if (sfk == sfk_destructor
+      || sfk == sfk_move_assignment
       || sfk == sfk_copy_assignment)
     check_for_override (fn, type);
   /* Add it to CLASSTYPE_METHOD_VEC.  */
@@ -1143,22 +1594,10 @@ lazily_declare_fn (special_function_kind sfk, tree type)
       TYPE_METHODS (type) = fn;
     }
   maybe_add_class_template_decl_list (type, fn, /*friend_p=*/0);
-  if (sfk == sfk_copy_assignment)
-    CLASSTYPE_LAZY_COPY_ASSIGN (type) = 0;
-  else
-    {
-      /* Remember that the function has been created.  */
-      if (sfk == sfk_constructor)
-       CLASSTYPE_LAZY_DEFAULT_CTOR (type) = 0;
-      else if (sfk == sfk_copy_constructor)
-       CLASSTYPE_LAZY_COPY_CTOR (type) = 0;
-      else if (sfk == sfk_move_constructor)
-       CLASSTYPE_LAZY_MOVE_CTOR (type) = 0;
-      else if (sfk == sfk_destructor)
-       CLASSTYPE_LAZY_DESTRUCTOR (type) = 0;
-      /* Create appropriate clones.  */
-      clone_function_decl (fn, /*update_method_vec=*/true);
-    }
+  if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
+      || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
+    /* Create appropriate clones.  */
+    clone_function_decl (fn, /*update_method_vec=*/true);
 
   return fn;
 }
index d291c08..9dbefd3 100644 (file)
@@ -1335,7 +1335,7 @@ lookup_conversion_operator (tree class_type, tree type)
 }
 
 /* TYPE is a class type. Return the index of the fields within
-   the method vector with name NAME, or -1 is no such field exists.  */
+   the method vector with name NAME, or -1 if no such field exists.  */
 
 int
 lookup_fnfields_1 (tree type, tree name)
@@ -1361,9 +1361,13 @@ lookup_fnfields_1 (tree type, tree name)
          if (CLASSTYPE_LAZY_MOVE_CTOR (type))
            lazily_declare_fn (sfk_move_constructor, type);
        }
-      else if (name == ansi_assopname(NOP_EXPR)
-              && CLASSTYPE_LAZY_COPY_ASSIGN (type))
-       lazily_declare_fn (sfk_copy_assignment, type);
+      else if (name == ansi_assopname (NOP_EXPR))
+       {
+         if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
+           lazily_declare_fn (sfk_copy_assignment, type);
+         if (CLASSTYPE_LAZY_MOVE_ASSIGN (type))
+           lazily_declare_fn (sfk_move_assignment, type);
+       }
       else if ((name == dtor_identifier
                || name == base_dtor_identifier
                || name == complete_dtor_identifier
@@ -1441,6 +1445,18 @@ lookup_fnfields_1 (tree type, tree name)
   return -1;
 }
 
+/* TYPE is a class type. Return the field within the method vector with
+   name NAME, or NULL_TREE if no such field exists.  */
+
+tree
+lookup_fnfields_slot (tree type, tree name)
+{
+  int ix = lookup_fnfields_1 (type, name);
+  if (ix < 0)
+    return NULL_TREE;
+  return VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
+}
+
 /* Like lookup_fnfields_1, except that the name is extracted from
    FUNCTION, which is a FUNCTION_DECL or a TEMPLATE_DECL.  */
 
@@ -1889,6 +1905,7 @@ check_final_overrider (tree overrider, tree basefn)
        {
          error ("deleted function %q+D", overrider);
          error ("overriding non-deleted function %q+D", basefn);
+         maybe_explain_implicit_delete (overrider);
        }
       else
        {
index adc5e7f..156f278 100644 (file)
@@ -3527,31 +3527,6 @@ finalize_nrv (tree *tp, tree var, tree result)
   htab_delete (data.visited);
 }
 \f
-/* Return the declaration for the function called by CALL_EXPR T,
-   TYPE is the class type of the clause decl.  */
-
-static tree
-omp_clause_info_fndecl (tree t, tree type)
-{
-  tree ret = get_callee_fndecl (t);
-
-  if (ret)
-    return ret;
-
-  gcc_assert (TREE_CODE (t) == CALL_EXPR);
-  t = CALL_EXPR_FN (t);
-  STRIP_NOPS (t);
-  if (TREE_CODE (t) == OBJ_TYPE_REF)
-    {
-      t = cp_fold_obj_type_ref (t, type);
-      if (TREE_CODE (t) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
-       return TREE_OPERAND (t, 0);
-    }
-
-  return NULL_TREE;
-}
-
 /* Create CP_OMP_CLAUSE_INFO for clause C.  Returns true if it is invalid.  */
 
 bool
@@ -3569,80 +3544,27 @@ cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor,
   info = make_tree_vec (3);
   CP_OMP_CLAUSE_INFO (c) = info;
 
-  if (need_default_ctor
-      || (need_copy_ctor && !TYPE_HAS_TRIVIAL_COPY_CTOR (type)))
+  if (need_default_ctor || need_copy_ctor)
     {
-      VEC(tree,gc) *vec;
-
       if (need_default_ctor)
-       vec = NULL;
+       t = get_default_ctor (type);
       else
-       {
-         t = build_int_cst (build_pointer_type (type), 0);
-         t = build1 (INDIRECT_REF, type, t);
-         vec = make_tree_vector_single (t);
-       }
-      t = build_special_member_call (NULL_TREE, complete_ctor_identifier,
-                                    &vec, type, LOOKUP_NORMAL,
-                                    tf_warning_or_error);
+       t = get_copy_ctor (type);
 
-      if (vec != NULL)
-       release_tree_vector (vec);
-
-      if (targetm.cxx.cdtor_returns_this () || errorcount)
-       /* Because constructors and destructors return this,
-          the call will have been cast to "void".  Remove the
-          cast here.  We would like to use STRIP_NOPS, but it
-          wouldn't work here because TYPE_MODE (t) and
-          TYPE_MODE (TREE_OPERAND (t, 0)) are different.
-          They are VOIDmode and Pmode, respectively.  */
-       if (TREE_CODE (t) == NOP_EXPR)
-         t = TREE_OPERAND (t, 0);
-
-      TREE_VEC_ELT (info, 0) = get_callee_fndecl (t);
+      if (t && !trivial_fn_p (t))
+       TREE_VEC_ELT (info, 0) = t;
     }
 
   if ((need_default_ctor || need_copy_ctor)
       && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
-    {
-      t = build_int_cst (build_pointer_type (type), 0);
-      t = build1 (INDIRECT_REF, type, t);
-      t = build_special_member_call (t, complete_dtor_identifier,
-                                    NULL, type, LOOKUP_NORMAL,
-                                    tf_warning_or_error);
+    TREE_VEC_ELT (info, 1) = get_dtor (type);
 
-      if (targetm.cxx.cdtor_returns_this () || errorcount)
-       /* Because constructors and destructors return this,
-          the call will have been cast to "void".  Remove the
-          cast here.  We would like to use STRIP_NOPS, but it
-          wouldn't work here because TYPE_MODE (t) and
-          TYPE_MODE (TREE_OPERAND (t, 0)) are different.
-          They are VOIDmode and Pmode, respectively.  */
-       if (TREE_CODE (t) == NOP_EXPR)
-         t = TREE_OPERAND (t, 0);
-
-      TREE_VEC_ELT (info, 1) = omp_clause_info_fndecl (t, type);
-    }
-
-  if (need_copy_assignment && !TYPE_HAS_TRIVIAL_COPY_ASSIGN (type))
+  if (need_copy_assignment)
     {
-      VEC(tree,gc) *vec;
-
-      t = build_int_cst (build_pointer_type (type), 0);
-      t = build1 (INDIRECT_REF, type, t);
-      vec = make_tree_vector_single (t);
-      t = build_special_member_call (t, ansi_assopname (NOP_EXPR),
-                                    &vec, type, LOOKUP_NORMAL,
-                                    tf_warning_or_error);
-      release_tree_vector (vec);
-
-      /* We'll have called convert_from_reference on the call, which
-        may well have added an indirect_ref.  It's unneeded here,
-        and in the way, so kill it.  */
-      if (TREE_CODE (t) == INDIRECT_REF)
-       t = TREE_OPERAND (t, 0);
+      t = get_copy_assign (type);
 
-      TREE_VEC_ELT (info, 2) = omp_clause_info_fndecl (t, type);
+      if (t && !trivial_fn_p (t))
+       TREE_VEC_ELT (info, 2) = t;
     }
 
   return errorcount != save_errorcount;
@@ -5076,7 +4998,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
       type1 = strip_array_types (type1);
       return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2) 
              || (CLASS_TYPE_P (type1)
-                 && (t = locate_ctor (type1, NULL))
+                 && (t = locate_ctor (type1))
                  && TYPE_NOTHROW_P (TREE_TYPE (t))));
 
     case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
index 7236924..3367a09 100644 (file)
@@ -2847,7 +2847,12 @@ special_function_p (const_tree decl)
   if (DECL_CONSTRUCTOR_P (decl))
     return sfk_constructor;
   if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
-    return sfk_copy_assignment;
+    {
+      if (copy_fn_p (decl))
+       return sfk_copy_assignment;
+      if (move_fn_p (decl))
+       return sfk_move_assignment;
+    }
   if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
     return sfk_destructor;
   if (DECL_COMPLETE_DESTRUCTOR_P (decl))