Commit 271e6f02 by Nathan Sidwell Committed by Nathan Sidwell

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
parent b3656137
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> 2001-12-08 Aldy Hernandez <aldyh@redhat.com>
* lex.c (rid_to_yy): Add RID_CHOOSE_EXPR and * lex.c (rid_to_yy): Add RID_CHOOSE_EXPR and
......
...@@ -4280,7 +4280,7 @@ build_over_call (cand, args, flags) ...@@ -4280,7 +4280,7 @@ build_over_call (cand, args, flags)
} }
} }
else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR 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))) && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CONTEXT (fn)))
{ {
tree to = stabilize_reference tree to = stabilize_reference
......
...@@ -1841,7 +1841,7 @@ struct lang_decl ...@@ -1841,7 +1841,7 @@ struct lang_decl
/* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor. */ /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor. */
#define DECL_COPY_CONSTRUCTOR_P(NODE) \ #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. */ /* Nonzero if NODE is a destructor. */
#define DECL_DESTRUCTOR_P(NODE) \ #define DECL_DESTRUCTOR_P(NODE) \
...@@ -3690,9 +3690,10 @@ extern int complete_array_type PARAMS ((tree, tree, int)); ...@@ -3690,9 +3690,10 @@ extern int complete_array_type PARAMS ((tree, tree, int));
extern tree build_ptrmemfunc_type PARAMS ((tree)); extern tree build_ptrmemfunc_type PARAMS ((tree));
/* the grokdeclarator prototype is in decl.h */ /* the grokdeclarator prototype is in decl.h */
extern int parmlist_is_exprlist PARAMS ((tree)); 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 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 PARAMS ((tree, tree, int));
extern tree xref_tag_from_type PARAMS ((tree, tree, int)); extern tree xref_tag_from_type PARAMS ((tree, tree, int));
extern void xref_basetypes PARAMS ((tree, tree, tree, tree)); extern void xref_basetypes PARAMS ((tree, tree, tree, tree));
...@@ -3757,7 +3758,6 @@ extern tree grokfield PARAMS ((tree, 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 grokbitfield PARAMS ((tree, tree, tree));
extern tree groktypefield PARAMS ((tree, tree)); extern tree groktypefield PARAMS ((tree, tree));
extern tree grokoptypename 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 void cplus_decl_attributes PARAMS ((tree *, tree, int));
extern tree constructor_name_full PARAMS ((tree)); extern tree constructor_name_full PARAMS ((tree));
extern tree constructor_name PARAMS ((tree)); extern tree constructor_name PARAMS ((tree));
......
...@@ -8789,9 +8789,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, ...@@ -8789,9 +8789,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
tree t; tree t;
if (raises) if (raises)
{
type = build_exception_variant (type, raises); type = build_exception_variant (type, raises);
}
decl = build_lang_decl (FUNCTION_DECL, declarator, type); decl = build_lang_decl (FUNCTION_DECL, declarator, type);
/* Propagate volatile out from type to decl. */ /* Propagate volatile out from type to decl. */
...@@ -8902,7 +8900,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, ...@@ -8902,7 +8900,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
} }
if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) 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)) if (ctype && decl_function_context (decl))
DECL_NO_STATIC_CHAIN (decl) = 1; DECL_NO_STATIC_CHAIN (decl) = 1;
...@@ -12053,89 +12051,149 @@ grokparms (first_parm) ...@@ -12053,89 +12051,149 @@ grokparms (first_parm)
} }
/* D is a constructor or overloaded `operator='. Returns non-zero if /* D is a constructor or overloaded `operator='.
D's arguments allow it to be a copy constructor, or copy assignment
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. */ operator. */
int int
copy_args_p (d) copy_fn_p (d)
tree 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; return 0;
t = FUNCTION_FIRST_USER_PARMTYPE (d); args = FUNCTION_FIRST_USER_PARMTYPE (d);
if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE if (!args)
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t))) return 0;
== DECL_CONTEXT (d))
&& (TREE_CHAIN (t) == NULL_TREE arg_type = TREE_VALUE (args);
|| TREE_CHAIN (t) == void_list_node
|| TREE_PURPOSE (TREE_CHAIN (t)))) if (TYPE_MAIN_VARIANT (arg_type) == DECL_CONTEXT (d))
return 1; {
/* 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 0;
return result;
} }
/* These memoizing functions keep track of special properties which /* Remember any special properties of member function DECL. */
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 void grok_special_member_properties (decl)
grok_ctor_properties (ctype, decl) tree decl;
tree ctype, decl;
{ {
tree parmtypes = FUNCTION_FIRST_USER_PARMTYPE (decl); if (!DECL_NONSTATIC_MEMBER_FUNCTION_P(decl))
tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node; ; /* Not special. */
else if (DECL_CONSTRUCTOR_P (decl))
{
int ctor = copy_fn_p (decl);
if (ctor > 0)
{
/* [class.copy] /* [class.copy]
A non-template constructor for class X is a copy constructor if A non-template constructor for class X is a copy
its first parameter is of type X&, const X&, volatile X& or const constructor if its first parameter is of type X&, const
volatile X&, and either there are no other parameters or else all X&, volatile X& or const volatile X&, and either there
other parameters have default arguments. */ are no other parameters or else all other parameters have
if (TREE_CODE (parmtype) == REFERENCE_TYPE default arguments. */
&& TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype TYPE_HAS_INIT_REF (DECL_CONTEXT (decl)) = 1;
&& sufficient_parms_p (TREE_CHAIN (parmtypes)) if (ctor > 1)
&& !(DECL_TEMPLATE_INSTANTIATION (decl) TYPE_HAS_CONST_INIT_REF (DECL_CONTEXT (decl)) = 1;
&& is_member_template (DECL_TI_TEMPLATE (decl)))) }
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)
{ {
TYPE_HAS_INIT_REF (ctype) = 1; /* [class.copy]
if (CP_TYPE_CONST_P (TREE_TYPE (parmtype)))
TYPE_HAS_CONST_INIT_REF (ctype) = 1; 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] /* [class.copy]
A declaration of a constructor for a class X is ill-formed if its A declaration of a constructor for a class X is ill-formed if
first parameter is of type (optionally cv-qualified) X and either its first parameter is of type (optionally cv-qualified) X
there are no other parameters or else all other parameters have and either there are no other parameters or else all other
default arguments. parameters have default arguments.
We *don't* complain about member template instantiations that We *don't* complain about member template instantiations that
have this form, though; they can occur as we try to decide what have this form, though; they can occur as we try to decide
constructor to use during overload resolution. Since overload what constructor to use during overload resolution. Since
resolution will never prefer such a constructor to the overload resolution will never prefer such a constructor to
non-template copy constructor (which is either explicitly or the non-template copy constructor (which is either explicitly
implicitly defined), there's no need to worry about their or implicitly defined), there's no need to worry about their
existence. Theoretically, they should never even be existence. Theoretically, they should never even be
instantiated, but that's hard to forestall. */ 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&)'", cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
ctype, ctype); ctype, ctype);
SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype); SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
return 0; return 0;
} }
else if (TREE_CODE (parmtype) == VOID_TYPE
|| TREE_PURPOSE (parmtypes) != NULL_TREE)
TYPE_HAS_DEFAULT_CONSTRUCTOR (ctype) = 1;
return 1; return 1;
} }
...@@ -12169,9 +12227,9 @@ unary_op_p (code) ...@@ -12169,9 +12227,9 @@ unary_op_p (code)
/* Do a little sanity-checking on how they declared their operator. */ /* Do a little sanity-checking on how they declared their operator. */
void void
grok_op_properties (decl, virtualp, friendp) grok_op_properties (decl, friendp)
tree decl; tree decl;
int virtualp, friendp; int friendp;
{ {
tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
tree argtype; tree argtype;
...@@ -12341,37 +12399,7 @@ grok_op_properties (decl, virtualp, friendp) ...@@ -12341,37 +12399,7 @@ grok_op_properties (decl, virtualp, friendp)
ref ? "a reference to " : "", what); ref ? "a reference to " : "", what);
} }
} }
if (operator_code == COND_EXPR)
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 */ /* 13.4.0.3 */
cp_error ("ISO C++ prohibits overloading operator ?:"); cp_error ("ISO C++ prohibits overloading operator ?:");
...@@ -12507,7 +12535,7 @@ grok_op_properties (decl, virtualp, friendp) ...@@ -12507,7 +12535,7 @@ grok_op_properties (decl, virtualp, friendp)
&& TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE) && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
cp_warning ("`%D' should return by value", decl); cp_warning ("`%D' should return by value", decl);
/* 13.4.0.8 */ /* [over.oper]/8 */
for (; argtypes && argtypes != void_list_node; for (; argtypes && argtypes != void_list_node;
argtypes = TREE_CHAIN (argtypes)) argtypes = TREE_CHAIN (argtypes))
if (TREE_PURPOSE (argtypes)) if (TREE_PURPOSE (argtypes))
...@@ -14244,14 +14272,7 @@ start_method (declspecs, declarator, attrlist) ...@@ -14244,14 +14272,7 @@ start_method (declspecs, declarator, attrlist)
fndecl = copy_node (fndecl); fndecl = copy_node (fndecl);
TREE_CHAIN (fndecl) = NULL_TREE; TREE_CHAIN (fndecl) = NULL_TREE;
} }
grok_special_member_properties (fndecl);
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); cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
......
...@@ -1645,6 +1645,9 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist) ...@@ -1645,6 +1645,9 @@ grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
SET_DECL_RTL (value, NULL_RTX); SET_DECL_RTL (value, NULL_RTX);
SET_DECL_ASSEMBLER_NAME (value, get_identifier (asmspec)); 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); cp_finish_decl (value, init, asmspec_tree, flags);
/* Pass friends back this way. */ /* Pass friends back this way. */
...@@ -1762,28 +1765,6 @@ grokoptypename (declspecs, declarator) ...@@ -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 static void
grok_function_init (decl, init) grok_function_init (decl, init)
tree decl; tree decl;
...@@ -1796,17 +1777,7 @@ grok_function_init (decl, init) ...@@ -1796,17 +1777,7 @@ grok_function_init (decl, init)
if (TREE_CODE (type) == FUNCTION_TYPE) if (TREE_CODE (type) == FUNCTION_TYPE)
cp_error ("initializer specified for non-member function `%D'", decl); cp_error ("initializer specified for non-member function `%D'", decl);
else if (integer_zerop (init)) else if (integer_zerop (init))
{
DECL_PURE_VIRTUAL_P (decl) = 1; 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 else
cp_error ("invalid initializer for virtual method `%D'", decl); cp_error ("invalid initializer for virtual method `%D'", decl);
} }
......
...@@ -5186,6 +5186,7 @@ instantiate_class_template (type) ...@@ -5186,6 +5186,7 @@ instantiate_class_template (type)
{ {
tree r = tsubst (t, args, /*complain=*/1, NULL_TREE); tree r = tsubst (t, args, /*complain=*/1, NULL_TREE);
set_current_access_from_decl (r); set_current_access_from_decl (r);
grok_special_member_properties (r);
finish_member_declaration (r); finish_member_declaration (r);
} }
...@@ -5895,10 +5896,10 @@ tsubst_decl (t, args, type) ...@@ -5895,10 +5896,10 @@ tsubst_decl (t, args, type)
If it isn't, that'll be handled by If it isn't, that'll be handled by
clone_constructors_and_destructors. */ clone_constructors_and_destructors. */
if (PRIMARY_TEMPLATE_P (gen_tmpl)) 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))) 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; break;
......
2001-12-09 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/other/copy1.C: New test.
2001-10-08 Aldy Hernandez <aldyh@redhat.com> 2001-10-08 Aldy Hernandez <aldyh@redhat.com>
* gcc.c-torture/execute/builtin-types-compatible-p.c: New. * gcc.c-torture/execute/builtin-types-compatible-p.c: New.
......
// { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment