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
This commit is contained in:
Nathan Sidwell 2007-07-22 16:25:54 +00:00 committed by Nathan Sidwell
parent 7e24f16cf7
commit 4195a76796
12 changed files with 155 additions and 39 deletions

View File

@ -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.

View File

@ -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))

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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; }

View File

@ -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;
}

View File

@ -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;
}