aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/parser.c8
-rw-r--r--gcc/cp/pt.c65
-rw-r--r--gcc/cp/typeck.c14
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/g++.dg/template/crash47.C2
-rw-r--r--gcc/testsuite/g++.dg/template/crash48.C2
-rw-r--r--gcc/testsuite/g++.dg/template/typedef6.C2
-rw-r--r--gcc/testsuite/g++.dg/template/typename12.C25
-rw-r--r--gcc/testsuite/g++.dg/template/typename13.C24
-rw-r--r--gcc/testsuite/g++.dg/template/typename14.C24
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;
+}