From 429b876b0784f5f4406eadf56115a8b4c20e874d Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Fri, 1 Sep 2006 13:46:19 +0000 Subject: [PATCH] re PR c++/23287 (Explicitly invoking destructor of template class in a template and is dependent) cp/ PR c++/23287 * parser.c (cp_parser_id_expression): Add member_p argument. Update all callers. (cp_parser_unqualified_id): Likewise. Lookup a destructor name in the object's scope, if valid. (cp_parser_global_scope_opt): Add object_scope_valid_p. Update callers. (cp_parser_postfix_dot_deref_expression): Set object_scope. * pt.c (tsubst_copy_and_build): Lookup dependent dtor name here. testsuite/ PR c++/23287 * g++.dg/parse/dtor12.C: New. From-SVN: r116623 --- gcc/cp/ChangeLog | 12 +++ gcc/cp/parser.c | 149 ++++++++++++++++++++-------- gcc/cp/pt.c | 8 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/g++.dg/parse/dtor12.C | 15 +++ 5 files changed, 147 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/dtor12.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5311778db8bd..bb2e8415f3ae 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2006-09-01 Nathan Sidwell + + PR c++/23287 + * parser.c (cp_parser_id_expression): Add member_p + argument. Update all callers. + (cp_parser_unqualified_id): Likewise. Lookup a destructor name in + the object's scope, if valid. + (cp_parser_global_scope_opt): Add object_scope_valid_p. Update + callers. + (cp_parser_postfix_dot_deref_expression): Set object_scope. + * pt.c (tsubst_copy_and_build): Lookup dependent dtor name here. + 2006-08-30 Jason Merrill PR c++/26670 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 5271113485a7..2e2885691023 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1393,9 +1393,9 @@ static bool cp_parser_translation_unit static tree cp_parser_primary_expression (cp_parser *, bool, bool, bool, cp_id_kind *); static tree cp_parser_id_expression - (cp_parser *, bool, bool, bool *, bool, bool); + (cp_parser *, bool, bool, bool *, bool, bool, bool); static tree cp_parser_unqualified_id - (cp_parser *, bool, bool, bool, bool); + (cp_parser *, bool, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier_opt (cp_parser *, bool, bool, bool, bool); static tree cp_parser_nested_name_specifier @@ -1720,7 +1720,7 @@ static bool cp_parser_check_template_parameters static tree cp_parser_simple_cast_expression (cp_parser *); static tree cp_parser_global_scope_opt - (cp_parser *, bool); + (cp_parser *, bool, bool); static bool cp_parser_constructor_declarator_p (cp_parser *, bool); static tree cp_parser_function_definition_from_specifiers_and_declarator @@ -2182,7 +2182,8 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser) /*check_dependency_p=*/true, /*template_p=*/NULL, /*declarator_p=*/true, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); /* After the id-expression, there should be a plain identifier, otherwise this is not a simple variable declaration. Also, if the scope is dependent, we cannot do much. */ @@ -3061,7 +3062,8 @@ cp_parser_primary_expression (cp_parser *parser, /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); if (id_expression == error_mark_node) return error_mark_node; token = cp_lexer_peek_token (parser->lexer); @@ -3195,7 +3197,8 @@ cp_parser_id_expression (cp_parser *parser, bool check_dependency_p, bool *template_p, bool declarator_p, - bool optional_p) + bool optional_p, + bool member_p) { bool global_scope_p; bool nested_name_specifier_p; @@ -3206,8 +3209,10 @@ cp_parser_id_expression (cp_parser *parser, /* Look for the optional `::' operator. */ global_scope_p - = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false) + = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/member_p) != NULL_TREE); + /* Look for the optional nested-name-specifier. */ nested_name_specifier_p = (cp_parser_nested_name_specifier_opt (parser, @@ -3239,7 +3244,8 @@ cp_parser_id_expression (cp_parser *parser, unqualified_id = cp_parser_unqualified_id (parser, *template_p, check_dependency_p, declarator_p, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); /* Restore the SAVED_SCOPE for our caller. */ parser->scope = saved_scope; parser->object_scope = saved_object_scope; @@ -3297,8 +3303,7 @@ cp_parser_id_expression (cp_parser *parser, else return cp_parser_unqualified_id (parser, template_keyword_p, /*check_dependency_p=*/true, - declarator_p, - optional_p); + declarator_p, optional_p, member_p); } /* Parse an unqualified-id. @@ -3328,7 +3333,8 @@ cp_parser_unqualified_id (cp_parser* parser, bool template_keyword_p, bool check_dependency_p, bool declarator_p, - bool optional_p) + bool optional_p, + bool member_p) { cp_token *token; @@ -3456,6 +3462,7 @@ cp_parser_unqualified_id (cp_parser* parser, if (cp_parser_parse_definitely (parser)) done = true; } + /* In "N::S::~S", look in "N" as well. */ if (!done && scope && qualifying_scope) { @@ -3474,24 +3481,56 @@ cp_parser_unqualified_id (cp_parser* parser, if (cp_parser_parse_definitely (parser)) done = true; } - /* In "p->S::~T", look in the scope given by "*p" as well. */ - else if (!done && object_scope) + /* In "p->~T", look in the scope given by "*p" as well. */ + else if (!done && member_p) { + if (!object_scope) + { + /* It's a dependent expression, so just parse the + dtor name. */ + tree id; + + if (template_keyword_p) + /* It's a template-id. */ + id = cp_parser_template_id (parser, true, + check_dependency_p, + declarator_p); + else + { + /* Otherwise, it's an ordinary identifier. */ + id = cp_parser_identifier (parser); + /* If ID is a template type parm, then use that + directly. */ + if (TREE_TYPE (id) + && TREE_CODE (TREE_TYPE (id)) == TEMPLATE_TYPE_PARM) + id = TREE_TYPE (id); + } + + if (id != error_mark_node) + id = build_nt (BIT_NOT_EXPR, id); + return id; + } + cp_parser_parse_tentatively (parser); parser->scope = object_scope; parser->object_scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; type_decl = cp_parser_class_name (parser, - /*typename_keyword_p=*/false, + /*typename_keyword_p=*/false, /*template_keyword_p=*/false, none_type, /*check_dependency=*/false, /*class_head_p=*/false, declarator_p); + /* The name is not qualified, so reset the parser scopes + so our callers do not get confused. */ + parser->object_scope = object_scope; + parser->scope = NULL_TREE; if (cp_parser_parse_definitely (parser)) done = true; } + /* Look in the surrounding context. */ if (!done) { @@ -4482,11 +4521,12 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; *idk = CP_ID_KIND_NONE; + /* Enter the scope corresponding to the type of the object given by the POSTFIX_EXPRESSION. */ - if (!dependent_p && TREE_TYPE (postfix_expression) != NULL_TREE) + scope = TREE_TYPE (postfix_expression); + if (!dependent_p && scope) { - scope = TREE_TYPE (postfix_expression); /* According to the standard, no expression should ever have reference type. Unfortunately, we do not currently match the standard in this respect in that our internal representation @@ -4500,11 +4540,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, error ("%qE does not have class type", postfix_expression); scope = NULL_TREE; } - else + else if (!dependent_p) scope = complete_type_or_else (scope, NULL_TREE); - /* Let the name lookup machinery know that we are processing a - class member access expression. */ - parser->context->object_type = scope; /* If something went wrong, we want to be able to discern that case, as opposed to the case where there was no SCOPE due to the type of expression being dependent. */ @@ -4516,6 +4553,10 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, if (scope == error_mark_node) postfix_expression = error_mark_node; } + /* Let the name lookup machinery know that we are processing a class + member access expression. */ + parser->context->object_type = scope; + parser->object_scope = scope; /* Assume this expression is not a pseudo-destructor access. */ pseudo_destructor_p = false; @@ -4553,7 +4594,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false)); + /*optional_p=*/false, + /*member_p=*/true)); /* In general, build a SCOPE_REF if the member name is qualified. However, if the name was not dependent and has already been resolved; there is no need to build the SCOPE_REF. For example; @@ -4758,7 +4800,9 @@ cp_parser_pseudo_destructor_name (cp_parser* parser, *type = error_mark_node; /* Look for the optional `::' operator. */ - cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true); + cp_parser_global_scope_opt (parser, + /*current_scope_valid_p=*/true, + /*object_scop_valid_p=*/true); /* Look for the optional nested-name-specifier. */ nested_name_specifier_p = (cp_parser_nested_name_specifier_opt (parser, @@ -5069,7 +5113,8 @@ cp_parser_new_expression (cp_parser* parser) /* Look for the optional `::' operator. */ global_scope_p = (cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false) + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false) != NULL_TREE); /* Look for the `new' operator. */ cp_parser_require_keyword (parser, RID_NEW, "`new'"); @@ -5367,7 +5412,8 @@ cp_parser_delete_expression (cp_parser* parser) /* Look for the optional `::' operator. */ global_scope_p = (cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false) + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false) != NULL_TREE); /* Look for the `delete' keyword. */ cp_parser_require_keyword (parser, RID_DELETE, "`delete'"); @@ -8022,7 +8068,8 @@ cp_parser_mem_initializer_id (cp_parser* parser) /* Look for the optional `::' operator. */ global_scope_p = (cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false) + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false) != NULL_TREE); /* Look for the optional nested-name-specifier. The simplest way to implement: @@ -8594,7 +8641,8 @@ cp_parser_type_parameter (cp_parser* parser) /*check_dependency_p=*/true, /*template_p=*/&is_template, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); if (TREE_CODE (default_argument) == TYPE_DECL) /* If the id-expression was a template-id that refers to a template-class, we already have the declaration here, @@ -9159,7 +9207,8 @@ cp_parser_template_argument (cp_parser* parser) /*check_dependency_p=*/true, &template_p, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); /* If the next token isn't a `,' or a `>', then this argument wasn't really finished. */ if (!cp_parser_next_token_ends_template_argument_p (parser)) @@ -9799,7 +9848,8 @@ cp_parser_simple_type_specifier (cp_parser* parser, /* Look for the optional `::' operator. */ global_p = (cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false) + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false) != NULL_TREE); /* Look for the nested-name specifier. */ qualified_p @@ -10024,7 +10074,8 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, /* Look for the `::' operator. */ cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false); + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* Look for the nested-name-specifier. */ if (tag_type == typename_type) { @@ -10559,7 +10610,8 @@ cp_parser_qualified_namespace_specifier (cp_parser* parser) { /* Look for the optional `::'. */ cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false); + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* Look for the optional nested-name-specifier. */ cp_parser_nested_name_specifier_opt (parser, @@ -10604,7 +10656,8 @@ cp_parser_using_declaration (cp_parser* parser) /* Look for the optional global scope qualification. */ global_scope_p = (cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false) + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false) != NULL_TREE); /* If we saw `typename', or didn't see `::', then there must be a @@ -10630,7 +10683,8 @@ cp_parser_using_declaration (cp_parser* parser) /*template_keyword_p=*/false, /*check_dependency_p=*/true, /*declarator_p=*/true, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); /* The function we call to handle a using-declaration is different depending on what scope we are in. */ @@ -10684,7 +10738,8 @@ cp_parser_using_directive (cp_parser* parser) /* And the `namespace' keyword. */ cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'"); /* Look for the optional `::' operator. */ - cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); + cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* And the optional nested-name-specifier. */ cp_parser_nested_name_specifier_opt (parser, /*typename_keyword_p=*/false, @@ -11752,7 +11807,8 @@ cp_parser_ptr_operator (cp_parser* parser, cp_parser_parse_tentatively (parser); /* Look for the optional `::' operator. */ cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false); + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* Look for the nested-name specifier. */ cp_parser_nested_name_specifier (parser, /*typename_keyword_p=*/false, @@ -11892,7 +11948,8 @@ cp_parser_declarator_id (cp_parser* parser, bool optional_p) /*check_dependency_p=*/false, /*template_p=*/NULL, /*declarator_p=*/true, - optional_p); + optional_p, + /*member_p=*/false); if (id && BASELINK_P (id)) id = BASELINK_FUNCTIONS (id); return id; @@ -13097,7 +13154,8 @@ cp_parser_class_head (cp_parser* parser, issuing an error about it later if this really is a 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)) + if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false)) qualified_p = true; push_deferring_access_checks (dk_no_check); @@ -14083,7 +14141,8 @@ cp_parser_base_specifier (cp_parser* parser) } /* Look for the optional `::' operator. */ - cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); + cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* Look for the nested-name-specifier. The simplest way to implement: @@ -15132,7 +15191,8 @@ cp_parser_check_template_parameters (cp_parser* parser, present, and NULL_TREE otherwise. */ static tree -cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p) +cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p, + bool object_scope_valid_p) { cp_token *token; @@ -15151,12 +15211,15 @@ cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p) return parser->scope; } - else if (!current_scope_valid_p) + + if (!current_scope_valid_p) { parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; - parser->object_scope = NULL_TREE; } + + if (!object_scope_valid_p) + parser->object_scope = NULL_TREE; return NULL_TREE; } @@ -15194,7 +15257,8 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) /* Look for the optional `::' operator. */ cp_parser_global_scope_opt (parser, - /*current_scope_valid_p=*/false); + /*current_scope_valid_p=*/false, + /*object_scope_valid_p=*/false); /* Look for the nested-name-specifier. */ nested_name_p = (cp_parser_nested_name_specifier_opt (parser, @@ -17901,7 +17965,8 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, /*check_dependency_p=*/true, /*template_p=*/NULL, /*declarator_p=*/false, - /*optional_p=*/false); + /*optional_p=*/false, + /*member_p=*/false); if (name == error_mark_node) goto skip_comma; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 79d9de4e4ce7..c8081f65fb2b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9200,6 +9200,14 @@ tsubst_copy_and_build (tree t, member = tsubst_baselink (member, non_reference (TREE_TYPE (object)), args, complain, in_decl); + else if (TREE_CODE (member) == BIT_NOT_EXPR + && !TYPE_P (TREE_OPERAND (member, 0))) + { + tree id = TREE_OPERAND (member, 0); + id = make_typename_type (object_type, id, typename_type, complain); + gcc_assert (TREE_CODE (id) != TYPENAME_TYPE); + member = build_nt (BIT_NOT_EXPR, id); + } else member = tsubst_copy (member, args, complain, in_decl); if (member == error_mark_node) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1a3ecb598edc..cec12fabecb9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-09-01 Nathan Sidwell + + PR c++/23287 + * g++.dg/parse/dtor12.C: New. + 2006-08-31 Zdenek Dvorak PR tree-optimization/28839 diff --git a/gcc/testsuite/g++.dg/parse/dtor12.C b/gcc/testsuite/g++.dg/parse/dtor12.C new file mode 100644 index 000000000000..d964662178e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/dtor12.C @@ -0,0 +1,15 @@ +// Copyright (C) 2006 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 1 Sep 2006 + +// PR 23287: Failure to parse dependent dtor name +// Origin:Wolfgang Bangerth + + +template struct A {}; + +template void f(A *ptr) { + ptr->~A(); +} + +template void f (A *); +