This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH to implement defaulted/deleted functions


bkoz asked me to implement this stuff for the atomics library. While working on it I realized that it wouldn't actually help; apparently there's an open issue in the library working group about this. But I went ahead and finished it anyway, can't hurt to have another C++0x feature taken care of.

Tested x86_64-pc-linux-gnu, applied to trunk.
2008-07-23  Jason Merrill  <jason@redhat.com>

	* cp-tree.h (struct lang_decl_flags): Add defaulted_p bitfield.
	(DECL_DELETED_FN): New macro.
	(DECL_DEFAULTED_FN): New macro.
	* class.c (user_provided_p): New fn.
	(defaultable_fn_p): New fn.
	(type_has_user_provided_constructor): New fn.
	(type_has_user_provided_default_constructor): New fn.
	(check_methods): A defaulted fn is still trivial.
	(check_bases_and_members): Likewise.
	* decl.c (grok_special_member_properties): Likewise.
	(duplicate_decls): Complain about redeclaring a function as deleted.
	(start_decl): initialized==2 means deleted.
	(cp_finish_decl): Handle deleted/defaulted semantics.
	* decl2.c (grokfield): Likewise.
	(mark_used): Check DECL_DEFAULTED_FN instead of DECL_ARTIFICIAL.
	Complain about using a deleted fn.
	* init.c (build_value_init_1): Use type_has_user_provided_constructor.
	(perform_member_init): Check for a user-provided default constructor
	even if TYPE_NEEDS_CONSTRUCTING.
	(build_new_1): Likewise.
	* call.c (build_over_call): Don't call mark_used twice.
	* method.c (implicitly_declare_fn): Set DECL_DEFAULTED_FN.
	* search.c (check_final_overrider): Check for deleted mismatch.
	* parser.c (cp_parser_init_declarator): Tell start_decl about =delete.
	(cp_parser_pure_specifier): Handle =default and =delete.

	* error.c (maybe_warn_cpp0x): Suggest -std=gnu++0x as well.

Index: cp/init.c
===================================================================
*** cp/init.c	(revision 138106)
--- cp/init.c	(working copy)
*************** build_value_init_1 (tree type, bool have
*** 346,352 ****
  
    if (CLASS_TYPE_P (type))
      {
!       if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor)
  	return build_cplus_new
  	  (type,
  	   build_special_member_call (NULL_TREE, complete_ctor_identifier,
--- 346,352 ----
  
    if (CLASS_TYPE_P (type))
      {
!       if (type_has_user_provided_constructor (type) && !have_ctor)
  	return build_cplus_new
  	  (type,
  	   build_special_member_call (NULL_TREE, complete_ctor_identifier,
*************** perform_member_init (tree member, tree i
*** 516,523 ****
                                              tf_warning_or_error));
  	}
        else
! 	finish_expr_stmt (build_aggr_init (decl, init, 0, 
!                                            tf_warning_or_error));
      }
    else
      {
--- 516,532 ----
                                              tf_warning_or_error));
  	}
        else
! 	{
! 	  if (CP_TYPE_CONST_P (type)
! 	      && init == NULL_TREE
! 	      && !type_has_user_provided_default_constructor (type))
! 	    /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
! 	       vtable; still give this diagnostic.  */
! 	    permerror ("%Juninitialized member %qD with %<const%> type %qT",
! 		       current_function_decl, member, type);
! 	  finish_expr_stmt (build_aggr_init (decl, init, 0, 
! 					     tf_warning_or_error));
! 	}
      }
    else
      {
*************** build_new_1 (tree placement, tree type, 
*** 1883,1889 ****
      return error_mark_node;
  
    is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
!   if (CP_TYPE_CONST_P (elt_type) && !is_initialized)
      {
        if (complain & tf_error)
          error ("uninitialized const in %<new%> of %q#T", elt_type);
--- 1892,1900 ----
      return error_mark_node;
  
    is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
! 
!   if (CP_TYPE_CONST_P (elt_type) && !init
!       && !type_has_user_provided_default_constructor (elt_type))
      {
        if (complain & tf_error)
          error ("uninitialized const in %<new%> of %q#T", elt_type);
Index: cp/class.c
===================================================================
*** cp/class.c	(revision 138106)
--- cp/class.c	(working copy)
*************** check_field_decls (tree t, tree *access_
*** 3045,3051 ****
  
        /* Core issue 80: A nonstatic data member is required to have a
  	 different name from the class iff the class has a
! 	 user-defined constructor.  */
        if (constructor_name_p (DECL_NAME (x), t)
  	  && TYPE_HAS_USER_CONSTRUCTOR (t))
  	permerror ("field %q+#D with same name as class", x);
--- 3045,3051 ----
  
        /* Core issue 80: A nonstatic data member is required to have a
  	 different name from the class iff the class has a
! 	 user-declared constructor.  */
        if (constructor_name_p (DECL_NAME (x), t)
  	  && TYPE_HAS_USER_CONSTRUCTOR (t))
  	permerror ("field %q+#D with same name as class", x);
*************** check_methods (tree t)
*** 3767,3774 ****
  	  if (DECL_PURE_VIRTUAL_P (x))
  	    VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
  	}
!       /* All user-declared destructors are non-trivial.  */
!       if (DECL_DESTRUCTOR_P (x))
  	TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
      }
  }
--- 3767,3774 ----
  	  if (DECL_PURE_VIRTUAL_P (x))
  	    VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x);
  	}
!       /* All user-provided destructors are non-trivial.  */
!       if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x))
  	TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1;
      }
  }
*************** type_has_user_nondefault_constructor (tr
*** 4067,4072 ****
--- 4067,4152 ----
    return false;
  }
  
+ /* Returns true iff FN is a user-provided function, i.e. user-declared
+    and not defaulted at its first declaration.  */
+ 
+ static bool
+ user_provided_p (tree fn)
+ {
+   if (TREE_CODE (fn) == TEMPLATE_DECL)
+     return true;
+   else
+     return (!DECL_ARTIFICIAL (fn)
+ 	    && !(DECL_DEFAULTED_FN (fn)
+ 		 && DECL_INITIALIZED_IN_CLASS_P (fn)));
+ }
+ 
+ /* Returns true iff class T has a user-provided constructor.  */
+ 
+ bool
+ type_has_user_provided_constructor (tree t)
+ {
+   tree fns;
+ 
+   if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+     return false;
+ 
+   /* This can happen in error cases; avoid crashing.  */
+   if (!CLASSTYPE_METHOD_VEC (t))
+     return false;
+ 
+   for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+     if (user_provided_p (OVL_CURRENT (fns)))
+       return true;
+ 
+   return false;
+ }
+ 
+ /* Returns true iff class T has a user-provided default constructor.  */
+ 
+ bool
+ type_has_user_provided_default_constructor (tree t)
+ {
+   tree fns;
+ 
+   if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+     return false;
+ 
+   for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
+     {
+       tree fn = OVL_CURRENT (fns);
+       if (user_provided_p (fn)
+ 	  && (skip_artificial_parms_for (fn, DECL_ARGUMENTS (fn))
+ 	      == NULL_TREE))
+ 	return true;
+     }
+ 
+   return false;
+ }
+ 
+ /* Returns true if FN can be explicitly defaulted.  */
+ 
+ bool
+ defaultable_fn_p (tree fn)
+ {
+   if (DECL_CONSTRUCTOR_P (fn))
+     {
+       if (skip_artificial_parms_for (fn, DECL_ARGUMENTS (fn))
+ 	  == NULL_TREE)
+ 	return true;
+       else if (copy_fn_p (fn) > 0)
+ 	return true;
+       else
+ 	return false;
+     }
+   else if (DECL_DESTRUCTOR_P (fn))
+     return true;
+   else if (DECL_ASSIGNMENT_OPERATOR_P (fn))
+     return copy_fn_p (fn);
+   else
+     return false;
+ }
+ 
  /* Remove all zero-width bit-fields from T.  */
  
  static void
*************** check_bases_and_members (tree t)
*** 4158,4163 ****
--- 4238,4245 ----
       should take a non-const reference argument.  */
    int no_const_asn_ref;
    tree access_decls;
+   bool saved_complex_asn_ref;
+   bool saved_nontrivial_dtor;
  
    /* By default, we use const reference arguments and generate default
       constructors.  */
*************** check_bases_and_members (tree t)
*** 4171,4176 ****
--- 4253,4264 ----
    /* Check all the method declarations.  */
    check_methods (t);
  
+   /* Save the initial values of these flags which only indicate whether
+      or not the class has user-provided functions.  As we analyze the
+      bases and members we can set these flags for other reasons.  */
+   saved_complex_asn_ref = TYPE_HAS_COMPLEX_ASSIGN_REF (t);
+   saved_nontrivial_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
+ 
    /* Check all the data member declarations.  We cannot call
       check_field_decls until we have called check_bases check_methods,
       as check_field_decls depends on TYPE_HAS_NONTRIVIAL_DESTRUCTOR
*************** check_bases_and_members (tree t)
*** 4186,4215 ****
  
    /* Do some bookkeeping that will guide the generation of implicitly
       declared member functions.  */
!   TYPE_HAS_COMPLEX_INIT_REF (t)
!     |= (TYPE_HAS_INIT_REF (t) || TYPE_CONTAINS_VPTR_P (t));
    /* We need to call a constructor for this class if it has a
!      user-declared constructor, or if the default constructor is going
       to initialize the vptr.  (This is not an if-and-only-if;
       TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
       themselves need constructing.)  */
    TYPE_NEEDS_CONSTRUCTING (t)
!     |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
    /* [dcl.init.aggr]
  
!      An aggregate is an array or a class with no user-declared
       constructors ... and no virtual functions.  
  
       Again, other conditions for being an aggregate are checked
       elsewhere.  */
    CLASSTYPE_NON_AGGREGATE (t)
!     |= (TYPE_HAS_USER_CONSTRUCTOR (t) || TYPE_POLYMORPHIC_P (t));
    CLASSTYPE_NON_POD_P (t)
      |= (CLASSTYPE_NON_AGGREGATE (t)
! 	|| TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
! 	|| TYPE_HAS_ASSIGN_REF (t));
!   TYPE_HAS_COMPLEX_ASSIGN_REF (t)
!     |= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
    TYPE_HAS_COMPLEX_DFLT (t)
      |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
  
--- 4274,4300 ----
  
    /* Do some bookkeeping that will guide the generation of implicitly
       declared member functions.  */
!   TYPE_HAS_COMPLEX_INIT_REF (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;
       TYPE_NEEDS_CONSTRUCTING is set elsewhere if bases or members
       themselves need constructing.)  */
    TYPE_NEEDS_CONSTRUCTING (t)
!     |= (type_has_user_provided_constructor (t) || TYPE_CONTAINS_VPTR_P (t));
    /* [dcl.init.aggr]
  
!      An aggregate is an array or a class with no user-provided
       constructors ... and no virtual functions.  
  
       Again, other conditions for being an aggregate are checked
       elsewhere.  */
    CLASSTYPE_NON_AGGREGATE (t)
!     |= (type_has_user_provided_constructor (t) || TYPE_POLYMORPHIC_P (t));
    CLASSTYPE_NON_POD_P (t)
      |= (CLASSTYPE_NON_AGGREGATE (t)
! 	|| saved_nontrivial_dtor || saved_complex_asn_ref);
!   TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_CONTAINS_VPTR_P (t);
    TYPE_HAS_COMPLEX_DFLT (t)
      |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t));
  
Index: cp/decl.c
===================================================================
*** cp/decl.c	(revision 138106)
--- cp/decl.c	(working copy)
*************** duplicate_decls (tree newdecl, tree oldd
*** 1613,1618 ****
--- 1613,1624 ----
  	  warning (OPT_Wredundant_decls, "redundant redeclaration of %qD in same scope", newdecl);
  	  warning (OPT_Wredundant_decls, "previous declaration of %q+D", olddecl);
  	}
+ 
+       if (DECL_DELETED_FN (newdecl))
+ 	{
+ 	  error ("deleted definition of %qD", newdecl);
+ 	  error ("after previous declaration %q+D", olddecl);
+ 	}
      }
  
    /* Deal with C++: must preserve virtual function table size.  */
*************** groktypename (cp_decl_specifier_seq *typ
*** 3931,3943 ****
     grokfield.)  The DECL corresponding to the DECLARATOR is returned.
     If an error occurs, the error_mark_node is returned instead.
     
!    DECLSPECS are the decl-specifiers for the declaration.  INITIALIZED
!    is true if an explicit initializer is present, but false if this is
!    a variable implicitly initialized via a default constructor.
!    ATTRIBUTES and PREFIX_ATTRIBUTES are GNU attributes associated with
!    this declaration.  *PUSHED_SCOPE_P is set to the scope entered in
!    this function, if any; if set, the caller is responsible for
!    calling pop_scope.  */
  
  tree
  start_decl (const cp_declarator *declarator,
--- 3937,3950 ----
     grokfield.)  The DECL corresponding to the DECLARATOR is returned.
     If an error occurs, the error_mark_node is returned instead.
     
!    DECLSPECS are the decl-specifiers for the declaration.  INITIALIZED is 1
!    if an explicit initializer is present, or 2 for an explicitly defaulted
!    function, or 3 for an explicitly deleted function, but 0 if this is a
!    variable implicitly initialized via a default constructor.  ATTRIBUTES
!    and PREFIX_ATTRIBUTES are GNU attributes associated with this
!    declaration.  *PUSHED_SCOPE_P is set to the scope entered in this
!    function, if any; if set, the caller is responsible for calling
!    pop_scope.  */
  
  tree
  start_decl (const cp_declarator *declarator,
*************** start_decl (const cp_declarator *declara
*** 3991,4002 ****
      switch (TREE_CODE (decl))
        {
        case TYPE_DECL:
! 	error ("typedef %qD is initialized (use __typeof__ instead)", decl);
  	return error_mark_node;
  
        case FUNCTION_DECL:
! 	error ("function %q#D is initialized like a variable", decl);
! 	return error_mark_node;
  
        default:
  	break;
--- 3998,4012 ----
      switch (TREE_CODE (decl))
        {
        case TYPE_DECL:
! 	error ("typedef %qD is initialized (use decltype instead)", decl);
  	return error_mark_node;
  
        case FUNCTION_DECL:
! 	if (initialized == 3)
! 	  /* We'll handle the rest of the semantics later, but we need to
! 	     set this now so it's visible to duplicate_decls.  */
! 	  DECL_DELETED_FN (decl) = 1;
! 	break;
  
        default:
  	break;
*************** cp_finish_decl (tree decl, tree init, bo
*** 5686,5695 ****
        else
  	abstract_virtuals_error (decl, type);
  
!       if (TREE_CODE (decl) == FUNCTION_DECL
! 	  || TREE_TYPE (decl) == error_mark_node)
  	/* No initialization required.  */
  	;
        else if (DECL_EXTERNAL (decl)
  	       && ! (DECL_LANG_SPECIFIC (decl)
  		     && DECL_NOT_REALLY_EXTERN (decl)))
--- 5696,5733 ----
        else
  	abstract_virtuals_error (decl, type);
  
!       if (TREE_TYPE (decl) == error_mark_node)
  	/* No initialization required.  */
  	;
+       else if (TREE_CODE (decl) == FUNCTION_DECL)
+ 	{
+ 	  if (init)
+ 	    {
+ 	      if (init == ridpointers[(int)RID_DELETE])
+ 		{
+ 		  /* fixme check this is 1st decl */
+ 		  DECL_DELETED_FN (decl) = 1;
+ 		  DECL_DECLARED_INLINE_P (decl) = 1;
+ 		  DECL_INITIAL (decl) = error_mark_node;
+ 		}
+ 	      else if (init == ridpointers[(int)RID_DEFAULT])
+ 		{
+ 		  if (!defaultable_fn_p (decl))
+ 		    error ("%qD cannot be defaulted", decl);
+ 		  else
+ 		    {
+ 		      /* An out-of-class default definition is defined at
+ 			 the point where it is explicitly defaulted.  */
+ 		      DECL_DEFAULTED_FN (decl) = 1;
+ 		      if (DECL_INITIAL (decl) == error_mark_node)
+ 			synthesize_method (decl);
+ 		    }
+ 		}
+ 	      else
+ 		error ("function %q#D is initialized like a variable", decl);
+ 	    }
+ 	  /* else no initialization required.  */
+ 	}
        else if (DECL_EXTERNAL (decl)
  	       && ! (DECL_LANG_SPECIFIC (decl)
  		     && DECL_NOT_REALLY_EXTERN (decl)))
*************** check_var_type (tree identifier, tree ty
*** 7361,7367 ****
        Don't make a DECL node; just return the ..._TYPE node.
       FIELD for a struct or union field; make a FIELD_DECL.
       BITFIELD for a field with specified width.
!    INITIALIZED is 1 if the decl has an initializer.
  
     ATTRLIST is a pointer to the list of attributes, which may be NULL
     if there are none; *ATTRLIST may be modified if attributes from inside
--- 7399,7405 ----
        Don't make a DECL node; just return the ..._TYPE node.
       FIELD for a struct or union field; make a FIELD_DECL.
       BITFIELD for a field with specified width.
!    INITIALIZED is as for start_decl.
  
     ATTRLIST is a pointer to the list of attributes, which may be NULL
     if there are none; *ATTRLIST may be modified if attributes from inside
*************** grokdeclarator (const cp_declarator *dec
*** 7459,7464 ****
--- 7497,7505 ----
    else if (decl_context == BITFIELD)
      bitfield = 1, decl_context = FIELD;
  
+   if (initialized > 1)
+     funcdef_flag = true;
+ 
    /* Look inside a declarator for the name being declared
       and get it as a string, for an error message.  */
    for (id_declarator = declarator;
*************** grok_special_member_properties (tree dec
*** 9670,9675 ****
--- 9711,9718 ----
  	     are no other parameters or else all other parameters have
  	     default arguments.  */
  	  TYPE_HAS_INIT_REF (class_type) = 1;
+ 	  if (!DECL_DEFAULTED_FN (decl))
+ 	    TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1;
  	  if (ctor > 1)
  	    TYPE_HAS_CONST_INIT_REF (class_type) = 1;
  	}
*************** grok_special_member_properties (tree dec
*** 9691,9696 ****
--- 9734,9741 ----
        if (assop)
  	{
  	  TYPE_HAS_ASSIGN_REF (class_type) = 1;
+ 	  if (!DECL_DEFAULTED_FN (decl))
+ 	    TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1;
  	  if (assop != 1)
  	    TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1;
  	}
Index: cp/call.c
===================================================================
*** cp/call.c	(revision 138106)
--- cp/call.c	(working copy)
*************** build_over_call (struct z_candidate *can
*** 5090,5095 ****
--- 5090,5096 ----
    int is_method = 0;
    int nargs;
    tree *argarray;
+   bool already_used = false;
  
    /* In a template, there is no need to perform all of the work that
       is normally done.  We are only interested in the type of the call
*************** build_over_call (struct z_candidate *can
*** 5310,5316 ****
        /* [class.copy]: the copy constructor is implicitly defined even if
  	 the implementation elided its use.  */
        if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
! 	mark_used (fn);
  
        /* If we're creating a temp and we already have one, don't create a
  	 new one.  If we're not creating a temp but we get one, use
--- 5311,5320 ----
        /* [class.copy]: the copy constructor is implicitly defined even if
  	 the implementation elided its use.  */
        if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
! 	{
! 	  mark_used (fn);
! 	  already_used = true;
! 	}
  
        /* If we're creating a temp and we already have one, don't create a
  	 new one.  If we're not creating a temp but we get one, use
*************** build_over_call (struct z_candidate *can
*** 5370,5376 ****
        return val;
      }
  
!   mark_used (fn);
  
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
--- 5374,5381 ----
        return val;
      }
  
!   if (!already_used)
!     mark_used (fn);
  
    if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
      {
Index: cp/method.c
===================================================================
*** cp/method.c	(revision 138106)
--- cp/method.c	(working copy)
*************** implicitly_declare_fn (special_function_
*** 1108,1113 ****
--- 1108,1114 ----
    rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
    DECL_IN_AGGR_P (fn) = 1;
    DECL_ARTIFICIAL (fn) = 1;
+   DECL_DEFAULTED_FN (fn) = 1;
    DECL_NOT_REALLY_EXTERN (fn) = 1;
    DECL_DECLARED_INLINE_P (fn) = 1;
    DECL_INLINE (fn) = 1;
Index: cp/error.c
===================================================================
*** cp/error.c	(revision 138106)
--- cp/error.c	(working copy)
*************** maybe_warn_cpp0x (const char* str)
*** 2685,2691 ****
      /* We really want to suppress this warning in system headers,
         because libstdc++ uses variadic templates even when we aren't
         in C++0x mode. */
!     pedwarn (0, "%s only available with -std=c++0x", str);
  }
  
  /* Warn about the use of variadic templates when appropriate.  */
--- 2685,2691 ----
      /* We really want to suppress this warning in system headers,
         because libstdc++ uses variadic templates even when we aren't
         in C++0x mode. */
!     pedwarn (0, "%s only available with -std=c++0x or -std=gnu++0x", str);
  }
  
  /* Warn about the use of variadic templates when appropriate.  */
Index: cp/mangle.c
===================================================================
*** cp/mangle.c	(revision 138106)
--- cp/mangle.c	(working copy)
*************** write_unqualified_name (const tree decl)
*** 1056,1062 ****
    else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
      write_special_name_destructor (decl);
    else if (DECL_NAME (decl) == NULL_TREE)
!     write_source_name (DECL_ASSEMBLER_NAME (decl));
    else if (DECL_CONV_FN_P (decl))
      {
        /* Conversion operator. Handle it right here.
--- 1056,1065 ----
    else if (DECL_LANG_SPECIFIC (decl) != NULL && DECL_DESTRUCTOR_P (decl))
      write_special_name_destructor (decl);
    else if (DECL_NAME (decl) == NULL_TREE)
!     {
!       gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
!       write_source_name (DECL_ASSEMBLER_NAME (decl));
!     }
    else if (DECL_CONV_FN_P (decl))
      {
        /* Conversion operator. Handle it right here.
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 138106)
--- cp/cp-tree.h	(working copy)
*************** struct lang_decl_flags GTY(())
*** 1609,1615 ****
    unsigned repo_available_p : 1;
    unsigned hidden_friend_p : 1;
    unsigned threadprivate_p : 1;
!   /* One unused bit.  */
  
    union lang_decl_u {
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
--- 1609,1615 ----
    unsigned repo_available_p : 1;
    unsigned hidden_friend_p : 1;
    unsigned threadprivate_p : 1;
!   unsigned defaulted_p : 1;
  
    union lang_decl_u {
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
*************** more_aggr_init_expr_args_p (const aggr_i
*** 2626,2631 ****
--- 2626,2639 ----
  #define CP_DECL_THREADPRIVATE_P(DECL) \
    (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->decl_flags.threadprivate_p)
  
+ /* Nonzero if DECL was declared with '= delete'.  */
+ #define DECL_DELETED_FN(DECL) \
+   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.threadprivate_p)
+ 
+ /* Nonzero if DECL was declared with '= default'.  */
+ #define DECL_DEFAULTED_FN(DECL) \
+   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->decl_flags.defaulted_p)
+ 
  /* Record whether a typedef for type `int' was actually `signed int'.  */
  #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP)
  
*************** extern void check_for_override			(tree, 
*** 4171,4176 ****
--- 4179,4187 ----
  extern void push_class_stack			(void);
  extern void pop_class_stack			(void);
  extern bool type_has_user_nondefault_constructor (tree);
+ extern bool type_has_user_provided_constructor  (tree);
+ extern bool type_has_user_provided_default_constructor (tree);
+ extern bool defaultable_fn_p			(tree);
  
  /* in cvt.c */
  extern tree convert_to_reference		(tree, tree, int, int, tree);
Index: cp/search.c
===================================================================
*** cp/search.c	(revision 138106)
--- cp/search.c	(working copy)
*************** check_final_overrider (tree overrider, t
*** 1912,1917 ****
--- 1912,1931 ----
        return 0;
      }
  
+   if (DECL_DELETED_FN (basefn) != DECL_DELETED_FN (overrider))
+     {
+       if (DECL_DELETED_FN (overrider))
+ 	{
+ 	  error ("deleted function %q+D", overrider);
+ 	  error ("overriding non-deleted function %q+D", basefn);
+ 	}
+       else
+ 	{
+ 	  error ("non-deleted function %q+D", overrider);
+ 	  error ("overriding deleted function %q+D", basefn);
+ 	}
+       return 0;
+     }
    return 1;
  }
  
Index: cp/decl2.c
===================================================================
*** cp/decl2.c	(revision 138106)
--- cp/decl2.c	(working copy)
*************** grokfield (const cp_declarator *declarat
*** 821,827 ****
  	{
  	  /* Initializers for functions are rejected early in the parser.
  	     If we get here, it must be a pure specifier for a method.  */
! 	  if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
  	    {
  	      gcc_assert (error_operand_p (init) || integer_zerop (init));
  	      DECL_PURE_VIRTUAL_P (value) = 1;
--- 821,845 ----
  	{
  	  /* Initializers for functions are rejected early in the parser.
  	     If we get here, it must be a pure specifier for a method.  */
! 	  if (init == ridpointers[(int)RID_DELETE])
! 	    {
! 	      DECL_DELETED_FN (value) = 1;
! 	      DECL_DECLARED_INLINE_P (value) = 1;
! 	      DECL_INITIAL (value) = error_mark_node;
! 	    }
! 	  else if (init == ridpointers[(int)RID_DEFAULT])
! 	    {
! 	      if (!defaultable_fn_p (value))
! 		error ("%qD cannot be defaulted", value);
! 	      else
! 		{
! 		  DECL_DEFAULTED_FN (value) = 1;
! 		  DECL_INITIALIZED_IN_CLASS_P (value) = 1;
! 		  DECL_DECLARED_INLINE_P (value) = 1;
! 		  DECL_INLINE (value) = 1;
! 		}
! 	    }
! 	  else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
  	    {
  	      gcc_assert (error_operand_p (init) || integer_zerop (init));
  	      DECL_PURE_VIRTUAL_P (value) = 1;
*************** mark_used (tree decl)
*** 3739,3745 ****
    /* Is it a synthesized method that needs to be synthesized?  */
    if (TREE_CODE (decl) == FUNCTION_DECL
        && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
!       && DECL_ARTIFICIAL (decl)
        && !DECL_THUNK_P (decl)
        && ! DECL_INITIAL (decl)
        /* Kludge: don't synthesize for default args.  Unfortunately this
--- 3757,3763 ----
    /* Is it a synthesized method that needs to be synthesized?  */
    if (TREE_CODE (decl) == FUNCTION_DECL
        && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
!       && DECL_DEFAULTED_FN (decl)
        && !DECL_THUNK_P (decl)
        && ! DECL_INITIAL (decl)
        /* Kludge: don't synthesize for default args.  Unfortunately this
*************** mark_used (tree decl)
*** 3752,3757 ****
--- 3770,3781 ----
        /* If we've already synthesized the method we don't need to
  	 do the instantiation test below.  */
      }
+   else if (TREE_CODE (decl) == FUNCTION_DECL
+ 	   && DECL_DELETED_FN (decl))
+     {
+       error ("deleted function %q+D", decl);
+       error ("used here");
+     }
    else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)
  	   && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
  	   && (!DECL_EXPLICIT_INSTANTIATION (decl)
Index: cp/parser.c
===================================================================
*** cp/parser.c	(revision 138106)
--- cp/parser.c	(working copy)
*************** cp_parser_init_declarator (cp_parser* pa
*** 12378,12384 ****
    tree initializer;
    tree decl = NULL_TREE;
    tree scope;
!   bool is_initialized;
    /* Only valid if IS_INITIALIZED is true.  In that case, CPP_EQ if
       initialized with "= ..", CPP_OPEN_PAREN if initialized with
       "(...)".  */
--- 12378,12384 ----
    tree initializer;
    tree decl = NULL_TREE;
    tree scope;
!   int is_initialized;
    /* Only valid if IS_INITIALIZED is true.  In that case, CPP_EQ if
       initialized with "= ..", CPP_OPEN_PAREN if initialized with
       "(...)".  */
*************** cp_parser_init_declarator (cp_parser* pa
*** 12514,12521 ****
        || token->type == CPP_OPEN_PAREN
        || token->type == CPP_OPEN_BRACE)
      {
!       is_initialized = true;
        initialization_kind = token->type;
      }
    else
      {
--- 12514,12531 ----
        || token->type == CPP_OPEN_PAREN
        || token->type == CPP_OPEN_BRACE)
      {
!       is_initialized = 1;
        initialization_kind = token->type;
+ 
+       if (token->type == CPP_EQ
+ 	  && function_declarator_p (declarator))
+ 	{
+ 	  cp_token *t2 = cp_lexer_peek_nth_token (parser->lexer, 2);
+ 	  if (t2->keyword == RID_DEFAULT)
+ 	    is_initialized = 2;
+ 	  else if (t2->keyword == RID_DELETE)
+ 	    is_initialized = 3;
+ 	}
      }
    else
      {
*************** cp_parser_init_declarator (cp_parser* pa
*** 12527,12533 ****
  	  cp_parser_error (parser, "expected initializer");
  	  return error_mark_node;
  	}
!       is_initialized = false;
        initialization_kind = CPP_EOF;
      }
  
--- 12537,12543 ----
  	  cp_parser_error (parser, "expected initializer");
  	  return error_mark_node;
  	}
!       is_initialized = 0;
        initialization_kind = CPP_EOF;
      }
  
*************** cp_parser_pure_specifier (cp_parser* par
*** 15681,15686 ****
--- 15691,15705 ----
      return error_mark_node;
    /* Look for the `0' token.  */
    token = cp_lexer_consume_token (parser->lexer);
+ 
+   /* Accept = default or = delete in c++0x mode.  */
+   if (token->keyword == RID_DEFAULT
+       || token->keyword == RID_DELETE)
+     {
+       maybe_warn_cpp0x ("defaulted and deleted functions");
+       return token->u.value;
+     }
+ 
    /* c_lex_with_flags marks a single digit '0' with PURE_ZERO.  */
    if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
      {
Index: testsuite/g++.old-deja/g++.pt/error2.C
===================================================================
*** testsuite/g++.old-deja/g++.pt/error2.C	(revision 138106)
--- testsuite/g++.old-deja/g++.pt/error2.C	(working copy)
***************
*** 2,8 ****
  // Origin: Carl Nygard <cnygard@bellatlantic.net>
  
  template <class RT>
! class Test { // { dg-error "" } in instantiation
  public:
    Test(const RT& c = RT()) {} // { dg-error "" } reference to void
  };
--- 2,8 ----
  // Origin: Carl Nygard <cnygard@bellatlantic.net>
  
  template <class RT>
! class Test {
  public:
    Test(const RT& c = RT()) {} // { dg-error "" } reference to void
  };
Index: testsuite/g++.dg/parse/crash27.C
===================================================================
*** testsuite/g++.dg/parse/crash27.C	(revision 138106)
--- testsuite/g++.dg/parse/crash27.C	(working copy)
***************
*** 1,5 ****
  // Bug: 23225
  
  void Dispatcher()
! 	 (__builtin_offsetof (ArgsType, largeMsgLen))
! 	/* { dg-error "function " "function" { target *-*-* } 4 } */
--- 1,4 ----
  // Bug: 23225
  
  void Dispatcher()
! 	 (__builtin_offsetof (ArgsType, largeMsgLen)) // { dg-error "initialize|end of input" }
Index: testsuite/g++.dg/parse/error15.C
===================================================================
*** testsuite/g++.dg/parse/error15.C	(revision 138106)
--- testsuite/g++.dg/parse/error15.C	(working copy)
*************** struct C
*** 35,38 ****
    typename N::A f7;   // { dg-error "15: error: invalid use of template-name 'N::A' without an argument list" }
  };
  
! // { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { xfail *-*-* } 17 }
--- 35,38 ----
    typename N::A f7;   // { dg-error "15: error: invalid use of template-name 'N::A' without an argument list" }
  };
  
! // { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { target *-*-* } 17 }
Index: testsuite/g++.dg/cpp0x/defaulted1.C
===================================================================
*** testsuite/g++.dg/cpp0x/defaulted1.C	(revision 0)
--- testsuite/g++.dg/cpp0x/defaulted1.C	(revision 0)
***************
*** 0 ****
--- 1,43 ----
+ // Positive test for defaulted/deleted fns
+ // { dg-do run }
+ // { dg-options "-std=c++0x" }
+ 
+ struct A
+ {
+   int i;
+   A() = default;
+   A(const A&) = delete;
+   A& operator=(const A&) = default;
+   ~A();
+ };
+ 
+ A::~A() = default;
+ 
+ void f() = delete;
+ 
+ struct B
+ {
+   int i;
+   B() = default;
+ };
+ 
+ int main()
+ {
+   A a1, a2;
+   B b = {1};
+   a1 = a2;
+ }
+ 
+ // fns defaulted in class defn are trivial
+ struct C
+ {
+   C() = default;
+   C(const C&) = default;
+   C& operator=(const C&) = default;
+   ~C() = default;
+ };
+ 
+ union U
+ {
+   C c;
+ };
Index: testsuite/g++.dg/cpp0x/defaulted2.C
===================================================================
*** testsuite/g++.dg/cpp0x/defaulted2.C	(revision 0)
--- testsuite/g++.dg/cpp0x/defaulted2.C	(revision 0)
***************
*** 0 ****
--- 1,66 ----
+ // Negative test for defaulted/deleted fns.
+ // { dg-options "-std=c++0x" }
+ 
+ void f();			// { dg-error "previous" }
+ void f() = delete;		// { dg-error "deleted" }
+ 
+ struct A
+ {
+   A() { }			// { dg-error "previous" }
+   void f() = default;		// { dg-error "default" }
+ };
+ 
+ A::A() = default;		// { dg-error "redefinition" }
+ 
+ void g() {}			// { dg-error "previous" }
+ void g() = delete;		// { dg-error "redefinition" }
+ 
+ struct B
+ {
+   B() = default;
+ };
+ 
+ const B b;			// { dg-error "uninitialized const" }
+ 
+ struct C
+ {
+   virtual void f() = delete;	// { dg-error "overriding deleted" }
+ };
+ 
+ struct D: public C
+ {
+   virtual void f();		// { dg-error "non-deleted function" }
+ };
+ 
+ struct E
+ {
+   const B b;
+   E() { }			// { dg-error "uninitialized" }
+ };
+ 
+ struct F
+ {
+   F() = default;
+   F(const F&) = delete;		// { dg-error "deleted" }
+ };
+ 
+ struct G
+ {
+   G();
+ };
+ 
+ // ctor defaulted after class defn is not trivial
+ G::G() = default;
+ 
+ union U
+ {
+   G g;				// { dg-error "constructor" }
+ };
+ 
+ int main()
+ {
+   F f;
+   F f2(f);			// { dg-error "used" }
+   B* b = new const B;		// { dg-error "uninitialized const" }
+ }
+ 
Index: testsuite/g++.dg/template/crash60.C
===================================================================
*** testsuite/g++.dg/template/crash60.C	(revision 138106)
--- testsuite/g++.dg/template/crash60.C	(working copy)
*************** struct A
*** 5,9 ****
      template<int> void foo(X);  // { dg-error "declared" }
  };
  
! template<int> void f()(0);      // { dg-error "initialized" }
   
--- 5,9 ----
      template<int> void foo(X);  // { dg-error "declared" }
  };
  
! template<int> void f()(0);      // { dg-error "initialize" }
   
Index: testsuite/g++.dg/template/crash7.C
===================================================================
*** testsuite/g++.dg/template/crash7.C	(revision 138106)
--- testsuite/g++.dg/template/crash7.C	(working copy)
***************
*** 6,13 ****
  // nested type.
  
  template <typename> struct A
! {					// { dg-error "candidates" }
      template <typename> A(typename A::X) {} // { dg-error "no type" }
  };
  
! A<void> a;	// { dg-error "instantiated|no match" }
--- 6,15 ----
  // nested type.
  
  template <typename> struct A
! {					// { not-dg-error "candidates" }
      template <typename> A(typename A::X) {} // { dg-error "no type" }
  };
  
! A<void> a;	// { not-dg-error "instantiated|no match" }
! // We currently don't give the "no match" error because we don't add the
! // invalid constructor template to TYPE_METHODS.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]