diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-02-10 00:34:46 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-02-10 00:34:46 +0000 |
commit | f0d4a6071814253e437f726f32ce6504121af58c (patch) | |
tree | db8f6d8142bd2c42ccac2bf7325075e8df87ea99 /gcc/cp | |
parent | b091dc59bfbdb8a9414f2e64f95b1284f991acf5 (diff) | |
download | gcc-f0d4a6071814253e437f726f32ce6504121af58c.tar.gz |
PR c++/19787
* call.c (initialize_reference): Robustify.
PR ++/19732
* decl.c (grokdeclarator): Check for invalid use of destructor
names.
PR c++/19762
* parser.c (cp_parser_unqualified_id): Avoid creating destructor
names with invalid types.
PR c++/19826
* parser.c (cp_parser_direct_declarator): Allow type-dependent
expressions as array bounds.
PR c++/19739
* parser.c (cp_parser_attributes_list): Allow empty lists.
PR c++/19787
* g++.dg/conversion/ambig1.C: New test.
PR c++/19739
* g++.dg/ext/attrib19.C: New test.
PR c++/19732
* g++.dg/parse/dtor5.C: New test.
PR c++/19762
* g++.dg/template/dtor3.C: New test.
PR c++/19826
* g++.dg/template/static11.C: New test.
* g++.dg/template/crash2.C: Remove dg-error marker.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94788 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/cp/call.c | 135 | ||||
-rw-r--r-- | gcc/cp/decl.c | 40 | ||||
-rw-r--r-- | gcc/cp/parser.c | 111 |
4 files changed, 182 insertions, 124 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dc5609f1a73..01d7f75dbd8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2005-02-09 Mark Mitchell <mark@codesourcery.com> + + PR c++/19787 + * call.c (initialize_reference): Robustify. + + PR ++/19732 + * decl.c (grokdeclarator): Check for invalid use of destructor + names. + + PR c++/19762 + * parser.c (cp_parser_unqualified_id): Avoid creating destructor + names with invalid types. + + PR c++/19826 + * parser.c (cp_parser_direct_declarator): Allow type-dependent + expressions as array bounds. + + PR c++/19739 + * parser.c (cp_parser_attributes_list): Allow empty lists. + 2005-02-08 Mark Mitchell <mark@codesourcery.com> PR c++/19733 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 599aecfa84a..5d931c8b6e3 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6534,81 +6534,86 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup) /*inner=*/-1, /*issue_conversion_warnings=*/true, /*c_cast_p=*/false); - if (!real_lvalue_p (expr)) + if (error_operand_p (expr)) + expr = error_mark_node; + else { - tree init; - tree type; - - /* Create the temporary variable. */ - type = TREE_TYPE (expr); - var = make_temporary_var_for_ref_to_temp (decl, type); - layout_decl (var, 0); - /* If the rvalue is the result of a function call it will be - a TARGET_EXPR. If it is some other construct (such as a - member access expression where the underlying object is - itself the result of a function call), turn it into a - TARGET_EXPR here. It is important that EXPR be a - TARGET_EXPR below since otherwise the INIT_EXPR will - attempt to make a bitwise copy of EXPR to initialize - VAR. */ - if (TREE_CODE (expr) != TARGET_EXPR) - expr = get_target_expr (expr); - /* Create the INIT_EXPR that will initialize the temporary - variable. */ - init = build2 (INIT_EXPR, type, var, expr); - if (at_function_scope_p ()) + if (!real_lvalue_p (expr)) { - add_decl_expr (var); - *cleanup = cxx_maybe_build_cleanup (var); - - /* We must be careful to destroy the temporary only - after its initialization has taken place. If the - initialization throws an exception, then the - destructor should not be run. We cannot simply - transform INIT into something like: - - (INIT, ({ CLEANUP_STMT; })) - - because emit_local_var always treats the - initializer as a full-expression. Thus, the - destructor would run too early; it would run at the - end of initializing the reference variable, rather - than at the end of the block enclosing the - reference variable. - - The solution is to pass back a cleanup expression - which the caller is responsible for attaching to - the statement tree. */ + tree init; + tree type; + + /* Create the temporary variable. */ + type = TREE_TYPE (expr); + var = make_temporary_var_for_ref_to_temp (decl, type); + layout_decl (var, 0); + /* If the rvalue is the result of a function call it will be + a TARGET_EXPR. If it is some other construct (such as a + member access expression where the underlying object is + itself the result of a function call), turn it into a + TARGET_EXPR here. It is important that EXPR be a + TARGET_EXPR below since otherwise the INIT_EXPR will + attempt to make a bitwise copy of EXPR to initialize + VAR. */ + if (TREE_CODE (expr) != TARGET_EXPR) + expr = get_target_expr (expr); + /* Create the INIT_EXPR that will initialize the temporary + variable. */ + init = build2 (INIT_EXPR, type, var, expr); + if (at_function_scope_p ()) + { + add_decl_expr (var); + *cleanup = cxx_maybe_build_cleanup (var); + + /* We must be careful to destroy the temporary only + after its initialization has taken place. If the + initialization throws an exception, then the + destructor should not be run. We cannot simply + transform INIT into something like: + + (INIT, ({ CLEANUP_STMT; })) + + because emit_local_var always treats the + initializer as a full-expression. Thus, the + destructor would run too early; it would run at the + end of initializing the reference variable, rather + than at the end of the block enclosing the + reference variable. + + The solution is to pass back a cleanup expression + which the caller is responsible for attaching to + the statement tree. */ + } + else + { + rest_of_decl_compilation (var, /*toplev=*/1, at_eof); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + static_aggregates = tree_cons (NULL_TREE, var, + static_aggregates); + } + /* Use its address to initialize the reference variable. */ + expr = build_address (var); + if (base_conv_type) + expr = convert_to_base (expr, + build_pointer_type (base_conv_type), + /*check_access=*/true, + /*nonnull=*/true); + expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr); } else - { - rest_of_decl_compilation (var, /*toplev=*/1, at_eof); - if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) - static_aggregates = tree_cons (NULL_TREE, var, - static_aggregates); - } - /* Use its address to initialize the reference variable. */ - expr = build_address (var); + /* Take the address of EXPR. */ + expr = build_unary_op (ADDR_EXPR, expr, 0); + /* If a BASE_CONV was required, perform it now. */ if (base_conv_type) - expr = convert_to_base (expr, - build_pointer_type (base_conv_type), - /*check_access=*/true, - /*nonnull=*/true); - expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr); + expr = (perform_implicit_conversion + (build_pointer_type (base_conv_type), expr)); + expr = build_nop (type, expr); } - else - /* Take the address of EXPR. */ - expr = build_unary_op (ADDR_EXPR, expr, 0); - /* If a BASE_CONV was required, perform it now. */ - if (base_conv_type) - expr = (perform_implicit_conversion - (build_pointer_type (base_conv_type), expr)); - expr = build_nop (type, expr); } else /* Perform the conversion. */ expr = convert_like (conv, expr); - + /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 4d8059fc46a..05918f553f9 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6553,9 +6553,22 @@ grokdeclarator (const cp_declarator *declarator, { case BIT_NOT_EXPR: { - tree type = TREE_OPERAND (decl, 0); - type = constructor_name (type); - name = IDENTIFIER_POINTER (type); + tree type; + + if (innermost_code != cdk_function) + { + error ("declaration of %qD as non-function", decl); + return error_mark_node; + } + else if (!qualifying_scope + && !(current_class_type && at_class_scope_p ())) + { + error ("declaration of %qD as non-member", decl); + return error_mark_node; + } + + type = TREE_OPERAND (decl, 0); + name = IDENTIFIER_POINTER (constructor_name (type)); } break; @@ -7803,15 +7816,6 @@ grokdeclarator (const cp_declarator *declarator, int publicp = 0; tree function_context; - /* We catch the others as conflicts with the builtin - typedefs. */ - if (friendp && unqualified_id == ridpointers[(int) RID_SIGNED]) - { - error ("function %qD cannot be declared friend", - unqualified_id); - friendp = 0; - } - if (friendp == 0) { if (ctype == NULL_TREE) @@ -7849,6 +7853,18 @@ grokdeclarator (const cp_declarator *declarator, TYPE_ARG_TYPES (type)); } + /* Check that the name used for a destructor makes sense. */ + if (sfk == sfk_destructor + && !same_type_p (TREE_OPERAND + (id_declarator->u.id.unqualified_name, 0), + ctype)) + { + error ("declaration of %qD as member of %qT", + id_declarator->u.id.unqualified_name, + ctype); + return error_mark_node; + } + /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ function_context = (ctype != NULL_TREE) ? decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6e797532153..f4e8ea28cc1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3173,6 +3173,7 @@ cp_parser_unqualified_id (cp_parser* parser, tree qualifying_scope; tree object_scope; tree scope; + bool done; /* Consume the `~' token. */ cp_lexer_consume_token (parser->lexer); @@ -3229,6 +3230,7 @@ cp_parser_unqualified_id (cp_parser* parser, /* If there was an explicit qualification (S::~T), first look in the scope given by the qualification (i.e., S). */ + done = false; if (scope) { cp_parser_parse_tentatively (parser); @@ -3240,10 +3242,10 @@ cp_parser_unqualified_id (cp_parser* parser, /*class_head_p=*/false, declarator_p); if (cp_parser_parse_definitely (parser)) - return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl)); + done = true; } /* In "N::S::~S", look in "N" as well. */ - if (scope && qualifying_scope) + if (!done && scope && qualifying_scope) { cp_parser_parse_tentatively (parser); parser->scope = qualifying_scope; @@ -3258,10 +3260,10 @@ cp_parser_unqualified_id (cp_parser* parser, /*class_head_p=*/false, declarator_p); if (cp_parser_parse_definitely (parser)) - return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl)); + done = true; } /* In "p->S::~T", look in the scope given by "*p" as well. */ - else if (object_scope) + else if (!done && object_scope) { cp_parser_parse_tentatively (parser); parser->scope = object_scope; @@ -3276,20 +3278,23 @@ cp_parser_unqualified_id (cp_parser* parser, /*class_head_p=*/false, declarator_p); if (cp_parser_parse_definitely (parser)) - return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl)); + done = true; } /* Look in the surrounding context. */ - parser->scope = NULL_TREE; - parser->object_scope = NULL_TREE; - parser->qualifying_scope = NULL_TREE; - type_decl - = cp_parser_class_name (parser, - /*typename_keyword_p=*/false, - /*template_keyword_p=*/false, - none_type, - /*check_dependency=*/false, - /*class_head_p=*/false, - declarator_p); + if (!done) + { + parser->scope = NULL_TREE; + parser->object_scope = NULL_TREE; + parser->qualifying_scope = NULL_TREE; + type_decl + = cp_parser_class_name (parser, + /*typename_keyword_p=*/false, + /*template_keyword_p=*/false, + none_type, + /*check_dependency=*/false, + /*class_head_p=*/false, + declarator_p); + } /* If an error occurred, assume that the name of the destructor is the same as the name of the qualifying class. That allows us to keep parsing after running @@ -11099,7 +11104,17 @@ cp_parser_direct_declarator (cp_parser* parser, &non_constant_p); if (!non_constant_p) bounds = fold_non_dependent_expr (bounds); - else if (!at_function_scope_p ()) + /* Normally, the array bound must be an integral constant + expression. However, as an extension, we allow VLAs + in function scopes. And, we allow type-dependent + expressions in templates; sometimes we don't know for + sure whether or not something is a valid integral + constant expression until instantiation time. (It + doesn't make sense to check for value-dependency, as + an expression is only value-dependent when it is a + constant expression.) */ + else if (!type_dependent_expression_p (bounds) + && !at_function_scope_p ()) { error ("array bound is not an integer constant"); bounds = error_mark_node; @@ -14042,10 +14057,10 @@ cp_parser_attributes_opt (cp_parser* parser) identifier ( identifier , expression-list ) identifier ( expression-list ) - Returns a TREE_LIST. Each node corresponds to an attribute. THe - TREE_PURPOSE of each node is the identifier indicating which - attribute is in use. The TREE_VALUE represents the arguments, if - any. */ + Returns a TREE_LIST, or NULL_TREE on error. Each node corresponds + to an attribute. The TREE_PURPOSE of each node is the identifier + indicating which attribute is in use. The TREE_VALUE represents + the arguments, if any. */ static tree cp_parser_attribute_list (cp_parser* parser) @@ -14063,37 +14078,39 @@ cp_parser_attribute_list (cp_parser* parser) /* Look for the identifier. We also allow keywords here; for example `__attribute__ ((const))' is legal. */ token = cp_lexer_peek_token (parser->lexer); - if (token->type != CPP_NAME - && token->type != CPP_KEYWORD) - return error_mark_node; - /* Consume the token. */ - token = cp_lexer_consume_token (parser->lexer); + if (token->type == CPP_NAME + || token->type == CPP_KEYWORD) + { + /* Consume the token. */ + token = cp_lexer_consume_token (parser->lexer); - /* Save away the identifier that indicates which attribute this is. */ - identifier = token->value; - attribute = build_tree_list (identifier, NULL_TREE); + /* Save away the identifier that indicates which attribute + this is. */ + identifier = token->value; + attribute = build_tree_list (identifier, NULL_TREE); - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); - /* If it's an `(', then parse the attribute arguments. */ - if (token->type == CPP_OPEN_PAREN) - { - tree arguments; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + /* If it's an `(', then parse the attribute arguments. */ + if (token->type == CPP_OPEN_PAREN) + { + tree arguments; - arguments = (cp_parser_parenthesized_expression_list - (parser, true, /*cast_p=*/false, - /*non_constant_p=*/NULL)); - /* Save the identifier and arguments away. */ - TREE_VALUE (attribute) = arguments; - } + arguments = (cp_parser_parenthesized_expression_list + (parser, true, /*cast_p=*/false, + /*non_constant_p=*/NULL)); + /* Save the identifier and arguments away. */ + TREE_VALUE (attribute) = arguments; + } - /* Add this attribute to the list. */ - TREE_CHAIN (attribute) = attribute_list; - attribute_list = attribute; + /* Add this attribute to the list. */ + TREE_CHAIN (attribute) = attribute_list; + attribute_list = attribute; - /* Now, look for more attributes. */ - token = cp_lexer_peek_token (parser->lexer); - /* If the next token isn't a `,', we're done. */ + token = cp_lexer_peek_token (parser->lexer); + } + /* Now, look for more attributes. If the next token isn't a + `,', we're done. */ if (token->type != CPP_COMMA) break; |