aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-12-09 16:33:44 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-12-09 16:33:44 +0000
commit271e6f02a18b2d480c55b7bdee57bc4de7edc02a (patch)
tree47497fa5c9fd195f980d2e24398c007ac46ceca9 /gcc/cp
parentb3656137984c755671e79da32c66379c0a4d2425 (diff)
downloadgcc-271e6f02a18b2d480c55b7bdee57bc4de7edc02a.zip
gcc-271e6f02a18b2d480c55b7bdee57bc4de7edc02a.tar.gz
gcc-271e6f02a18b2d480c55b7bdee57bc4de7edc02a.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog26
-rw-r--r--gcc/cp/call.c2
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/decl.c241
-rw-r--r--gcc/cp/decl2.c37
-rw-r--r--gcc/cp/pt.c5
6 files changed, 169 insertions, 150 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d8004b6..ea344c4 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0a59b17..21049b8 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 992c708..6172adf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 66aa70d..26d3a24 100644
--- a/gcc/cp/decl.c
+++ b/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;
-
- /* [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))))
- {
+ 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;
}
- 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);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 737d295..e625d96 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8e620be..48f3951 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;