C++ PATCH: PR 25635, 25638, 25638, 25633, 25634
Mark Mitchell
mark@codesourcery.com
Tue Jan 3 08:46:00 GMT 2006
This patch fixes various C++ regressions:
* 25635: We failed to set TYPE_HAS_CONVERSION on a type for which a
(erroneous) conversion operator declaration appeared after the type
was complete. As a result, subsequent attempts to find the
conversion operator failed, leading to an error cases.
* 25638: We created multiple destructor declarations for a class, in
the presence of an (erroneous) friend destructor declaration. Other
parts of the front end reasonably assume that a class has only one
destructor. Fixed by refusing to register multiple destructors.
* 25637: We permitted friend function definitions of members of other
classes; friend declarations should be allowed, but not
definitions.
* 25633: We failed to discard erroneous mem-initializers.
* 25634: We failed to check for the presence of too many template
parameter lists in elaborated type specifiers.
Tested on x86_64-unknown-linux-gnu. Applied on the mainline, 4.1, and
4.0 branches; the branch versions omit the cleanups below which are
not necessary to fix the bugs.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
2006-01-02 Mark Mitchell <mark@codesourcery.com>
PR c++/25635
* class.c (add_method): Set TYPE_HAS_CONVERSION for classes with a
conversion operator.
* decl.c (grokdeclarator): Do not set TYPE_HAS_CONVERSION here.
PR c++/25638
* class.c (add_method): Never associate more than one destructor
with a single class.
PR c++/25637
* cp-tree.h (do_friend): Adjust prototype.
* decl.c (grokfndecl): Make funcdef_flag a bool, not an int.
(grokdeclarator): Likewise. Refine check for invalid
declarations/definitions of member functions outside of their own
class.
* friend.c (do_friend): Make funcdef_flag a bool, not an int.
PR c++/25633
* parser.c (cp_parser_mem_initializer_list): Check result of
cp_parser_mem_initializer against error_mark_node, not NULL_TREE.
(cp_parser_mem_initializer): Return error_mark_node for failure.
PR c++/25634
* parser.c (cp_parser_template_parameter_list): Call
begin_template_parm_list and end_template_parm_list here.
(cp_parser_type_parameter): Not here.
(cp_parser_template_declaration_after_export): Or here.
(cp_parser_elaborated_type_specifier): Call
cp_parser_check_template_parameters.
* tree.c (build_target_expr_with_type): Use force_target_expr.
2006-01-02 Mark Mitchell <mark@codesourcery.com>
PR c++/25635
* g++.dg/parse/operator6.C: New test.
PR c++/25637
* g++.dg/parse/error29.C: New test.
PR c++/25638
* g++.dg/parse/dtor6.C: New test.
PR c++/25633
* g++.dg/parse/ctor3.C: New test.
PR c++/25634
* g++.dg/template/class3.C: New test.
Index: gcc/testsuite/g++.dg/parse/operator6.C
===================================================================
--- gcc/testsuite/g++.dg/parse/operator6.C (revision 0)
+++ gcc/testsuite/g++.dg/parse/operator6.C (revision 0)
@@ -0,0 +1,5 @@
+// PR c++/25635
+
+struct A {};
+
+A::operator int(); // { dg-error "class" }
Index: gcc/testsuite/g++.dg/parse/error29.C
===================================================================
--- gcc/testsuite/g++.dg/parse/error29.C (revision 0)
+++ gcc/testsuite/g++.dg/parse/error29.C (revision 0)
@@ -0,0 +1,12 @@
+// PR c++/25637
+
+struct A {
+ void foo();
+ A();
+ void operator delete(void *);
+};
+struct B {
+ friend void A::foo() {} // { dg-error "define" }
+ friend void A::operator delete(void*) {} // { dg-error "define" }
+ friend A::A() {} // { dg-error "define" }
+};
Index: gcc/testsuite/g++.dg/parse/dtor6.C
===================================================================
--- gcc/testsuite/g++.dg/parse/dtor6.C (revision 0)
+++ gcc/testsuite/g++.dg/parse/dtor6.C (revision 0)
@@ -0,0 +1,8 @@
+// PR c++/25638
+
+struct A { ~A(); }; // { dg-error "candidate" }
+
+struct B : A
+{
+ template<int> friend A::~A(); // { dg-error "match" }
+};
Index: gcc/testsuite/g++.dg/parse/ctor3.C
===================================================================
--- gcc/testsuite/g++.dg/parse/ctor3.C (revision 0)
+++ gcc/testsuite/g++.dg/parse/ctor3.C (revision 0)
@@ -0,0 +1,8 @@
+// PR c++/25633
+
+struct A {};
+
+struct B : A
+{
+ B() : A {} // { dg-error "expected" }
+};
Index: gcc/testsuite/g++.dg/template/class3.C
===================================================================
--- gcc/testsuite/g++.dg/template/class3.C (revision 0)
+++ gcc/testsuite/g++.dg/template/class3.C (revision 0)
@@ -0,0 +1,2 @@
+// PR c++/25634
+template<int> template<int> struct A; // { dg-error "too many" }
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c (revision 109259)
+++ gcc/cp/class.c (working copy)
@@ -1059,10 +1059,16 @@ add_method (tree type, tree method, tree
}
}
+ /* A class should never have more than one destructor. */
+ if (current_fns && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+ return false;
+
/* Add the new binding. */
overload = build_overload (method, current_fns);
- if (!conv_p && slot >= CLASSTYPE_FIRST_CONVERSION_SLOT && !complete_p)
+ if (conv_p)
+ TYPE_HAS_CONVERSION (type) = 1;
+ else if (slot >= CLASSTYPE_FIRST_CONVERSION_SLOT && !complete_p)
push_class_level_binding (DECL_NAME (method), overload);
if (insert_p)
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 109259)
+++ gcc/cp/decl.c (working copy)
@@ -5697,7 +5697,7 @@ grokfndecl (tree ctype,
int publicp,
int inlinep,
special_function_kind sfk,
- int funcdef_flag,
+ bool funcdef_flag,
int template_count,
tree in_namespace,
tree* attrlist)
@@ -5918,7 +5918,7 @@ grokfndecl (tree ctype,
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
- 2 * (funcdef_flag != 0) +
+ 2 * funcdef_flag +
4 * (friendp != 0));
if (decl == error_mark_node)
return NULL_TREE;
@@ -5940,27 +5940,26 @@ grokfndecl (tree ctype,
> template_class_depth (ctype))
? current_template_parms
: NULL_TREE);
-
- if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
- /* Because grokfndecl is always supposed to return a
- FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
- here. We depend on our callers to figure out that its
- really a template that's being returned. */
- old_decl = DECL_TEMPLATE_RESULT (old_decl);
-
- if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
- && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
- /* Remove the `this' parm added by grokclassfn.
- XXX Isn't this done in start_function, too? */
- revert_static_member_fn (decl);
- if (old_decl && DECL_ARTIFICIAL (old_decl))
- error ("definition of implicitly-declared %qD", old_decl);
-
if (old_decl)
{
tree ok;
tree pushed_scope;
+ if (TREE_CODE (old_decl) == TEMPLATE_DECL)
+ /* Because grokfndecl is always supposed to return a
+ FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
+ here. We depend on our callers to figure out that its
+ really a template that's being returned. */
+ old_decl = DECL_TEMPLATE_RESULT (old_decl);
+
+ if (DECL_STATIC_FUNCTION_P (old_decl)
+ && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ /* Remove the `this' parm added by grokclassfn.
+ XXX Isn't this done in start_function, too? */
+ revert_static_member_fn (decl);
+ if (DECL_ARTIFICIAL (old_decl))
+ error ("definition of implicitly-declared %qD", old_decl);
+
/* Since we've smashed OLD_DECL to its
DECL_TEMPLATE_RESULT, we must do the same to DECL. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -6627,7 +6626,8 @@ grokdeclarator (const cp_declarator *dec
tree typedef_decl = NULL_TREE;
const char *name = NULL;
tree typedef_type = NULL_TREE;
- int funcdef_flag = 0;
+ /* True if this declarator is a function definition. */
+ bool funcdef_flag = false;
cp_declarator_kind innermost_code = cdk_error;
int bitfield = 0;
#if 0
@@ -6674,9 +6674,9 @@ grokdeclarator (const cp_declarator *dec
thread_p = declspecs->specs[(int)ds_thread];
if (decl_context == FUNCDEF)
- funcdef_flag = 1, decl_context = NORMAL;
+ funcdef_flag = true, decl_context = NORMAL;
else if (decl_context == MEMFUNCDEF)
- funcdef_flag = -1, decl_context = FIELD;
+ funcdef_flag = true, decl_context = FIELD;
else if (decl_context == BITFIELD)
bitfield = 1, decl_context = FIELD;
@@ -7349,8 +7349,6 @@ grokdeclarator (const cp_declarator *dec
&& (friendp == 0 || dname == current_class_name))
ctype = current_class_type;
- if (ctype && sfk == sfk_conversion)
- TYPE_HAS_CONVERSION (ctype) = 1;
if (ctype && (sfk == sfk_constructor
|| sfk == sfk_destructor))
{
@@ -7604,22 +7602,25 @@ grokdeclarator (const cp_declarator *dec
{
tree sname = declarator->u.id.unqualified_name;
+ if (current_class_type
+ && (!friendp || funcdef_flag))
+ {
+ error (funcdef_flag
+ ? "cannot define member function %<%T::%s%> within %<%T%>"
+ : "cannot declare member function %<%T::%s%> within %<%T%>",
+ ctype, name, current_class_type);
+ return error_mark_node;
+ }
+
if (TREE_CODE (sname) == IDENTIFIER_NODE
&& NEW_DELETE_OPNAME_P (sname))
/* Overloaded operator new and operator delete
are always static functions. */
;
- else if (current_class_type == NULL_TREE || friendp)
- type
- = build_method_type_directly (ctype,
- TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
else
- {
- error ("cannot declare member function %<%T::%s%> within %<%T%>",
- ctype, name, current_class_type);
- return error_mark_node;
- }
+ type = build_method_type_directly (ctype,
+ TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
}
else if (declspecs->specs[(int)ds_typedef]
|| COMPLETE_TYPE_P (complete_type (ctype)))
@@ -8179,7 +8180,7 @@ grokdeclarator (const cp_declarator *dec
{
decl = check_explicit_specialization
(unqualified_id, decl, template_count,
- 2 * (funcdef_flag != 0) + 4);
+ 2 * funcdef_flag + 4);
if (decl == error_mark_node)
return error_mark_node;
}
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c (revision 109259)
+++ gcc/cp/tree.c (working copy)
@@ -325,8 +325,6 @@ build_cplus_new (tree type, tree init)
tree
build_target_expr_with_type (tree init, tree type)
{
- tree slot;
-
gcc_assert (!VOID_TYPE_P (type));
if (TREE_CODE (init) == TARGET_EXPR)
@@ -342,8 +340,7 @@ build_target_expr_with_type (tree init,
aggregate; there's no additional work to be done. */
return force_rvalue (init);
- slot = build_local_temp (type);
- return build_target_expr (slot, init);
+ return force_target_expr (type, init);
}
/* Like the above function, but without the checking. This function should
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 109259)
+++ gcc/cp/cp-tree.h (working copy)
@@ -3935,7 +3935,7 @@ extern tree cplus_expand_constant (tree
extern int is_friend (tree, tree);
extern void make_friend_class (tree, tree, bool);
extern void add_friend (tree, tree, bool);
-extern tree do_friend (tree, tree, tree, tree, enum overload_flags, cp_cv_quals, int);
+extern tree do_friend (tree, tree, tree, tree, enum overload_flags, cp_cv_quals, bool);
/* in init.c */
extern tree expand_member_init (tree);
Index: gcc/cp/friend.c
===================================================================
--- gcc/cp/friend.c (revision 109259)
+++ gcc/cp/friend.c (working copy)
@@ -408,7 +408,7 @@ tree
do_friend (tree ctype, tree declarator, tree decl,
tree attrlist, enum overload_flags flags,
cp_cv_quals quals,
- int funcdef_flag)
+ bool funcdef_flag)
{
/* Every decl that gets here is a friend of something. */
DECL_FRIEND_P (decl) = 1;
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 109259)
+++ gcc/cp/parser.c (working copy)
@@ -7808,7 +7808,7 @@ cp_parser_mem_initializer_list (cp_parse
/* Parse the mem-initializer. */
mem_initializer = cp_parser_mem_initializer (parser);
/* Add it to the list, unless it was erroneous. */
- if (mem_initializer)
+ if (mem_initializer != error_mark_node)
{
TREE_CHAIN (mem_initializer) = mem_initializer_list;
mem_initializer_list = mem_initializer;
@@ -7837,7 +7837,8 @@ cp_parser_mem_initializer_list (cp_parse
Returns a TREE_LIST. The TREE_PURPOSE is the TYPE (for a base
class) or FIELD_DECL (for a non-static data member) to initialize;
- the TREE_VALUE is the expression-list. */
+ the TREE_VALUE is the expression-list. An empty initialization
+ list is represented by void_list_node. */
static tree
cp_parser_mem_initializer (cp_parser* parser)
@@ -7862,12 +7863,14 @@ cp_parser_mem_initializer (cp_parser* pa
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
/*non_constant_p=*/NULL);
+ if (expression_list == error_mark_node)
+ return error_mark_node;
if (!expression_list)
expression_list = void_type_node;
in_base_initializer = 0;
- return member ? build_tree_list (member, expression_list) : NULL_TREE;
+ return member ? build_tree_list (member, expression_list) : error_mark_node;
}
/* Parse a mem-initializer-id.
@@ -8277,6 +8280,7 @@ cp_parser_template_parameter_list (cp_pa
{
tree parameter_list = NULL_TREE;
+ begin_template_parm_list ();
while (true)
{
tree parameter;
@@ -8299,7 +8303,7 @@ cp_parser_template_parameter_list (cp_pa
cp_lexer_consume_token (parser->lexer);
}
- return parameter_list;
+ return end_template_parm_list (parameter_list);
}
/* Parse a template-parameter.
@@ -8447,10 +8451,7 @@ cp_parser_type_parameter (cp_parser* par
/* Look for the `<'. */
cp_parser_require (parser, CPP_LESS, "`<'");
/* Parse the template-parameter-list. */
- begin_template_parm_list ();
- parameter_list
- = cp_parser_template_parameter_list (parser);
- parameter_list = end_template_parm_list (parameter_list);
+ parameter_list = cp_parser_template_parameter_list (parser);
/* Look for the `>'. */
cp_parser_require (parser, CPP_GREATER, "`>'");
/* Look for the `class' keyword. */
@@ -10112,6 +10113,11 @@ cp_parser_elaborated_type_specifier (cp_
(parser->num_template_parameter_lists
&& (cp_parser_next_token_starts_class_definition_p (parser)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
+ /* An unqualified name was used to reference this type, so
+ there were no qualifying templates. */
+ if (!cp_parser_check_template_parameters (parser,
+ /*num_templates=*/0))
+ return error_mark_node;
type = xref_tag (tag_type, identifier, ts, template_p);
}
}
@@ -15259,12 +15265,8 @@ cp_parser_template_declaration_after_exp
parameter_list = NULL_TREE;
}
else
- {
- /* Parse the template parameters. */
- begin_template_parm_list ();
- parameter_list = cp_parser_template_parameter_list (parser);
- parameter_list = end_template_parm_list (parameter_list);
- }
+ /* Parse the template parameters. */
+ parameter_list = cp_parser_template_parameter_list (parser);
/* Look for the `>'. */
cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
More information about the Gcc-patches
mailing list