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]

Re: [C++ PATCH] Fix 87


Mark Mitchell wrote:
> <nathan@codesourcery.com> wrote:
> 
> > Hi,
> > this fixes bug 87 where a templated operator= was mistaken for a
> > trivial copy assignment operator, leading to incorrect code generation.
Well, on more digging, it transpires that wasn't the best fix. I took
Jason's comment about putting it into copy_args_p (which I've renamed
copy_fn_p), and then found some more bugs.

grokdeclarator is responsible for registering the special properties
of ctors and assignment ops, but at that point template information has
not been attached, so the wrong thing happens with template functions.
I fixed this by removing the memoizing behaviour from grok_ctor_properties
and grok_operator_properties.  I put all that behaviour into a new
function grok_special_member_properties, which I call in start_function,
grokfield and instantiate_class_template appropriately. (These functions
already call grok_ctor_properties etc, at the right point, but the damage
has already been done by the earlier call in grokdeclarator.)

booted & tested on i686-pc-linux-gnu, ok?

nathan
-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2001-12-04  Nathan Sidwell  <nathan@codesourcery.com>

	PR g++/87
	* cp-tree.h (DECL_COPY_CONSTRUCTOR_P): Use copy_fn_p.
	(copy_args_p): Rename to ...
	(copy_fn_p): ... here.
	(grok_special_member_properties): New function.
	(grok_op_properties): Lose VIRTUALP parameter.
	(copy_assignment_arg_p): Remove.
	* call.c (build_over_call): Use copy_fn_p.
	* decl.c (grokfndecl): Reformat. Adjust call to
	grok_op_properties.
	(copy_args_p): Rename to ...
	(copy_fn_p): ... here. Reject template functions. Check for pass
	by value.
	(grok_special_member_properties): Remember special functions.
	(grok_ctor_properties): Don't remember them here, just check.
	(grok_op_properties): Likewise.
	(start_method): Call grok_special_member_properties.
	* decl2.c (grokfield): Likewise.
	(copy_assignment_arg_p): Remove.
	(grok_function_init): Don't remember abstract assignment here.
	* pt.c (instantiate_class_template): Call
	grok_special_member_properties.
	(tsubst_decl): Adjust grok_op_properties call.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.293
diff -c -3 -p -r1.293 call.c
*** call.c	2001/12/02 00:04:34	1.293
--- call.c	2001/12/04 14:19:10
*************** build_over_call (cand, args, flags)
*** 4280,4286 ****
  	}
      }
    else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
! 	   && copy_args_p (fn)
  	   && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
      {
        tree to = stabilize_reference
--- 4280,4286 ----
  	}
      }
    else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
! 	   && copy_fn_p (fn)
  	   && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
      {
        tree to = stabilize_reference
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.659
diff -c -3 -p -r1.659 cp-tree.h
*** cp-tree.h	2001/11/30 03:14:56	1.659
--- cp-tree.h	2001/12/04 14:19:13
*************** struct lang_decl
*** 1841,1847 ****
  
  /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor.  */
  #define DECL_COPY_CONSTRUCTOR_P(NODE) \
!   (DECL_CONSTRUCTOR_P (NODE) && copy_args_p (NODE))
  
  /* Nonzero if NODE is a destructor.  */
  #define DECL_DESTRUCTOR_P(NODE)				\
--- 1841,1847 ----
  
  /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor.  */
  #define DECL_COPY_CONSTRUCTOR_P(NODE) \
!   (DECL_CONSTRUCTOR_P (NODE) && copy_fn_p (NODE) > 0)
  
  /* Nonzero if NODE is a destructor.  */
  #define DECL_DESTRUCTOR_P(NODE)				\
*************** extern int complete_array_type			PARAMS 
*** 3684,3692 ****
  extern tree build_ptrmemfunc_type		PARAMS ((tree));
  /* the grokdeclarator prototype is in decl.h */
  extern int parmlist_is_exprlist			PARAMS ((tree));
! extern int copy_args_p				PARAMS ((tree));
  extern int grok_ctor_properties			PARAMS ((tree, tree));
! extern void grok_op_properties			PARAMS ((tree, int, int));
  extern tree xref_tag				PARAMS ((tree, tree, int));
  extern tree xref_tag_from_type			PARAMS ((tree, tree, int));
  extern void xref_basetypes			PARAMS ((tree, tree, tree, tree));
--- 3684,3693 ----
  extern tree build_ptrmemfunc_type		PARAMS ((tree));
  /* the grokdeclarator prototype is in decl.h */
  extern int parmlist_is_exprlist			PARAMS ((tree));
! extern int copy_fn_p				PARAMS ((tree));
! extern void grok_special_member_properties	PARAMS ((tree));
  extern int grok_ctor_properties			PARAMS ((tree, tree));
! extern void grok_op_properties			PARAMS ((tree, int));
  extern tree xref_tag				PARAMS ((tree, tree, int));
  extern tree xref_tag_from_type			PARAMS ((tree, tree, int));
  extern void xref_basetypes			PARAMS ((tree, tree, tree, tree));
*************** extern tree grokfield				PARAMS ((tree, 
*** 3751,3757 ****
  extern tree grokbitfield			PARAMS ((tree, tree, tree));
  extern tree groktypefield			PARAMS ((tree, tree));
  extern tree grokoptypename			PARAMS ((tree, tree));
- extern int copy_assignment_arg_p		PARAMS ((tree, int));
  extern void cplus_decl_attributes		PARAMS ((tree *, tree, int));
  extern tree constructor_name_full		PARAMS ((tree));
  extern tree constructor_name			PARAMS ((tree));
--- 3752,3757 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.832
diff -c -3 -p -r1.832 decl.c
*** decl.c	2001/12/03 23:15:09	1.832
--- decl.c	2001/12/04 14:19:16
*************** grokfndecl (ctype, type, declarator, ori
*** 8804,8812 ****
    tree t;
  
    if (raises)
!     {
!       type = build_exception_variant (type, raises);
!     }
  
    decl = build_lang_decl (FUNCTION_DECL, declarator, type);
    /* Propagate volatile out from type to decl. */
--- 8804,8810 ----
    tree t;
  
    if (raises)
!     type = build_exception_variant (type, raises);
  
    decl = build_lang_decl (FUNCTION_DECL, declarator, type);
    /* Propagate volatile out from type to decl. */
*************** grokfndecl (ctype, type, declarator, ori
*** 8917,8924 ****
      }
  
    if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
!     grok_op_properties (decl, virtualp, check < 0);
! 
    if (ctype && decl_function_context (decl))
      DECL_NO_STATIC_CHAIN (decl) = 1;
  
--- 8915,8922 ----
      }
  
    if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
!     grok_op_properties (decl, friendp);
! 
    if (ctype && decl_function_context (decl))
      DECL_NO_STATIC_CHAIN (decl) = 1;
  
*************** grokparms (first_parm)
*** 12068,12157 ****
  }
  
  
! /* D is a constructor or overloaded `operator='.  Returns non-zero if
!    D's arguments allow it to be a copy constructor, or copy assignment
!    operator.  */
  
  int
! copy_args_p (d)
       tree d;
  {
!   tree t;
! 
    if (!DECL_FUNCTION_MEMBER_P (d))
      return 0;
  
!   t = FUNCTION_FIRST_USER_PARMTYPE (d);
!   if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
!       && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
! 	  == DECL_CONTEXT (d))
!       && (TREE_CHAIN (t) == NULL_TREE
! 	  || TREE_CHAIN (t) == void_list_node
! 	  || TREE_PURPOSE (TREE_CHAIN (t))))
!     return 1;
!   return 0;
  }
  
! /* These memoizing functions keep track of special properties which
!    a class may have.  `grok_ctor_properties' notices whether a class
!    has a constructor of the form X(X&), and also complains
!    if the class has a constructor of the form X(X).
!    `grok_op_properties' takes notice of the various forms of
!    operator= which are defined, as well as what sorts of type conversion
!    may apply.  Both functions take a FUNCTION_DECL as an argument.  */
  
  int
  grok_ctor_properties (ctype, decl)
       tree ctype, decl;
  {
!   tree parmtypes = FUNCTION_FIRST_USER_PARMTYPE (decl);
!   tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
! 
!   /* [class.copy]
  
!      A non-template constructor for class X is a copy constructor if
!      its first parameter is of type X&, const X&, volatile X& or const
!      volatile X&, and either there are no other parameters or else all
!      other parameters have default arguments.  */
!   if (TREE_CODE (parmtype) == REFERENCE_TYPE
!       && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype
!       && sufficient_parms_p (TREE_CHAIN (parmtypes))
!       && !(DECL_TEMPLATE_INSTANTIATION (decl)
! 	   && is_member_template (DECL_TI_TEMPLATE (decl))))
!     {
!       TYPE_HAS_INIT_REF (ctype) = 1;
!       if (CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
! 	TYPE_HAS_CONST_INIT_REF (ctype) = 1;
!     }
!   /* [class.copy]
! 
!      A declaration of a constructor for a class X is ill-formed if its
!      first parameter is of type (optionally cv-qualified) X and either
!      there are no other parameters or else all other parameters have
!      default arguments.
! 
!      We *don't* complain about member template instantiations that
!      have this form, though; they can occur as we try to decide what
!      constructor to use during overload resolution.  Since overload
!      resolution will never prefer such a constructor to the
!      non-template copy constructor (which is either explicitly or
!      implicitly defined), there's no need to worry about their
!      existence.  Theoretically, they should never even be
!      instantiated, but that's hard to forestall.  */
!   else if (TYPE_MAIN_VARIANT (parmtype) == ctype
! 	   && sufficient_parms_p (TREE_CHAIN (parmtypes))
! 	   && !(DECL_TEMPLATE_INSTANTIATION (decl)
! 		&& is_member_template (DECL_TI_TEMPLATE (decl))))
      {
        cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
  		ctype, ctype);
        SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
        return 0;
      }
!   else if (TREE_CODE (parmtype) == VOID_TYPE
! 	   || TREE_PURPOSE (parmtypes) != NULL_TREE)
!     TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
! 
    return 1;
  }
  
--- 12066,12202 ----
  }
  
  
! /* D is a constructor or overloaded `operator='.
!    Returns 0 if it is not a copy ctor or copy assignment operator.
!    Return 1 if it is a non-constant copy ctor or copy assignment
!    operator.
!    Return 2 if it is a constant copy ctor or copy assignment
!    operator.
!    Return -1 if it is a by-value argument.  */
  
  int
! copy_fn_p (d)
       tree d;
  {
!   tree args;
!   tree arg_type;
!   int result = 1;
!   
    if (!DECL_FUNCTION_MEMBER_P (d))
      return 0;
  
!   if (DECL_TEMPLATE_INFO (d) && is_member_template (DECL_TI_TEMPLATE (d)))
!     return 0;
!     
!   args = FUNCTION_FIRST_USER_PARMTYPE (d);
!   if (!args)
!     return 0;
! 
!   arg_type = TREE_VALUE (args);
! 
!   if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d))
!     {
!       /* Pass by value copy assignment operator.  */
!       result = -1;
!     }
!   else if (TREE_CODE (arg_type) == REFERENCE_TYPE
! 	   && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
!     {
!       if (CP_TYPE_CONST_P (TREE_TYPE (arg_type)))
! 	result = 2;
!     }
!   else
!     return 0;
!   
!   args = TREE_CHAIN (args);
! 
!   if (args && args != void_list_node && !TREE_PURPOSE (args))
!     /* There are more non-optional args.  */
!     return 0;
! 
!   return result;
! }
! 
! /* Remember any special properties of member function DECL.  */
! 
! void grok_special_member_properties (decl)
!      tree decl;
! {
!   if (!DECL_NONSTATIC_MEMBER_FUNCTION_P(decl))
!     ; /* Not special.  */
!   else if (DECL_CONSTRUCTOR_P (decl))
!     {
!       int ctor = copy_fn_p (decl);
!       
!       if (ctor > 0)
! 	{
! 	  /* [class.copy]
! 	      
!      	     A non-template constructor for class X is a copy
!      	     constructor if its first parameter is of type X&, const
!      	     X&, volatile X& or const volatile X&, and either there
!      	     are no other parameters or else all other parameters have
!      	     default arguments.  */
! 	  TYPE_HAS_INIT_REF (DECL_CONTEXT (decl)) = 1;
! 	  if (ctor > 1)
! 	    TYPE_HAS_CONST_INIT_REF (DECL_CONTEXT (decl)) = 1;
! 	}
!       else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl)))
! 	TYPE_HAS_DEFAULT_CONSTRUCTOR (DECL_CONTEXT (decl)) = 1;
!     }
!   else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
!     {
!       /* [class.copy]
! 	  
!      	 A non-template assignment operator for class X is a copy
!      	 assignment operator if its parameter is of type X, X&, const
!      	 X&, volatile X& or const volatile X&.  */
!       
!       int assop = copy_fn_p (decl);
!       
!       if (assop)
! 	{
! 	  TYPE_HAS_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
! 	  if (assop != 1)
! 	    TYPE_HAS_CONST_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
! 	  if (DECL_PURE_VIRTUAL_P (decl))
! 	    TYPE_HAS_ABSTRACT_ASSIGN_REF (DECL_CONTEXT (decl)) = 1;
! 	}
!     }
  }
  
! /* Check a constructor DECL has the correct form.  Complains
!    if the class has a constructor of the form X(X).  */
  
  int
  grok_ctor_properties (ctype, decl)
       tree ctype, decl;
  {
!   int ctor_parm = copy_fn_p (decl);
  
!   if (ctor_parm < 0)
      {
+       /* [class.copy]
+ 	  
+      	 A declaration of a constructor for a class X is ill-formed if
+      	 its first parameter is of type (optionally cv-qualified) X
+      	 and either there are no other parameters or else all other
+      	 parameters have default arguments.
+ 	  
+      	 We *don't* complain about member template instantiations that
+      	 have this form, though; they can occur as we try to decide
+      	 what constructor to use during overload resolution.  Since
+      	 overload resolution will never prefer such a constructor to
+      	 the non-template copy constructor (which is either explicitly
+      	 or implicitly defined), there's no need to worry about their
+      	 existence.  Theoretically, they should never even be
+      	 instantiated, but that's hard to forestall.  */
        cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
  		ctype, ctype);
        SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
        return 0;
      }
!   
    return 1;
  }
  
*************** unary_op_p (code)
*** 12184,12192 ****
  /* Do a little sanity-checking on how they declared their operator.  */
  
  void
! grok_op_properties (decl, virtualp, friendp)
       tree decl;
!      int virtualp, friendp;
  {
    tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
    tree argtype;
--- 12229,12237 ----
  /* Do a little sanity-checking on how they declared their operator.  */
  
  void
! grok_op_properties (decl, friendp)
       tree decl;
!      int friendp;
  {
    tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
    tree argtype;
*************** grok_op_properties (decl, virtualp, frie
*** 12355,12392 ****
  		warning ("conversion to %s%s will never use a type conversion operator",
  			 ref ? "a reference to " : "", what);
  	    }
- 	}
- 
-       if (DECL_ASSIGNMENT_OPERATOR_P (decl)
- 	  && operator_code == NOP_EXPR)
- 	{
- 	  tree parmtype;
- 
- 	  if (arity != 2 && methodp)
- 	    {
- 	      cp_error ("`%D' must take exactly one argument", decl);
- 	      return;
- 	    }
- 	  parmtype = TREE_VALUE (TREE_CHAIN (argtypes));
- 
- 	  /* [class.copy]
- 
- 	     A user-declared copy assignment operator X::operator= is
- 	     a non-static non-template member function of class X with
- 	     exactly one parameter of type X, X&, const X&, volatile
- 	     X& or const volatile X&.  */
- 	  if (copy_assignment_arg_p (parmtype, virtualp)
- 	      && !(DECL_TEMPLATE_INSTANTIATION (decl)
- 		   && is_member_template (DECL_TI_TEMPLATE (decl)))
- 	      && ! friendp)
- 	    {
- 	      TYPE_HAS_ASSIGN_REF (current_class_type) = 1;
- 	      if (TREE_CODE (parmtype) != REFERENCE_TYPE
- 		  || CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
- 		TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
- 	    }
  	}
!       else if (operator_code == COND_EXPR)
  	{
  	  /* 13.4.0.3 */
  	  cp_error ("ISO C++ prohibits overloading operator ?:");
--- 12400,12407 ----
  		warning ("conversion to %s%s will never use a type conversion operator",
  			 ref ? "a reference to " : "", what);
  	    }
  	}
!       if (operator_code == COND_EXPR)
  	{
  	  /* 13.4.0.3 */
  	  cp_error ("ISO C++ prohibits overloading operator ?:");
*************** grok_op_properties (decl, virtualp, frie
*** 12522,12528 ****
  	  && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
  	cp_warning ("`%D' should return by value", decl);
  
!       /* 13.4.0.8 */
        for (; argtypes && argtypes != void_list_node;
            argtypes = TREE_CHAIN (argtypes))
          if (TREE_PURPOSE (argtypes))
--- 12537,12543 ----
  	  && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
  	cp_warning ("`%D' should return by value", decl);
  
!       /* [over.oper]/8 */
        for (; argtypes && argtypes != void_list_node;
            argtypes = TREE_CHAIN (argtypes))
          if (TREE_PURPOSE (argtypes))
*************** start_method (declspecs, declarator, att
*** 14258,14272 ****
  	{
  	  fndecl = copy_node (fndecl);
  	  TREE_CHAIN (fndecl) = NULL_TREE;
- 	}
- 
-       if (DECL_CONSTRUCTOR_P (fndecl))
- 	{
- 	  if (! grok_ctor_properties (current_class_type, fndecl))
- 	    return void_type_node;
  	}
!       else if (IDENTIFIER_OPNAME_P (DECL_NAME (fndecl)))
! 	grok_op_properties (fndecl, DECL_VIRTUAL_P (fndecl), 0);
      }
  
    cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
--- 14273,14280 ----
  	{
  	  fndecl = copy_node (fndecl);
  	  TREE_CHAIN (fndecl) = NULL_TREE;
  	}
!       grok_special_member_properties (fndecl);
      }
  
    cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.501
diff -c -3 -p -r1.501 decl2.c
*** decl2.c	2001/11/30 03:14:56	1.501
--- decl2.c	2001/12/04 14:19:17
*************** grokfield (declarator, declspecs, init, 
*** 1645,1650 ****
--- 1645,1653 ----
  	  SET_DECL_RTL (value, NULL_RTX);
  	  SET_DECL_ASSEMBLER_NAME (value, get_identifier (asmspec));
  	}
+       if (!DECL_FRIEND_P (value))
+ 	grok_special_member_properties (value);
+       
        cp_finish_decl (value, init, asmspec_tree, flags);
  
        /* Pass friends back this way.  */
*************** grokoptypename (declspecs, declarator)
*** 1762,1789 ****
  
  */
  
- int
- copy_assignment_arg_p (parmtype, virtualp)
-      tree parmtype;
-      int virtualp ATTRIBUTE_UNUSED;
- {
-   if (current_class_type == NULL_TREE)
-     return 0;
- 
-   if (TREE_CODE (parmtype) == REFERENCE_TYPE)
-     parmtype = TREE_TYPE (parmtype);
- 
-   if ((TYPE_MAIN_VARIANT (parmtype) == current_class_type)
- #if 0
-       /* Non-standard hack to support old Booch components.  */
-       || (! virtualp && DERIVED_FROM_P (parmtype, current_class_type))
- #endif
-       )
-     return 1;
- 
-   return 0;
- }
- 
  static void
  grok_function_init (decl, init)
       tree decl;
--- 1765,1770 ----
*************** grok_function_init (decl, init)
*** 1796,1812 ****
    if (TREE_CODE (type) == FUNCTION_TYPE)
      cp_error ("initializer specified for non-member function `%D'", decl);
    else if (integer_zerop (init))
!     {
!       DECL_PURE_VIRTUAL_P (decl) = 1;
!       if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
! 	{
! 	  tree parmtype
! 	    = TREE_VALUE (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (decl))));
! 
! 	  if (copy_assignment_arg_p (parmtype, 1))
! 	    TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1;
! 	}
!     }
    else
      cp_error ("invalid initializer for virtual method `%D'", decl);
  }
--- 1777,1783 ----
    if (TREE_CODE (type) == FUNCTION_TYPE)
      cp_error ("initializer specified for non-member function `%D'", decl);
    else if (integer_zerop (init))
!     DECL_PURE_VIRTUAL_P (decl) = 1;
    else
      cp_error ("invalid initializer for virtual method `%D'", decl);
  }
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.560
diff -c -3 -p -r1.560 pt.c
*** pt.c	2001/12/04 09:51:18	1.560
--- pt.c	2001/12/04 14:19:19
*************** instantiate_class_template (type)
*** 5187,5192 ****
--- 5187,5193 ----
      {
        tree r = tsubst (t, args, /*complain=*/1, NULL_TREE);
        set_current_access_from_decl (r);
+       grok_special_member_properties (r);
        finish_member_declaration (r);
      }
  
*************** tsubst_decl (t, args, type)
*** 5896,5905 ****
  	       If it isn't, that'll be handled by
  	       clone_constructors_and_destructors.  */
  	    if (PRIMARY_TEMPLATE_P (gen_tmpl))
! 	      clone_function_decl(r, /*update_method_vec_p=*/0);
  	  }
  	else if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
! 	  grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
        }
        break;
  
--- 5897,5906 ----
  	       If it isn't, that'll be handled by
  	       clone_constructors_and_destructors.  */
  	    if (PRIMARY_TEMPLATE_P (gen_tmpl))
! 	      clone_function_decl (r, /*update_method_vec_p=*/0);
  	  }
  	else if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
! 	  grok_op_properties (r, DECL_FRIEND_P (r));
        }
        break;
  
// { dg-do run }

// Copyright (C) 2000 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 30 Nov 2001 <nathan@nathan@codesourcery.com>

// PR 87

int assign = 0;
int ctor = 0;
int assignC = 0;

struct A {
  int i;

  template<class T>
  void operator=(const T&) const
  { 
    assign = 1;
  }

  A () : i (0) {}
  
  template <typename T> A (const T &)
  {
    ctor = 1;
  }
};

struct B : A 
{
};

struct C 
{
  int i;

  C (int i_) :i (i_) {}
  
  template <int I>
  void operator= (const C &)
  {
    assignC = 1;
  }
};


int main()
{
  const A a;
  A b;
  B c;

  b = a;
  if (assign)
    return 5;
  
  b.i = 100;
  c.i = 200;
  
  a = b; 

  if (!assign)
    return 1;
  if (a.i)
    return 2;

  A e (b);
  if (ctor)
    return 3;
  
  A d (c);
  if (!ctor)
    return 4;

  C c0 (0);
  C c1 (1);

  c0 = c1;
  if (assignC)
    return 5;
  
  return 0;
}

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