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:
parent
7e24f16cf7
commit
4195a76796
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
65
gcc/cp/pt.c
65
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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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" }
|
||||
|
@ -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" }
|
||||
|
@ -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" }
|
||||
|
25
gcc/testsuite/g++.dg/template/typename12.C
Normal file
25
gcc/testsuite/g++.dg/template/typename12.C
Normal 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; }
|
24
gcc/testsuite/g++.dg/template/typename13.C
Normal file
24
gcc/testsuite/g++.dg/template/typename13.C
Normal 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;
|
||||
}
|
24
gcc/testsuite/g++.dg/template/typename14.C
Normal file
24
gcc/testsuite/g++.dg/template/typename14.C
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user