From bbaab9162a854dd2225f38cb42e0c3666a9462ec Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Sat, 25 Jan 2003 18:02:43 +0000 Subject: [PATCH] re PR c++/9403 (parse error on template keyword used for disambiguation) cp: PR c++/9403 * parser.c (cp_parser_class_or_namespace_name): Reject duplicate template keyword. (cp_parser_base_specifier): Look for and consume a TEMPLATE keyword. Replace switch with array index. PR c++/795 * semantics.c (finish_non_static_data_member): Remember the field's type even in a template. PR c++/9415 * pt.c (tsubst_copy_and_build, CALL_EXPR): BASELINK exprs are already scoped. PR c++/8545 * parser.c (cp_parser_cast_expression): Be more tentative. testsuite: PR c++/9403 * g++.dg/parse/template3.C: New test. * g++.old-deja/g++.pt/memclass5.C: Add needed template keyword. PR c++/795 * g++.dg/parse/template4.C: New test. PR c++/9415 * g++.dg/template/qual2.C: New test. PR c++/8545 * g++.old-deja/g++.brendan/parse3.C: Remove XFAIL. * g++.old-deja/g++.ns/bogus1.C: Change expected error. From-SVN: r61791 --- gcc/cp/ChangeLog | 19 +++++ gcc/cp/parser.c | 85 ++++++------------- gcc/cp/pt.c | 26 +++--- gcc/cp/semantics.c | 3 +- gcc/testsuite/ChangeLog | 17 ++++ gcc/testsuite/g++.dg/parse/template3.C | 17 ++++ gcc/testsuite/g++.dg/parse/template4.C | 21 +++++ gcc/testsuite/g++.dg/template/qual2.C | 29 +++++++ .../g++.old-deja/g++.brendan/parse3.C | 3 +- gcc/testsuite/g++.old-deja/g++.ns/bogus1.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/memclass5.C | 2 +- 11 files changed, 150 insertions(+), 74 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/template3.C create mode 100644 gcc/testsuite/g++.dg/parse/template4.C create mode 100644 gcc/testsuite/g++.dg/template/qual2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 336370f2051..fe8898f28d6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,22 @@ +2003-01-25 Nathan Sidwell + + PR c++/9403 + * parser.c (cp_parser_class_or_namespace_name): Reject duplicate + template keyword. + (cp_parser_base_specifier): Look for and consume a + TEMPLATE keyword. Replace switch with array index. + + PR c++/795 + * semantics.c (finish_non_static_data_member): Remember the + field's type even in a template. + + PR c++/9415 + * pt.c (tsubst_copy_and_build, CALL_EXPR): BASELINK exprs are + already scoped. + + PR c++/8545 + * parser.c (cp_parser_cast_expression): Be more tentative. + 2003-01-25 Kriang Lerdsuwanakij * cp-tree.h (flagged_type_tree_s): Remove. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4d809b81012..7e172abd555 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3392,16 +3392,6 @@ cp_parser_class_or_namespace_name (cp_parser *parser, tree scope; bool only_class_p; - /* If the next token is the `template' keyword, we know that we are - looking at a class-name. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) - return cp_parser_class_name (parser, - typename_keyword_p, - template_keyword_p, - type_p, - /*check_access_p=*/true, - check_dependency_p, - /*class_head_p=*/false); /* Before we try to parse the class-name, we must save away the current PARSER->SCOPE since cp_parser_class_name will destroy it. */ @@ -3410,7 +3400,7 @@ cp_parser_class_or_namespace_name (cp_parser *parser, saved_object_scope = parser->object_scope; /* Try for a class-name first. If the SAVED_SCOPE is a type, then there is no need to look for a namespace-name. */ - only_class_p = saved_scope && TYPE_P (saved_scope); + only_class_p = template_keyword_p || (saved_scope && TYPE_P (saved_scope)); if (!only_class_p) cp_parser_parse_tentatively (parser); scope = cp_parser_class_name (parser, @@ -3931,7 +3921,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) postfix_expression = build_x_arrow (postfix_expression); /* Check to see whether or not the expression is type-dependent. */ - dependent_p = (type_dependent_expression_p (postfix_expression)); + dependent_p = type_dependent_expression_p (postfix_expression); /* The identifier following the `->' or `.' is not qualified. */ parser->scope = NULL_TREE; @@ -4761,23 +4751,26 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p) /* Restore the saved message. */ parser->type_definition_forbidden_message = saved_message; - /* If all went well, this is a cast. */ + /* If ok so far, parse the dependent expression. We cannot be + sure it is a cast. Consider `(T ())'. It is a parenthesized + ctor of T, but looks like a cast to function returning T + without a dependent expression. */ + if (!cp_parser_error_occurred (parser)) + expr = cp_parser_cast_expression (parser, /*address_p=*/false); + if (cp_parser_parse_definitely (parser)) { - /* Parse the dependent expression. */ - expr = cp_parser_cast_expression (parser, /*address_p=*/false); /* Warn about old-style casts, if so requested. */ if (warn_old_style_cast && !in_system_header && !VOID_TYPE_P (type) && current_lang_name != lang_name_c) warning ("use of old-style cast"); + /* Perform the cast. */ expr = build_c_cast (type, expr); + return expr; } - - if (expr) - return expr; } /* If we get here, then it's not a cast, so it must be a @@ -12175,12 +12168,20 @@ cp_parser_base_clause (cp_parser* parser) static tree cp_parser_base_specifier (cp_parser* parser) { + static const tree *const access_nodes[][2] = + { + /* This ordering must match the access_kind enumeration. */ + {&access_default_node, &access_default_virtual_node}, + {&access_public_node, &access_public_virtual_node}, + {&access_protected_node, &access_protected_virtual_node}, + {&access_private_node, &access_private_virtual_node} + }; cp_token *token; bool done = false; bool virtual_p = false; bool duplicate_virtual_error_issued_p = false; bool duplicate_access_error_issued_p = false; - bool class_scope_p; + bool class_scope_p, template_p; access_kind access = ak_none; tree access_node; tree type; @@ -12236,45 +12237,9 @@ cp_parser_base_specifier (cp_parser* parser) } } - /* Map `virtual_p' and `access' onto one of the access - tree-nodes. */ - if (!virtual_p) - switch (access) - { - case ak_none: - access_node = access_default_node; - break; - case ak_public: - access_node = access_public_node; - break; - case ak_protected: - access_node = access_protected_node; - break; - case ak_private: - access_node = access_private_node; - break; - default: - abort (); - } - else - switch (access) - { - case ak_none: - access_node = access_default_virtual_node; - break; - case ak_public: - access_node = access_public_virtual_node; - break; - case ak_protected: - access_node = access_protected_virtual_node; - break; - case ak_private: - access_node = access_private_virtual_node; - break; - default: - abort (); - } - + /* Map `virtual_p' and `access' onto one of the access tree-nodes. */ + access_node = *access_nodes[access][virtual_p]; + /* Look for the optional `::' operator. */ cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false); /* Look for the nested-name-specifier. The simplest way to @@ -12296,10 +12261,12 @@ cp_parser_base_specifier (cp_parser* parser) /* If the base class is given by a qualified name, assume that names we see are type names or templates, as appropriate. */ class_scope_p = (parser->scope && TYPE_P (parser->scope)); + template_p = class_scope_p && cp_parser_optional_template_keyword (parser); + /* Finally, look for the class-name. */ type = cp_parser_class_name (parser, class_scope_p, - class_scope_p, + template_p, /*type_p=*/true, /*check_access=*/true, /*check_dependency_p=*/true, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ca75cb0b0d6..bbfec1483f0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8129,28 +8129,32 @@ tsubst_copy_and_build (t, args, complain, in_decl) case CALL_EXPR: { - tree function - = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); - if (TREE_CODE (function) == SCOPE_REF) + tree function, copy_args; + + function = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl); + copy_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args, + complain, in_decl); + + if (BASELINK_P (function)) + return build_call_from_tree (function, copy_args, 1); + else if (TREE_CODE (function) == SCOPE_REF) { tree name = TREE_OPERAND (function, 1); if (TREE_CODE (name) == TEMPLATE_ID_EXPR) name = build_nt (TEMPLATE_ID_EXPR, TREE_OPERAND (name, 0), TREE_OPERAND (name, 1)); - - return build_call_from_tree - (resolve_scoped_fn_name (TREE_OPERAND (function, 0), name), - tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, - in_decl), - 1); + + function = resolve_scoped_fn_name (TREE_OPERAND (function, 0), + name); + + return build_call_from_tree (function, copy_args, 1); } else { tree name = function; tree id; - tree copy_args = tsubst_copy_and_build - (TREE_OPERAND (t, 1), args, complain, in_decl); + if (copy_args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR && !LOOKUP_EXPR_GLOBAL (name) && (TREE_CODE ((id = TREE_OPERAND (name, 0))) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 19808e68583..fb6f25d116f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1214,7 +1214,8 @@ finish_non_static_data_member (tree decl, tree qualifying_scope) } TREE_USED (current_class_ptr) = 1; if (processing_template_decl) - return build_min_nt (COMPONENT_REF, current_class_ref, DECL_NAME (decl)); + return build_min (COMPONENT_REF, TREE_TYPE (decl), + current_class_ref, DECL_NAME (decl)); else { tree access_type = current_class_type; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f6a8dff0a9f..7c331f1a98a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2003-01-25 Nathan Sidwell + + PR c++/9403 + * g++.dg/parse/template3.C: New test. + * g++.old-deja/g++.pt/memclass5.C: Add needed template keyword. + + PR c++/795 + * g++.dg/parse/template4.C: New test. + + PR c++/9415 + * g++.dg/template/qual2.C: New test. + + PR c++/8545 + * g++.old-deja/g++.brendan/parse3.C: Remove XFAIL. + + * g++.old-deja/g++.ns/bogus1.C: Change expected error. + 2003-01-25 Roger Sayle * gcc.c-torture/execute/switch-1.c: New test case. diff --git a/gcc/testsuite/g++.dg/parse/template3.C b/gcc/testsuite/g++.dg/parse/template3.C new file mode 100644 index 00000000000..290721eaa53 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/template3.C @@ -0,0 +1,17 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 24 Jan 2003 + +// PR 9403. We failed to parse template keyword, and we accepted code +// which required one. + +template struct Outer; + +template +struct X : Outer::template Inner +{}; + +template +struct Y : Outer::Inner {}; // { dg-error "" "" } + diff --git a/gcc/testsuite/g++.dg/parse/template4.C b/gcc/testsuite/g++.dg/parse/template4.C new file mode 100644 index 00000000000..11f11d53525 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/template4.C @@ -0,0 +1,21 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 32 Jan 2003 + +// PR 795. fields are not necessarily a dependent type. + +struct V +{ + template T get (); +}; + +struct L +{ + V v; + + template T at (int i) + { + return v.get (); + } +}; diff --git a/gcc/testsuite/g++.dg/template/qual2.C b/gcc/testsuite/g++.dg/template/qual2.C new file mode 100644 index 00000000000..aa6b10ea4a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/qual2.C @@ -0,0 +1,29 @@ +// { dg-do run } + +// Copyright (C) 2003 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 23 Jan 2003 + +// PR9415. Forgot a lookup was scoped + +int here; +int there; + +struct B +{ + virtual int activate() {return !here++;} +}; + +template +struct TPL : public B +{ + int activate() + { + return !there++ && B::activate(); + } +}; + +int main () +{ + TPL i; + return !i.activate (); +} diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/parse3.C b/gcc/testsuite/g++.old-deja/g++.brendan/parse3.C index 8941356e061..ffe72d2a38a 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/parse3.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/parse3.C @@ -6,6 +6,7 @@ // when the parser's been cleaned up or rewritten, these two error // markers can go away, since they'll no longer occur. +// Fixed. PR 8545, 2001 01 23 class A { public: @@ -19,5 +20,5 @@ A A::operator+(const A in) if (high==0) return A(); // this works else - return (A()); // this works not // gets bogus error - XFAIL *-*-* + return (A()); // this works not } diff --git a/gcc/testsuite/g++.old-deja/g++.ns/bogus1.C b/gcc/testsuite/g++.old-deja/g++.ns/bogus1.C index c61dea8e77e..373688a99c3 100644 --- a/gcc/testsuite/g++.old-deja/g++.ns/bogus1.C +++ b/gcc/testsuite/g++.old-deja/g++.ns/bogus1.C @@ -2,7 +2,7 @@ namespace N {} -void f(int N::k); // ERROR - cannot use `::' in parameter declaration +void f(int N::k); // ERROR - class Foo { diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memclass5.C b/gcc/testsuite/g++.old-deja/g++.pt/memclass5.C index 6fc72199b64..5a0c037e7d2 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/memclass5.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/memclass5.C @@ -14,7 +14,7 @@ void f () b.A::template B::~B(); } -template struct C: public A::B { }; +template struct C: public A::template B { }; int main () {