From: nathan Date: Sun, 22 Jul 2007 16:25:54 +0000 (+0000) Subject: cp/ X-Git-Url: http://git.sourceforge.jp/view?a=commitdiff_plain;h=8826a863f1b32186c8efcbf5e9ee09dacfd0c8e7;p=pf3gnuchains%2Fgcc-fork.git cp/ PR c++/30818 * typeck.c (structural_comptypes): No need to check resolve_typename_type return value here. * cp-tree.h (TYPENAME_IS_RESOLVING_P): New. * pt.c (resolve_typename_type): Follow typename typedefs. Return original type rather than error_mark_node in case of failure. * parser.c (cp_parser_nested_name_specifier_opt): Adjust resolve_typename_type result check. (cp_parser_direct_declarator, cp_parser_head, cp_parser_constructor_declarator_p): Likewise. testsuite/ PR c++/30818 * g++.dg/template/crash47.C: Adjust errors. * g++.dg/template/crash48.C: Adjust errors. * g++.dg/template/typename12.C: New. * g++.dg/template/typename13.C: New. * g++.dg/template/typename14.C: New. * g++.dg/template/typedef6.C: Adjust errors. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126825 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 192c8f42738..6faa01f80a1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2007-07-22 Nathan Sidwell + + PR c++/30818 + * typeck.c (structural_comptypes): No need to check + resolve_typename_type return value here. + * cp-tree.h (TYPENAME_IS_RESOLVING_P): New. + * pt.c (resolve_typename_type): Follow typename typedefs. Return + original type rather than error_mark_node in case of failure. + * parser.c (cp_parser_nested_name_specifier_opt): Adjust + resolve_typename_type result check. + (cp_parser_direct_declarator, cp_parser_head, + cp_parser_constructor_declarator_p): Likewise. + 2007-07-12 Kazu Hirata * pt.c (template_parms_variadic_p): Remove. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 86044470ab7..e4401712fb5 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -71,6 +71,7 @@ struct diagnostic_context; ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) + TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -2589,6 +2590,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define TYPENAME_IS_CLASS_P(NODE) \ (TREE_LANG_FLAG_1 (TYPENAME_TYPE_CHECK (NODE))) +/* True if a TYPENAME_TYPE is in the process of being resolved. */ +#define TYPENAME_IS_RESOLVING_P(NODE) \ + (TREE_LANG_FLAG_2 (TYPENAME_TYPE_CHECK (NODE))) + /* Nonzero in INTEGER_CST means that this int is negative by dint of using a twos-complement negated operand. */ #define TREE_NEGATED_INT(NODE) TREE_LANG_FLAG_0 (INTEGER_CST_CHECK (NODE)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b49b9f8279c..458d300c331 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3922,7 +3922,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, { new_scope = resolve_typename_type (parser->scope, /*only_current_p=*/false); - if (new_scope != error_mark_node) + if (TREE_CODE (new_scope) != TYPENAME_TYPE) parser->scope = new_scope; } success = true; @@ -12464,7 +12464,7 @@ cp_parser_direct_declarator (cp_parser* parser, type = resolve_typename_type (qualifying_scope, /*only_current_p=*/false); /* If that failed, the declarator is invalid. */ - if (type == error_mark_node) + if (TREE_CODE (type) == TYPENAME_TYPE) error ("%<%T::%E%> is not a type", TYPE_CONTEXT (qualifying_scope), TYPE_IDENTIFIER (qualifying_scope)); @@ -14282,7 +14282,7 @@ cp_parser_class_head (cp_parser* parser, { class_type = resolve_typename_type (TREE_TYPE (type), /*only_current_p=*/false); - if (class_type != error_mark_node) + if (TREE_CODE (class_type) != TYPENAME_TYPE) type = TYPE_NAME (class_type); else { @@ -16291,7 +16291,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p) { type = resolve_typename_type (type, /*only_current_p=*/false); - if (type == error_mark_node) + if (TREE_CODE (type) == TYPENAME_TYPE) { cp_parser_abort_tentative_parse (parser); return false; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3ff4706048c..86b8eee6a10 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15457,11 +15457,12 @@ dependent_template_id_p (tree tmpl, tree args) } /* TYPE is a TYPENAME_TYPE. Returns the ordinary TYPE to which the - TYPENAME_TYPE corresponds. Returns ERROR_MARK_NODE if no such TYPE - can be found. Note that this function peers inside uninstantiated - templates and therefore should be used only in extremely limited - situations. ONLY_CURRENT_P restricts this peering to the currently - open classes hierarchy (which is required when comparing types). */ + TYPENAME_TYPE corresponds. Returns the original TYPENAME_TYPE if + no such TYPE can be found. Note that this function peers inside + uninstantiated templates and therefore should be used only in + extremely limited situations. ONLY_CURRENT_P restricts this + peering to the currently open classes hierarchy (which is required + when comparing types). */ tree resolve_typename_type (tree type, bool only_current_p) @@ -15471,6 +15472,7 @@ resolve_typename_type (tree type, bool only_current_p) tree decl; int quals; tree pushed_scope; + tree result; gcc_assert (TREE_CODE (type) == TYPENAME_TYPE); @@ -15483,8 +15485,8 @@ resolve_typename_type (tree type, bool only_current_p) scope = resolve_typename_type (scope, only_current_p); /* If we don't know what SCOPE refers to, then we cannot resolve the TYPENAME_TYPE. */ - if (scope == error_mark_node || TREE_CODE (scope) == TYPENAME_TYPE) - return error_mark_node; + if (TREE_CODE (scope) == TYPENAME_TYPE) + return type; /* If the SCOPE is a template type parameter, we have no way of resolving the name. */ if (TREE_CODE (scope) == TEMPLATE_TYPE_PARM) @@ -15492,7 +15494,7 @@ resolve_typename_type (tree type, bool only_current_p) /* If the SCOPE is not the current instantiation, there's no reason to look inside it. */ if (only_current_p && !currently_open_class (scope)) - return error_mark_node; + return type; /* If SCOPE is a partial instantiation, it will not have a valid TYPE_FIELDS list, so use the original template. */ scope = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (scope); @@ -15502,15 +15504,20 @@ resolve_typename_type (tree type, bool only_current_p) pushed_scope = push_scope (scope); /* Look up the declaration. */ decl = lookup_member (scope, name, /*protect=*/0, /*want_type=*/true); - /* Obtain the set of qualifiers applied to the TYPE. */ - quals = cp_type_quals (type); + + result = NULL_TREE; + /* For a TYPENAME_TYPE like "typename X::template Y", we want to find a TEMPLATE_DECL. Otherwise, we want to find a TYPE_DECL. */ if (!decl) - type = error_mark_node; + /*nop*/; else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == IDENTIFIER_NODE && TREE_CODE (decl) == TYPE_DECL) - type = TREE_TYPE (decl); + { + result = TREE_TYPE (decl); + if (result == error_mark_node) + result = NULL_TREE; + } else if (TREE_CODE (TYPENAME_TYPE_FULLNAME (type)) == TEMPLATE_ID_EXPR && DECL_CLASS_TEMPLATE_P (decl)) { @@ -15520,19 +15527,37 @@ resolve_typename_type (tree type, bool only_current_p) tmpl = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 0); args = TREE_OPERAND (TYPENAME_TYPE_FULLNAME (type), 1); /* Instantiate the template. */ - type = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE, - /*entering_scope=*/0, tf_error | tf_user); + result = lookup_template_class (tmpl, args, NULL_TREE, NULL_TREE, + /*entering_scope=*/0, + tf_error | tf_user); + if (result == error_mark_node) + result = NULL_TREE; } - else - type = error_mark_node; - /* Qualify the resulting type. */ - if (type != error_mark_node && quals) - type = cp_build_qualified_type (type, quals); + /* Leave the SCOPE. */ if (pushed_scope) pop_scope (pushed_scope); - return type; + /* If we failed to resolve it, return the original typename. */ + if (!result) + return type; + + /* If lookup found a typename type, resolve that too. */ + if (TREE_CODE (result) == TYPENAME_TYPE && !TYPENAME_IS_RESOLVING_P (result)) + { + /* Ill-formed programs can cause infinite recursion here, so we + must catch that. */ + TYPENAME_IS_RESOLVING_P (type) = 1; + result = resolve_typename_type (result, only_current_p); + TYPENAME_IS_RESOLVING_P (type) = 0; + } + + /* Qualify the resulting type. */ + quals = cp_type_quals (type); + if (quals) + result = cp_build_qualified_type (result, cp_type_quals (result) | quals); + + return result; } /* EXPR is an expression which is not type-dependent. Return a proxy diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 4f08c8e9aa7..7e59ec36b05 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -943,20 +943,10 @@ structural_comptypes (tree t1, tree t2, int strict) /* TYPENAME_TYPEs should be resolved if the qualifying scope is the current instantiation. */ if (TREE_CODE (t1) == TYPENAME_TYPE) - { - tree resolved = resolve_typename_type (t1, /*only_current_p=*/true); - - if (resolved != error_mark_node) - t1 = resolved; - } + t1 = resolve_typename_type (t1, /*only_current_p=*/true); if (TREE_CODE (t2) == TYPENAME_TYPE) - { - tree resolved = resolve_typename_type (t2, /*only_current_p=*/true); - - if (resolved != error_mark_node) - t2 = resolved; - } + t2 = resolve_typename_type (t2, /*only_current_p=*/true); if (TYPE_PTRMEMFUNC_P (t1)) t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f091d147bfc..1b5a4101bc9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2007-07-22 Nathan Sidwell + + PR c++/30818 + * g++.dg/template/crash47.C: Adjust errors. + * g++.dg/template/crash48.C: Adjust errors. + * g++.dg/template/typename12.C: New. + * g++.dg/template/typename13.C: New. + * g++.dg/template/typename14.C: New. + * g++.dg/template/typedef6.C: Adjust errors. + 2007-07-21 Christopher D. Rickett PR fortran/32627 diff --git a/gcc/testsuite/g++.dg/template/crash47.C b/gcc/testsuite/g++.dg/template/crash47.C index ad4aaa2fcaf..9c216320933 100644 --- a/gcc/testsuite/g++.dg/template/crash47.C +++ b/gcc/testsuite/g++.dg/template/crash47.C @@ -1,3 +1,3 @@ // PR c++/27102 -template void T::X::foo() {} // { dg-error "invalid" } +template void T::X::foo() {} // { dg-error "invalid|not a type" } diff --git a/gcc/testsuite/g++.dg/template/crash48.C b/gcc/testsuite/g++.dg/template/crash48.C index 9fd1a4fbefd..deb944685bd 100644 --- a/gcc/testsuite/g++.dg/template/crash48.C +++ b/gcc/testsuite/g++.dg/template/crash48.C @@ -7,4 +7,4 @@ template struct A typedef typename T::X X; }; -template A::X::X() {} // { dg-error "no type|invalid use" } +template A::X::X() {} // { dg-error "no type|invalid use|not a type" } diff --git a/gcc/testsuite/g++.dg/template/typedef6.C b/gcc/testsuite/g++.dg/template/typedef6.C index cd2db634a2b..c95945966fa 100644 --- a/gcc/testsuite/g++.dg/template/typedef6.C +++ b/gcc/testsuite/g++.dg/template/typedef6.C @@ -5,4 +5,4 @@ template struct A typedef struct typename T::X X; // { dg-error "expected identifier|two or more" } }; -template A::X::X() {} // { dg-error "not a type|forbids declaration" } +template A::X::X() {} // { dg-error "not a type|forbids declaration|invalid use of" } diff --git a/gcc/testsuite/g++.dg/template/typename12.C b/gcc/testsuite/g++.dg/template/typename12.C new file mode 100644 index 00000000000..0bb78c7c857 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename12.C @@ -0,0 +1,25 @@ +// { dg-do compile } + +// Copyright (C) 2007 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Jul 2007 + +// Origin: sschunck@pdf.de +// PR 30818, failure to resolve typename typedef + +template < typename T > +class A +{ + typedef int type; + class B; +}; + +template < typename T > +class A::B +{ + typedef typename A::type type; + type f(); +}; + +template < typename T > +typename A::B::type +A::B::f() { return 0; } diff --git a/gcc/testsuite/g++.dg/template/typename13.C b/gcc/testsuite/g++.dg/template/typename13.C new file mode 100644 index 00000000000..527b0d15316 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename13.C @@ -0,0 +1,24 @@ +// { dg-do compile } + +// Copyright (C) 2007 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Jul 2007 + +template struct A +{ + struct B; + typedef typename B::type type; +}; + +template struct A::B +{ + typedef typename A::type type; + + type Foo (); +}; + +template +typename A::B::type +A::B::Foo () +{ + return 0; +} diff --git a/gcc/testsuite/g++.dg/template/typename14.C b/gcc/testsuite/g++.dg/template/typename14.C new file mode 100644 index 00000000000..7e73cb0f3ad --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename14.C @@ -0,0 +1,24 @@ +// { dg-do compile } + +// Copyright (C) 2007 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 21 Jul 2007 + +template struct A +{ + typedef const T X; + + struct B; +}; + +template struct A::B +{ + typedef volatile typename A::X Y; + + T const volatile *Foo (); +}; + +template +typename A::B::Y *A::B::Foo () +{ + return 0; +}