diff options
author | Nathan Sidwell <nathan@codesourcery.com> | 2007-07-22 16:25:54 +0000 |
---|---|---|
committer | Nathan Sidwell <nathan@gcc.gnu.org> | 2007-07-22 16:25:54 +0000 |
commit | 4195a76796f2a88bbbcb0947b3fc8cfb590bcf28 (patch) | |
tree | dfb789ad9be1e19231b508e1334e98d3418748a1 /gcc | |
parent | 7e24f16cf7d70e74c60985f7591cbf2e129a23da (diff) | |
download | gcc-4195a76796f2a88bbbcb0947b3fc8cfb590bcf28.zip gcc-4195a76796f2a88bbbcb0947b3fc8cfb590bcf28.tar.gz gcc-4195a76796f2a88bbbcb0947b3fc8cfb590bcf28.tar.bz2 |
re PR c++/30818 (templates and typedefs cause function prototype not to match)
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.
From-SVN: r126825
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/parser.c | 8 | ||||
-rw-r--r-- | gcc/cp/pt.c | 65 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/crash47.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/crash48.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/typedef6.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/typename12.C | 25 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/typename13.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/typename14.C | 24 |
12 files changed, 155 insertions, 39 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 192c8f4..6faa01f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2007-07-22 Nathan Sidwell <nathan@codesourcery.com> + + 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 <kazu@codesourcery.com> * pt.c (template_parms_variadic_p): Remove. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8604447..e440171 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 b49b9f8..458d300 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 3ff4706..86b8eee 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<T>", 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 4f08c8e..7e59ec3 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 f091d14..1b5a410 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2007-07-22 Nathan Sidwell <nathan@codesourcery.com> + + 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 <crickett@lanl.gov> PR fortran/32627 diff --git a/gcc/testsuite/g++.dg/template/crash47.C b/gcc/testsuite/g++.dg/template/crash47.C index ad4aaa2..9c21632 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<typename T> void T::X::foo() {} // { dg-error "invalid" } +template<typename T> 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 9fd1a4f..deb9446 100644 --- a/gcc/testsuite/g++.dg/template/crash48.C +++ b/gcc/testsuite/g++.dg/template/crash48.C @@ -7,4 +7,4 @@ template<typename T> struct A typedef typename T::X X; }; -template<typename T> A<T>::X::X() {} // { dg-error "no type|invalid use" } +template<typename T> A<T>::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 cd2db63..c9594596 100644 --- a/gcc/testsuite/g++.dg/template/typedef6.C +++ b/gcc/testsuite/g++.dg/template/typedef6.C @@ -5,4 +5,4 @@ template<typename T> struct A typedef struct typename T::X X; // { dg-error "expected identifier|two or more" } }; -template<typename T> A<T>::X::X() {} // { dg-error "not a type|forbids declaration" } +template<typename T> A<T>::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 0000000..0bb78c7 --- /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 <nathan@codesourcery.com> + +// 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<T>::B +{ + typedef typename A<T>::type type; + type f(); +}; + +template < typename T > +typename A<T>::B::type +A<T>::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 0000000..527b0d1 --- /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 <nathan@codesourcery.com> + +template <typename T> struct A +{ + struct B; + typedef typename B::type type; +}; + +template <typename T> struct A<T>::B +{ + typedef typename A<T>::type type; + + type Foo (); +}; + +template <typename T> +typename A<T>::B::type +A<T>::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 0000000..7e73cb0 --- /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 <nathan@codesourcery.com> + +template <typename T> struct A +{ + typedef const T X; + + struct B; +}; + +template <typename T> struct A<T>::B +{ + typedef volatile typename A<T>::X Y; + + T const volatile *Foo (); +}; + +template<typename T> +typename A<T>::B::Y *A<T>::B::Foo () +{ + return 0; +} |