re PR c++/87 (member template assignment operator)
cp: 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. testsuite: * g++.dg/other/copy1.C: New test. From-SVN: r47813
This commit is contained in:
parent
b365613798
commit
271e6f02a1
@ -1,3 +1,29 @@
|
||||
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.
|
||||
|
||||
2001-12-08 Aldy Hernandez <aldyh@redhat.com>
|
||||
|
||||
* lex.c (rid_to_yy): Add RID_CHOOSE_EXPR and
|
||||
|
@ -4280,7 +4280,7 @@ build_over_call (cand, args, flags)
|
||||
}
|
||||
}
|
||||
else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
|
||||
&& copy_args_p (fn)
|
||||
&& copy_fn_p (fn)
|
||||
&& TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
|
||||
{
|
||||
tree to = stabilize_reference
|
||||
|
@ -1841,7 +1841,7 @@ struct lang_decl
|
||||
|
||||
/* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor. */
|
||||
#define DECL_COPY_CONSTRUCTOR_P(NODE) \
|
||||
(DECL_CONSTRUCTOR_P (NODE) && copy_args_p (NODE))
|
||||
(DECL_CONSTRUCTOR_P (NODE) && copy_fn_p (NODE) > 0)
|
||||
|
||||
/* Nonzero if NODE is a destructor. */
|
||||
#define DECL_DESTRUCTOR_P(NODE) \
|
||||
@ -3690,9 +3690,10 @@ extern int complete_array_type PARAMS ((tree, tree, int));
|
||||
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 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, int));
|
||||
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));
|
||||
@ -3757,7 +3758,6 @@ extern tree grokfield PARAMS ((tree, tree, tree, tree, tree));
|
||||
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));
|
||||
|
237
gcc/cp/decl.c
237
gcc/cp/decl.c
@ -8789,9 +8789,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
|
||||
tree t;
|
||||
|
||||
if (raises)
|
||||
{
|
||||
type = build_exception_variant (type, raises);
|
||||
}
|
||||
type = build_exception_variant (type, raises);
|
||||
|
||||
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
|
||||
/* Propagate volatile out from type to decl. */
|
||||
@ -8902,7 +8900,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
|
||||
}
|
||||
|
||||
if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
|
||||
grok_op_properties (decl, virtualp, check < 0);
|
||||
grok_op_properties (decl, friendp);
|
||||
|
||||
if (ctype && decl_function_context (decl))
|
||||
DECL_NO_STATIC_CHAIN (decl) = 1;
|
||||
@ -12053,90 +12051,150 @@ grokparms (first_parm)
|
||||
}
|
||||
|
||||
|
||||
/* D is a constructor or overloaded `operator='. Returns non-zero if
|
||||
D's arguments allow it to be a copy constructor, or copy assignment
|
||||
/* D is a constructor or overloaded `operator='.
|
||||
|
||||
Let T be the class in which D is declared. Then, this function
|
||||
returns:
|
||||
|
||||
-1 if D's is an ill-formed constructor or copy assignment operator
|
||||
whose first parameter is of type `T'.
|
||||
0 if D is not a copy constructor or copy assignment
|
||||
operator.
|
||||
1 if D is a copy constructor or copy assignment operator whose
|
||||
first parameter is a reference to const qualified T.
|
||||
2 if D is a copy constructor or copy assignment operator whose
|
||||
first parameter is a reference to non-const qualified T.
|
||||
|
||||
This function can be used as a predicate. Positive values indicate
|
||||
a copy constructor and non-zero values indicate a copy assignment
|
||||
operator. */
|
||||
|
||||
int
|
||||
copy_args_p (d)
|
||||
copy_fn_p (d)
|
||||
tree d;
|
||||
{
|
||||
tree t;
|
||||
tree args;
|
||||
tree arg_type;
|
||||
int result = 1;
|
||||
|
||||
my_friendly_assert (DECL_FUNCTION_MEMBER_P (d), 20011208);
|
||||
|
||||
if (!DECL_FUNCTION_MEMBER_P (d))
|
||||
if (DECL_TEMPLATE_INFO (d) && is_member_template (DECL_TI_TEMPLATE (d)))
|
||||
/* Instantiations of template member functions are never copy
|
||||
functions. Note that member functions of templated classes are
|
||||
represented as template functions internally, and we must
|
||||
accept those as copy functions. */
|
||||
return 0;
|
||||
|
||||
args = FUNCTION_FIRST_USER_PARMTYPE (d);
|
||||
if (!args)
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* 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;
|
||||
{
|
||||
tree parmtypes = FUNCTION_FIRST_USER_PARMTYPE (decl);
|
||||
tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
|
||||
int ctor_parm = copy_fn_p (decl);
|
||||
|
||||
/* [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))))
|
||||
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;
|
||||
}
|
||||
else if (TREE_CODE (parmtype) == VOID_TYPE
|
||||
|| TREE_PURPOSE (parmtypes) != NULL_TREE)
|
||||
TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -12169,9 +12227,9 @@ unary_op_p (code)
|
||||
/* Do a little sanity-checking on how they declared their operator. */
|
||||
|
||||
void
|
||||
grok_op_properties (decl, virtualp, friendp)
|
||||
grok_op_properties (decl, friendp)
|
||||
tree decl;
|
||||
int virtualp, friendp;
|
||||
int friendp;
|
||||
{
|
||||
tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
||||
tree argtype;
|
||||
@ -12341,37 +12399,7 @@ grok_op_properties (decl, virtualp, friendp)
|
||||
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)
|
||||
if (operator_code == COND_EXPR)
|
||||
{
|
||||
/* 13.4.0.3 */
|
||||
cp_error ("ISO C++ prohibits overloading operator ?:");
|
||||
@ -12507,7 +12535,7 @@ grok_op_properties (decl, virtualp, friendp)
|
||||
&& TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
|
||||
cp_warning ("`%D' should return by value", decl);
|
||||
|
||||
/* 13.4.0.8 */
|
||||
/* [over.oper]/8 */
|
||||
for (; argtypes && argtypes != void_list_node;
|
||||
argtypes = TREE_CHAIN (argtypes))
|
||||
if (TREE_PURPOSE (argtypes))
|
||||
@ -14244,14 +14272,7 @@ start_method (declspecs, declarator, attrlist)
|
||||
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);
|
||||
grok_special_member_properties (fndecl);
|
||||
}
|
||||
|
||||
cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
|
||||
|
@ -1645,6 +1645,9 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
|
||||
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. */
|
||||
@ -1762,28 +1765,6 @@ grokoptypename (declspecs, declarator)
|
||||
|
||||
*/
|
||||
|
||||
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;
|
||||
@ -1796,17 +1777,7 @@ grok_function_init (decl, init)
|
||||
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;
|
||||
}
|
||||
}
|
||||
DECL_PURE_VIRTUAL_P (decl) = 1;
|
||||
else
|
||||
cp_error ("invalid initializer for virtual method `%D'", decl);
|
||||
}
|
||||
|
@ -5186,6 +5186,7 @@ instantiate_class_template (type)
|
||||
{
|
||||
tree r = tsubst (t, args, /*complain=*/1, NULL_TREE);
|
||||
set_current_access_from_decl (r);
|
||||
grok_special_member_properties (r);
|
||||
finish_member_declaration (r);
|
||||
}
|
||||
|
||||
@ -5895,10 +5896,10 @@ tsubst_decl (t, args, type)
|
||||
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);
|
||||
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));
|
||||
grok_op_properties (r, DECL_FRIEND_P (r));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2001-12-09 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/other/copy1.C: New test.
|
||||
|
||||
2001-10-08 Aldy Hernandez <aldyh@redhat.com>
|
||||
|
||||
* gcc.c-torture/execute/builtin-types-compatible-p.c: New.
|
||||
|
83
gcc/testsuite/g++.dg/other/copy1.C
Normal file
83
gcc/testsuite/g++.dg/other/copy1.C
Normal file
@ -0,0 +1,83 @@
|
||||
// { 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user