From 2050a1bbac14451de357a7d78ffdc6621f49ab30 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 10 Jan 2003 20:30:56 +0000 Subject: [PATCH] re PR c++/9128 (Typeid does not work on polymorphic classes) PR c++/9128 * g++.dg/rtti/typeid1.C: New file. PR c++/9153 * g++.dg/parse/lookup1.C: New file. PR c++/9171 * g++.dg/templ/spec5.C: New file. * cp-tree.h (reparse_absdcl_as_expr): Remove. (reparse_absdcl_as_casts): Likewise. (reparse_decl_as_expr): Likewise. (finish_decl_parsing): Likewise. * decl2.c (reparse_absdcl_as_expr): Remove. (reparse_absdcl_as_casts): Likewise. (repase_decl_as_expr): Likewise. (finish_decl_parsing): Likewise. PR c++/9128 PR c++/9153 PR c++/9171 * parser.c (cp_parser_pre_parsed_nested_name_specifier): New function. (cp_parser_nested_name_specifier_opt): Correct the check_dependency_p false. (cp_parser_postfix_expression): Fix formatting. (cp_parser_decl_specifier_seq): Avoid looking for constructor declarators when possible. (cp_parser_template_id): Avoid performing name-lookup when possible. (cp_parser_class_head): Do not count specializations when counting levels of templates. (cp_parser_constructor_declarator_p): Return immediately if there's no chance that the tokens form a constructor declarator. * rtti.c (throw_bad_typeid): Add comment. Do not return an expression with reference type. (get_tinfo_decl_dynamic): Do not return an expression with reference type. (build_typeid): Add comment. Do not return an expression with reference type. * typeck.c (build_class_member_access_expr): Improve handling of conditionals and comma-expressions as objects. From-SVN: r61166 --- gcc/cp/ChangeLog | 36 +++++++ gcc/cp/cp-tree.h | 4 - gcc/cp/decl2.c | 129 ----------------------- gcc/cp/parser.c | 142 +++++++++++++++++--------- gcc/cp/rtti.c | 26 +++-- gcc/cp/typeck.c | 49 +++++---- gcc/testsuite/ChangeLog | 11 ++ gcc/testsuite/g++.dg/parse/lookup1.C | 9 ++ gcc/testsuite/g++.dg/rtti/typeid1.C | 11 ++ gcc/testsuite/g++.dg/template/spec5.C | 3 + 10 files changed, 208 insertions(+), 212 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/lookup1.C create mode 100644 gcc/testsuite/g++.dg/rtti/typeid1.C create mode 100644 gcc/testsuite/g++.dg/template/spec5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 696391d3921..6ea43a423d4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,39 @@ +2003-01-10 Mark Mitchell + + * cp-tree.h (reparse_absdcl_as_expr): Remove. + (reparse_absdcl_as_casts): Likewise. + (reparse_decl_as_expr): Likewise. + (finish_decl_parsing): Likewise. + * decl2.c (reparse_absdcl_as_expr): Remove. + (reparse_absdcl_as_casts): Likewise. + (repase_decl_as_expr): Likewise. + (finish_decl_parsing): Likewise. + + PR c++/9128 + PR c++/9153 + PR c++/9171 + * parser.c (cp_parser_pre_parsed_nested_name_specifier): New + function. + (cp_parser_nested_name_specifier_opt): Correct the + check_dependency_p false. + (cp_parser_postfix_expression): Fix formatting. + (cp_parser_decl_specifier_seq): Avoid looking for constructor + declarators when possible. + (cp_parser_template_id): Avoid performing name-lookup when + possible. + (cp_parser_class_head): Do not count specializations when counting + levels of templates. + (cp_parser_constructor_declarator_p): Return immediately if + there's no chance that the tokens form a constructor declarator. + * rtti.c (throw_bad_typeid): Add comment. Do not return an + expression with reference type. + (get_tinfo_decl_dynamic): Do not return an expression with + reference type. + (build_typeid): Add comment. Do not return an expression with + reference type. + * typeck.c (build_class_member_access_expr): Improve handling of + conditionals and comma-expressions as objects. + 2003-01-09 Nathanael Nerode * decl.c (bad_specifiers): Fix parameter order error I introduced. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index aad82c019b2..46fd5b1c351 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3865,13 +3865,9 @@ extern void import_export_decl (tree); extern void import_export_tinfo (tree, tree, bool); extern tree build_cleanup PARAMS ((tree)); extern void finish_file PARAMS ((void)); -extern tree reparse_absdcl_as_expr PARAMS ((tree, tree)); -extern tree reparse_absdcl_as_casts PARAMS ((tree, tree)); extern tree build_expr_from_tree PARAMS ((tree)); extern tree build_offset_ref_call_from_tree (tree, tree); extern tree build_call_from_tree (tree, tree, bool); -extern tree reparse_decl_as_expr (tree, tree); -extern tree finish_decl_parsing (tree); extern void set_decl_namespace (tree, tree, bool); extern tree current_decl_namespace PARAMS ((void)); extern void push_decl_namespace PARAMS ((tree)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2491c8a3979..47b841cbd3b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2876,79 +2876,6 @@ finish_file () } } -/* This is something of the form 'A()()()()()+1' that has turned out to be an - expr. Since it was parsed like a type, we need to wade through and fix - that. Unfortunately, since operator() is left-associative, we can't use - tail recursion. In the above example, TYPE is `A', and DECL is - `()()()()()'. - - Maybe this shouldn't be recursive, but how often will it actually be - used? (jason) */ - -tree -reparse_absdcl_as_expr (type, decl) - tree type, decl; -{ - /* do build_functional_cast (type, NULL_TREE) at bottom */ - if (TREE_OPERAND (decl, 0) == NULL_TREE) - return build_functional_cast (type, NULL_TREE); - - /* recurse */ - decl = reparse_absdcl_as_expr (type, TREE_OPERAND (decl, 0)); - - return finish_call_expr (decl, NULL_TREE, /*disallow_virtual=*/false); -} - -/* This is something of the form `int ((int)(int)(int)1)' that has turned - out to be an expr. Since it was parsed like a type, we need to wade - through and fix that. Since casts are right-associative, we are - reversing the order, so we don't have to recurse. - - In the above example, DECL is the `(int)(int)(int)', and EXPR is the - `1'. */ - -tree -reparse_absdcl_as_casts (decl, expr) - tree decl, expr; -{ - tree type; - int non_void_p = 0; - - if (TREE_CODE (expr) == CONSTRUCTOR - && TREE_TYPE (expr) == 0) - { - type = groktypename (TREE_VALUE (CALL_DECLARATOR_PARMS (decl))); - decl = TREE_OPERAND (decl, 0); - - if (processing_template_decl) - TREE_TYPE (expr) = type; - else - { - expr = digest_init (type, expr, (tree *) 0); - if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) - { - int failure = complete_array_type (type, expr, 1); - my_friendly_assert (!failure, 78); - } - } - } - - while (decl) - { - type = groktypename (TREE_VALUE (CALL_DECLARATOR_PARMS (decl))); - decl = TREE_OPERAND (decl, 0); - if (!VOID_TYPE_P (type)) - non_void_p = 1; - expr = build_c_cast (type, expr); - } - - if (warn_old_style_cast && ! in_system_header - && non_void_p && current_lang_name != lang_name_c) - warning ("use of old-style cast"); - - return expr; -} - /* T is the parse tree for an expression. Return the expression after performing semantic analysis. */ @@ -3461,62 +3388,6 @@ build_call_from_tree (tree fn, tree args, bool disallow_virtual) return finish_call_expr (fn, args, disallow_virtual); } -/* This is something of the form `int (*a)++' that has turned out to be an - expr. It was only converted into parse nodes, so we need to go through - and build up the semantics. Most of the work is done by - build_expr_from_tree, above. - - In the above example, TYPE is `int' and DECL is `*a'. */ - -tree -reparse_decl_as_expr (tree type, tree decl) -{ - decl = build_expr_from_tree (decl); - if (type) - return build_functional_cast (type, build_tree_list (NULL_TREE, decl)); - else - return decl; -} - -/* This is something of the form `int (*a)' that has turned out to be a - decl. It was only converted into parse nodes, so we need to do the - checking that make_{pointer,reference}_declarator do. */ - -tree -finish_decl_parsing (tree decl) -{ - switch (TREE_CODE (decl)) - { - case IDENTIFIER_NODE: - return decl; - case INDIRECT_REF: - return make_pointer_declarator - (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0))); - case ADDR_EXPR: - return make_reference_declarator - (NULL_TREE, finish_decl_parsing (TREE_OPERAND (decl, 0))); - case BIT_NOT_EXPR: - TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0)); - return decl; - case SCOPE_REF: - push_nested_class (TREE_TYPE (TREE_OPERAND (decl, 0)), 3); - TREE_COMPLEXITY (decl) = current_class_depth; - return decl; - case ARRAY_REF: - TREE_OPERAND (decl, 0) = finish_decl_parsing (TREE_OPERAND (decl, 0)); - return decl; - case TREE_LIST: - /* For attribute handling. */ - TREE_VALUE (decl) = finish_decl_parsing (TREE_VALUE (decl)); - return decl; - case TEMPLATE_ID_EXPR: - return decl; - default: - abort (); - return NULL_TREE; - } -} - /* Return 1 if root encloses child. */ static bool diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 629ba5d8178..d626939e281 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1764,6 +1764,8 @@ static void cp_parser_check_class_key (enum tag_types, tree type); static bool cp_parser_optional_template_keyword (cp_parser *); +static void cp_parser_pre_parsed_nested_name_specifier + (cp_parser *); static void cp_parser_cache_group (cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned); static void cp_parser_parse_tentatively @@ -3091,15 +3093,6 @@ cp_parser_primary_expression (cp_parser *parser, function does not do this in order to avoid wastefully creating SCOPE_REFs when they are not required. - If ASSUME_TYPENAME_P is true then we assume that qualified names - are typenames. This flag is set when parsing a declarator-id; - for something like: - - template - int S::R::i = 3; - - we are supposed to assume that `S::R' is a class. - If TEMPLATE_KEYWORD_P is true, then we have just seen the `template' keyword. @@ -3460,25 +3453,19 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, bool success = false; tree access_check = NULL_TREE; ptrdiff_t start; + cp_token* token; /* If the next token corresponds to a nested name specifier, there - is no need to reparse it. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER)) + is no need to reparse it. However, if CHECK_DEPENDENCY_P is + false, it may have been true before, in which case something + like `A::B::C' may have resulted in a nested-name-specifier + of `A::', where it should now be `A::B::'. So, when + CHECK_DEPENDENCY_P is false, we have to fall through into the + main loop. */ + if (check_dependency_p + && cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER)) { - tree value; - tree check; - - /* Get the stored value. */ - value = cp_lexer_consume_token (parser->lexer)->value; - /* Perform any access checks that were deferred. */ - for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check)) - cp_parser_defer_access_check (parser, - TREE_PURPOSE (check), - TREE_VALUE (check)); - /* Set the scope from the stored value. */ - parser->scope = TREE_VALUE (value); - parser->qualifying_scope = TREE_TYPE (value); - parser->object_scope = NULL_TREE; + cp_parser_pre_parsed_nested_name_specifier (parser); return parser->scope; } @@ -3486,10 +3473,10 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, if (cp_parser_parsing_tentatively (parser) && !cp_parser_committed_to_tentative_parse (parser)) { - cp_token *next_token = cp_lexer_peek_token (parser->lexer); + token = cp_lexer_peek_token (parser->lexer); start = cp_lexer_token_difference (parser->lexer, parser->lexer->first_token, - next_token); + token); access_check = parser->context->deferred_access_checks; } else @@ -3500,13 +3487,25 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, tree new_scope; tree old_scope; tree saved_qualifying_scope; - cp_token *token; bool template_keyword_p; + /* Spot cases that cannot be the beginning of a + nested-name-specifier. */ + token = cp_lexer_peek_token (parser->lexer); + + /* If the next token is CPP_NESTED_NAME_SPECIFIER, just process + the already parsed nested-name-specifier. */ + if (token->type == CPP_NESTED_NAME_SPECIFIER) + { + /* Grab the nested-name-specifier and continue the loop. */ + cp_parser_pre_parsed_nested_name_specifier (parser); + success = true; + continue; + } + /* Spot cases that cannot be the beginning of a nested-name-specifier. On the second and subsequent times through the loop, we look for the `template' keyword. */ - token = cp_lexer_peek_token (parser->lexer); if (success && token->keyword == RID_TEMPLATE) ; /* A template-id can start a nested-name-specifier. */ @@ -3631,7 +3630,6 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, we issue duplicate error messages. */ if (success && start >= 0) { - cp_token *token; tree c; /* Find the token that corresponds to the start of the @@ -4232,20 +4230,16 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) postfix_expression = (build_offset_ref_call_from_tree (postfix_expression, args)); else if (idk == CP_PARSER_ID_KIND_QUALIFIED) - { - /* A call to a static class member, or a - namespace-scope function. */ - postfix_expression - = finish_call_expr (postfix_expression, args, - /*disallow_virtual=*/true); - } + /* A call to a static class member, or a namespace-scope + function. */ + postfix_expression + = finish_call_expr (postfix_expression, args, + /*disallow_virtual=*/true); else - { - /* All other function calls. */ - postfix_expression - = finish_call_expr (postfix_expression, args, - /*disallow_virtual=*/false); - } + /* All other function calls. */ + postfix_expression + = finish_call_expr (postfix_expression, args, + /*disallow_virtual=*/false); /* The POSTFIX_EXPRESSION is certainly no longer an id. */ idk = CP_PARSER_ID_KIND_NONE; @@ -6903,6 +6897,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, { tree decl_specs = NULL_TREE; bool friend_p = false; + bool constructor_possible_p = true; /* Assume no class or enumeration type is declared. */ *declares_class_or_enum = false; @@ -6961,6 +6956,8 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, decl_spec = token->value; /* Consume the token. */ cp_lexer_consume_token (parser->lexer); + /* A constructor declarator cannot appear in a typedef. */ + constructor_possible_p = false; break; /* storage-class-specifier: @@ -6988,6 +6985,7 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, /* Constructors are a special case. The `S' in `S()' is not a decl-specifier; it is the beginning of the declarator. */ constructor_p = (!decl_spec + && constructor_possible_p && cp_parser_constructor_declarator_p (parser, friend_p)); @@ -7045,6 +7043,9 @@ cp_parser_decl_specifier_seq (parser, flags, attributes, error message later. */ if (decl_spec && !is_cv_qualifier) flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; + /* A constructor declarator cannot follow a type-specifier. */ + if (decl_spec) + constructor_possible_p = false; } /* If we still do not have a DECL_SPEC, then there are no more @@ -8102,10 +8103,12 @@ cp_parser_template_id (cp_parser *parser, bool saved_greater_than_is_operator_p; ptrdiff_t start_of_id; tree access_check = NULL_TREE; + cp_token *next_token; /* If the next token corresponds to a template-id, there is no need to reparse it. */ - if (cp_lexer_next_token_is (parser->lexer, CPP_TEMPLATE_ID)) + next_token = cp_lexer_peek_token (parser->lexer); + if (next_token->type == CPP_TEMPLATE_ID) { tree value; tree check; @@ -8121,11 +8124,21 @@ cp_parser_template_id (cp_parser *parser, return TREE_VALUE (value); } + /* Avoid performing name lookup if there is no possibility of + finding a template-id. */ + if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR) + || (next_token->type == CPP_NAME + && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS)) + { + cp_parser_error (parser, "expected template-id"); + return error_mark_node; + } + /* Remember where the template-id starts. */ if (cp_parser_parsing_tentatively (parser) && !cp_parser_committed_to_tentative_parse (parser)) { - cp_token *next_token = cp_lexer_peek_token (parser->lexer); + next_token = cp_lexer_peek_token (parser->lexer); start_of_id = cp_lexer_token_difference (parser->lexer, parser->lexer->first_token, next_token); @@ -10177,7 +10190,7 @@ cp_parser_direct_declarator (parser, dcl_kind, ctor_dtor_or_conv_p) { /* This is either a parameter-declaration-clause, or a parenthesized declarator. When we know we are parsing a - named declaratory, it must be a paranthesized declarator + named declarator, it must be a paranthesized declarator if FIRST is true. For instance, `(int)' is a parameter-declaration-clause, with an omitted direct-abstract-declarator. But `((*))', is a @@ -11851,7 +11864,7 @@ cp_parser_class_head (parser, Handle this gracefully by accepting the extra qualifier, and then issuing an error about it later if this really is a - class-header. If it turns out just to be an elaborated type + class-head. If it turns out just to be an elaborated type specifier, remain silent. */ if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)) qualified_p = true; @@ -11920,7 +11933,8 @@ cp_parser_class_head (parser, if (TYPE_P (scope) && CLASS_TYPE_P (scope) && CLASSTYPE_TEMPLATE_INFO (scope) - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)) + && !CLASSTYPE_TEMPLATE_SPECIALIZATION (scope)) ++num_templates; } } @@ -13983,6 +13997,16 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) bool constructor_p; tree type_decl = NULL_TREE; bool nested_name_p; + cp_token *next_token; + + /* The common case is that this is not a constructor declarator, so + try to avoid doing lots of work if at all possible. */ + next_token = cp_lexer_peek_token (parser->lexer); + if (next_token->type != CPP_NAME + && next_token->type != CPP_SCOPE + && next_token->type != CPP_NESTED_NAME_SPECIFIER + && next_token->type != CPP_TEMPLATE_ID) + return false; /* Parse tentatively; we are going to roll back all of the tokens consumed here. */ @@ -14830,6 +14854,28 @@ cp_parser_optional_template_keyword (cp_parser *parser) return false; } +/* The next token is a CPP_NESTED_NAME_SPECIFIER. Consume the token, + set PARSER->SCOPE, and perform other related actions. */ + +static void +cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser) +{ + tree value; + tree check; + + /* Get the stored value. */ + value = cp_lexer_consume_token (parser->lexer)->value; + /* Perform any access checks that were deferred. */ + for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check)) + cp_parser_defer_access_check (parser, + TREE_PURPOSE (check), + TREE_VALUE (check)); + /* Set the scope from the stored value. */ + parser->scope = TREE_VALUE (value); + parser->qualifying_scope = TREE_TYPE (value); + parser->object_scope = NULL_TREE; +} + /* Add tokens to CACHE until an non-nested END token appears. */ static void diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index d89f13332d7..71b8e34b199 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -174,6 +174,9 @@ throw_bad_cast (void) return build_call (fn, NULL_TREE); } +/* Return an expression for "__cxa_bad_typeid()". The expression + returned is an lvalue of type "const std::type_info". */ + static tree throw_bad_typeid (void) { @@ -187,17 +190,19 @@ throw_bad_typeid (void) fn = push_throw_library_fn (fn, t); } - return build_call (fn, NULL_TREE); + return convert_from_reference (build_call (fn, NULL_TREE)); } -/* Return a pointer to type_info function associated with the expression EXP. - If EXP is a reference to a polymorphic class, return the dynamic type; +/* Return an lvalue expression whose type is "const std::type_info" + and whose value indicates the type of the expression EXP. If EXP + is a reference to a polymorphic class, return the dynamic type; otherwise return the static type of the expression. */ static tree get_tinfo_decl_dynamic (tree exp) { tree type; + tree t; if (exp == error_mark_node) return error_mark_node; @@ -221,18 +226,18 @@ get_tinfo_decl_dynamic (tree exp) if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0)) { /* build reference to type_info from vtable. */ - tree t; tree index; /* The RTTI information is at index -1. */ index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1); t = build_vtbl_ref (exp, index); TREE_TYPE (t) = type_info_ptr_type; - return t; } + else + /* Otherwise return the type_info for the static type of the expr. */ + t = get_tinfo_ptr (TYPE_MAIN_VARIANT (type)); - /* Otherwise return the type_info for the static type of the expr. */ - return get_tinfo_ptr (TYPE_MAIN_VARIANT (type)); + return build_indirect_ref (t, NULL); } static bool @@ -253,6 +258,9 @@ typeid_ok_p (void) return true; } +/* Return an expression for "typeid(EXP)". The expression returned is + an lvalue of type "const std::type_info". */ + tree build_typeid (tree exp) { @@ -280,8 +288,6 @@ build_typeid (tree exp) if (exp == error_mark_node) return error_mark_node; - exp = build_indirect_ref (exp, NULL); - if (cond) { tree bad = throw_bad_typeid (); @@ -289,7 +295,7 @@ build_typeid (tree exp) exp = build (COND_EXPR, TREE_TYPE (exp), cond, exp, bad); } - return convert_from_reference (exp); + return exp; } /* Generate the NTBS name of a type. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dd7c26bd8f6..e7921c55e10 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1865,27 +1865,6 @@ build_class_member_access_expr (tree object, tree member, my_friendly_assert (DECL_P (member) || BASELINK_P (member), 20020801); - /* Transform `(a, b).x' into `a, b.x' and `(a ? b : c).x' into - `a ? b.x : c.x'. These transformations should not really be - necessary, but they are. */ - if (TREE_CODE (object) == COMPOUND_EXPR) - { - result = build_class_member_access_expr (TREE_OPERAND (object, 1), - member, access_path, - preserve_reference); - return build (COMPOUND_EXPR, TREE_TYPE (result), - TREE_OPERAND (object, 0), result); - } - else if (TREE_CODE (object) == COND_EXPR) - return (build_conditional_expr - (TREE_OPERAND (object, 0), - build_class_member_access_expr (TREE_OPERAND (object, 1), - member, access_path, - preserve_reference), - build_class_member_access_expr (TREE_OPERAND (object, 2), - member, access_path, - preserve_reference))); - /* [expr.ref] The type of the first expression shall be "class object" (of a @@ -1925,6 +1904,34 @@ build_class_member_access_expr (tree object, tree member, return error_mark_node; } + /* Transform `(a, b).x' into `(*(a, &b)).x' and `(a ? b : c).x' into + `(*(a ? &b : &c)).x'. Unfortunately, expand_expr cannot handle a + COMPONENT_REF where the first operand is a conditional or comma + expression with class type. */ + if (TREE_CODE (object) == COMPOUND_EXPR) + { + object = build (COMPOUND_EXPR, + build_pointer_type (object_type), + TREE_OPERAND (object, 0), + build_unary_op (ADDR_EXPR, + TREE_OPERAND (object, 1), + /*noconvert=*/1)); + object = build_indirect_ref (object, NULL); + } + else if (TREE_CODE (object) == COND_EXPR) + { + object = build (COND_EXPR, + build_pointer_type (object_type), + TREE_OPERAND (object, 0), + build_unary_op (ADDR_EXPR, + TREE_OPERAND (object, 1), + /*noconvert=*/1), + build_unary_op (ADDR_EXPR, + TREE_OPERAND (object, 2), + /*noconvert=*/1)); + object = build_indirect_ref (object, NULL); + } + /* In [expr.ref], there is an explicit list of the valid choices for MEMBER. We check for each of those cases here. */ if (TREE_CODE (member) == VAR_DECL) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f71130fe65c..e642d44faa5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2003-01-10 Mark Mitchell + + PR c++/9128 + * g++.dg/rtti/typeid1.C: New file. + + PR c++/9153 + * g++.dg/parse/lookup1.C: New file. + + PR c++/9171 + * g++.dg/templ/spec5.C: New file. + 2003-01-10 Josef Zlomek * gcc.c-torture/compile/20030110-1.c: New test. diff --git a/gcc/testsuite/g++.dg/parse/lookup1.C b/gcc/testsuite/g++.dg/parse/lookup1.C new file mode 100644 index 00000000000..0325d3c6926 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/lookup1.C @@ -0,0 +1,9 @@ +#include + +using namespace std; + +template +class new_list : public list { +public: + typedef typename list::iterator iterator; +}; diff --git a/gcc/testsuite/g++.dg/rtti/typeid1.C b/gcc/testsuite/g++.dg/rtti/typeid1.C new file mode 100644 index 00000000000..e26517576b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/rtti/typeid1.C @@ -0,0 +1,11 @@ +#include + +struct A { + virtual ~A() {} +}; + +int main() { + A* a = new A; + typeid(*a).name(); +} + diff --git a/gcc/testsuite/g++.dg/template/spec5.C b/gcc/testsuite/g++.dg/template/spec5.C new file mode 100644 index 00000000000..ad101b01d6a --- /dev/null +++ b/gcc/testsuite/g++.dg/template/spec5.C @@ -0,0 +1,3 @@ +template struct A; +template <> struct A<0> { struct B; }; +struct A<0>::B {};