summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/decl.c18
-rw-r--r--gcc/cp/error.c3
-rw-r--r--gcc/cp/parser.c16
-rw-r--r--gcc/cp/pt.c46
-rw-r--r--gcc/cp/search.c24
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/g++.dg/template/inherit.C2
-rw-r--r--gcc/testsuite/g++.dg/template/injected1.C33
-rw-r--r--gcc/testsuite/g++.old-deja/g++.brendan/crash56.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/lookup8.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/ttp22.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/ttp23.C2
13 files changed, 134 insertions, 45 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ce4415d3f7f..960cedc2af5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+2009-11-16 Jason Merrill <jason@redhat.com>
+
+ PR c++/13950, DR 176
+ * search.c (lookup_field_r): Allow lookup to find the
+ injected-class-name from a template base.
+ (template_self_reference_p): Remove.
+ * decl.c (make_typename_type): Diagnose ambiguity. Use
+ maybe_get_template_decl_from_type_decl.
+ * parser.c (cp_parser_template_name): Pass true to is_template
+ rather than use maybe_get_template_decl_from_type_decl.
+ (cp_parser_lookup_name): Use maybe_get_template_decl_from_type_decl.
+ * pt.c (maybe_get_template_decl_from_type_decl): Handle ambiguity.
+ Use DECL_SELF_REFERENCE_P.
+
+ * parser.c (cp_parser_parse_and_diagnose_invalid_type_name):
+ Avoid duplicate ambiguity error.
+ * error.c (dump_decl): Don't say "typedef" for injected-class-name.
+ * pt.c (convert_template_argument): Tweak logic.
+
2009-11-16 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/42055
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 73bf995714f..851edeb5251 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -3040,11 +3040,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
if (!dependent_scope_p (context))
/* We should only set WANT_TYPE when we're a nested typename type.
Then we can give better diagnostics if we find a non-type. */
- t = lookup_field (context, name, 0, /*want_type=*/true);
+ t = lookup_field (context, name, 2, /*want_type=*/true);
else
t = NULL_TREE;
- if (!t && dependent_type_p (context))
+ if ((!t || TREE_CODE (t) == TREE_LIST) && dependent_type_p (context))
return build_typename_type (context, name, fullname, tag_type);
want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR;
@@ -3057,6 +3057,20 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
return error_mark_node;
}
+ /* Pull out the template from an injected-class-name (or multiple). */
+ if (want_template)
+ t = maybe_get_template_decl_from_type_decl (t);
+
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ if (complain & tf_error)
+ {
+ error ("lookup of %qT in %qT is ambiguous", name, context);
+ print_candidates (t);
+ }
+ return error_mark_node;
+ }
+
if (want_template && !DECL_CLASS_TEMPLATE_P (t))
{
if (complain & tf_error)
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index f4232075119..7266d8872d5 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -908,7 +908,8 @@ dump_decl (tree t, int flags)
dump_type (TREE_TYPE (t), flags);
break;
}
- if (flags & TFF_DECL_SPECIFIERS)
+ if ((flags & TFF_DECL_SPECIFIERS)
+ && !DECL_SELF_REFERENCE_P (t))
pp_cxx_ws_string (cxx_pp, "typedef");
dump_simple_decl (t, DECL_ORIGINAL_TYPE (t)
? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t),
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 3a4b409e738..576842641fe 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2430,6 +2430,14 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
tree id;
cp_token *token = cp_lexer_peek_token (parser->lexer);
+ /* Avoid duplicate error about ambiguous lookup. */
+ if (token->type == CPP_NESTED_NAME_SPECIFIER)
+ {
+ cp_token *next = cp_lexer_peek_nth_token (parser->lexer, 2);
+ if (next->type == CPP_NAME && next->ambiguous_p)
+ goto out;
+ }
+
cp_parser_parse_tentatively (parser);
id = cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
@@ -2451,6 +2459,7 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
/* Emit a diagnostic for the invalid type. */
cp_parser_diagnose_invalid_type_name (parser, parser->scope,
id, token->location);
+ out:
/* If we aren't in the middle of a declarator (i.e. in a
parameter-declaration-clause), skip to the end of the declaration;
there's no point in trying to process it. */
@@ -11086,12 +11095,11 @@ cp_parser_template_name (cp_parser* parser,
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
none_type,
- /*is_template=*/false,
+ /*is_template=*/true,
/*is_namespace=*/false,
check_dependency_p,
/*ambiguous_decls=*/NULL,
token->location);
- decl = maybe_get_template_decl_from_type_decl (decl);
/* If DECL is a template, then the name was a template-name. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -18045,6 +18053,10 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
if (!decl || decl == error_mark_node)
return error_mark_node;
+ /* Pull out the template from an injected-class-name (or multiple). */
+ if (is_template)
+ decl = maybe_get_template_decl_from_type_decl (decl);
+
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
if (TREE_CODE (decl) == TREE_LIST)
{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4ca94d6a895..9c82e3c19a5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5451,7 +5451,7 @@ convert_template_argument (tree parm,
complain, in_decl,
args))
{
- val = orig_arg;
+ val = arg;
/* TEMPLATE_TEMPLATE_PARM node is preferred over
TEMPLATE_DECL. */
@@ -5459,12 +5459,8 @@ convert_template_argument (tree parm,
{
if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
val = TREE_TYPE (val);
- else if (TREE_CODE (val) == TYPE_PACK_EXPANSION
- && DECL_TEMPLATE_TEMPLATE_PARM_P (arg))
- {
- val = TREE_TYPE (arg);
- val = make_pack_expansion (val);
- }
+ if (TREE_CODE (orig_arg) == TYPE_PACK_EXPANSION)
+ val = make_pack_expansion (val);
}
}
else
@@ -5990,15 +5986,43 @@ lookup_template_function (tree fns, tree arglist)
TEMPLATE_DECL. If DECL is a TYPE_DECL for current_class_type,
or one of its enclosing classes, and that type is a template,
return the associated TEMPLATE_DECL. Otherwise, the original
- DECL is returned. */
+ DECL is returned.
+
+ Also handle the case when DECL is a TREE_LIST of ambiguous
+ injected-class-names from different bases. */
tree
maybe_get_template_decl_from_type_decl (tree decl)
{
+ if (decl == NULL_TREE)
+ return decl;
+
+ /* DR 176: A lookup that finds an injected-class-name (10.2
+ [class.member.lookup]) can result in an ambiguity in certain cases
+ (for example, if it is found in more than one base class). If all of
+ the injected-class-names that are found refer to specializations of
+ the same class template, and if the name is followed by a
+ template-argument-list, the reference refers to the class template
+ itself and not a specialization thereof, and is not ambiguous. */
+ if (TREE_CODE (decl) == TREE_LIST)
+ {
+ tree t, tmpl = NULL_TREE;
+ for (t = decl; t; t = TREE_CHAIN (t))
+ {
+ tree elt = maybe_get_template_decl_from_type_decl (TREE_VALUE (t));
+ if (!tmpl)
+ tmpl = elt;
+ else if (tmpl != elt)
+ break;
+ }
+ if (tmpl && t == NULL_TREE)
+ return tmpl;
+ else
+ return decl;
+ }
+
return (decl != NULL_TREE
- && TREE_CODE (decl) == TYPE_DECL
- && DECL_ARTIFICIAL (decl)
- && CLASS_TYPE_P (TREE_TYPE (decl))
+ && DECL_SELF_REFERENCE_P (decl)
&& CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 3adf9e0a1ab..3e9bec011ff 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -63,7 +63,6 @@ static tree dfs_access_in_type (tree, void *);
static access_kind access_in_type (tree, tree);
static int protected_accessible_p (tree, tree, tree);
static int friend_accessible_p (tree, tree, tree);
-static int template_self_reference_p (tree, tree);
static tree dfs_get_pure_virtuals (tree, void *);
@@ -955,24 +954,6 @@ struct lookup_field_info {
const char *errstr;
};
-/* Within the scope of a template class, you can refer to the to the
- current specialization with the name of the template itself. For
- example:
-
- template <typename T> struct S { S* sp; }
-
- Returns nonzero if DECL is such a declaration in a class TYPE. */
-
-static int
-template_self_reference_p (tree type, tree decl)
-{
- return (CLASSTYPE_USE_TEMPLATE (type)
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
- && TREE_CODE (decl) == TYPE_DECL
- && DECL_ARTIFICIAL (decl)
- && DECL_NAME (decl) == constructor_name (type));
-}
-
/* Nonzero for a class member means that it is shared between all objects
of that class.
@@ -1092,11 +1073,6 @@ lookup_field_r (tree binfo, void *data)
}
}
- /* You must name a template base class with a template-id. */
- if (!same_type_p (type, lfi->type)
- && template_self_reference_p (type, nval))
- goto done;
-
/* If the lookup already found a match, and the new value doesn't
hide the old one, we might have an ambiguity. */
if (lfi->rval_binfo
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 42702ebd9d5..6b3e48cbdac 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2009-11-16 Jason Merrill <jason@redhat.com>
+
+ PR c++/13950
+ * g++.dg/template/injected1.C: New.
+ * g++.dg/template/inherit.C: Adjust.
+ * g++.old-deja/g++.brendan/crash56.C: Adjust.
+ * g++.old-deja/g++.pt/lookup8.C: Adjust.
+ * g++.old-deja/g++.pt/ttp22.C: Adjust.
+ * g++.old-deja/g++.pt/ttp23.C: Adjust.
+
2009-11-16 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/42055
diff --git a/gcc/testsuite/g++.dg/template/inherit.C b/gcc/testsuite/g++.dg/template/inherit.C
index bc20345fa0a..43af3cfc5ac 100644
--- a/gcc/testsuite/g++.dg/template/inherit.C
+++ b/gcc/testsuite/g++.dg/template/inherit.C
@@ -9,5 +9,5 @@ struct Z : X<int> { };
int main()
{
Z z;
- z.X::f(); // { dg-error "template parameters" "" }
+ z.X::f();
}
diff --git a/gcc/testsuite/g++.dg/template/injected1.C b/gcc/testsuite/g++.dg/template/injected1.C
new file mode 100644
index 00000000000..81873b498f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/injected1.C
@@ -0,0 +1,33 @@
+// PR c++/13950, DR 176
+
+template <class T> struct Base { }; // { dg-error "" } candidate
+
+struct D1: Base<void>
+{
+ D1::Base* p1;
+ D1::Base<double>* p2;
+ Base *p3;
+ Base<double>* p4;
+};
+
+struct D2: Base<void>, Base<void*>
+{
+ D2::Base* p1; // { dg-error "" }
+ D2::Base<double>* p2;
+ Base *p3; // { dg-error "" }
+ Base<double>* p4;
+};
+
+template <class T>
+struct D3: Base<T> {
+ typename D3::Base* p1;
+ typename D3::template Base<double>* p2;
+};
+template struct D3<void>;
+
+template <class T>
+struct D4: Base<T>, Base<T*> {
+ typename D4::Base* p1; // { dg-error "" }
+ typename D4::template Base<double>* p2;
+};
+template struct D4<void>; // { dg-message "instantiated" }
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
index dcb89dc9e48..0932ca46659 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
@@ -342,7 +342,7 @@ operator>=(const SetLD<T>& a, const SetLD<T>& b)
{ return ! (a < b); }
class String { };
class IcaseString: public String { };
-template <> class SetLD< IcaseString >: public SetLD< String > { public: SetLD (): SetLD< String >() { }; SetLD (const ListD< IcaseString >& other): SetLD< String >() { ListD< IcaseString >::Vix x; for (other.first(x); 0 != x; other.next(x)) add(other(x)); }; SetLD (const SetLD & other): SetLD< String >(other) { }; const IcaseString & operator()(const Vix& x) const { return ( IcaseString &) SetLD< String >::operator()(x); } }; typedef SetLD< String > SetLD_String_IcaseString_old_tmp99; typedef SetLD< IcaseString > SetLD_String_IcaseString_new_tmp99;
+template <> class SetLD< IcaseString >: public SetLD< String > { public: SetLD (): SetLD< String >() { }; SetLD (const ::ListD< IcaseString >& other): SetLD< String >() { ::ListD< IcaseString >::Vix x; for (other.first(x); 0 != x; other.next(x)) add(other(x)); }; SetLD (const SetLD & other): SetLD< String >(other) { }; const IcaseString & operator()(const Vix& x) const { return ( IcaseString &) SetLD< String >::operator()(x); } }; typedef SetLD< String > SetLD_String_IcaseString_old_tmp99; typedef SetLD< IcaseString > SetLD_String_IcaseString_new_tmp99;
inline int operator== (const SetLD_String_IcaseString_new_tmp99& a, const SetLD_String_IcaseString_new_tmp99& b) // { dg-message "operator==" }
{
const SetLD_String_IcaseString_old_tmp99& oa = a;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/lookup8.C b/gcc/testsuite/g++.old-deja/g++.pt/lookup8.C
index 2c6df5583b9..1662f68c7b6 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/lookup8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/lookup8.C
@@ -11,5 +11,5 @@ class Y : public X<int>
void Y::f()
{
- X x; // { dg-error "" } X is not a type.
+ X x;
}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp22.C b/gcc/testsuite/g++.old-deja/g++.pt/ttp22.C
index 01f08c0dbbe..de3334e79e6 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ttp22.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp22.C
@@ -24,7 +24,7 @@ template<template<class> class DD,class EE> int C<DD,EE>::f()
class E : C<D,int>
{
public:
- int f() { return C<D,int>::f(); }
+ int f() { return C< ::D,int>::f(); }
};
int main()
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp23.C b/gcc/testsuite/g++.old-deja/g++.pt/ttp23.C
index 8db7f386a03..051a3f33036 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ttp23.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp23.C
@@ -24,7 +24,7 @@ template<template<class> class E,class D> int C<E,D>::f()
class E : C<D,int>
{
public:
- int f() { return C<D,int>::f(); }
+ int f() { return C< ::D,int>::f(); }
};
int main()