Commit 5a080ad7 by Jason Merrill Committed by Jason Merrill

PR c++/13950, DR 176

	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.

From-SVN: r154223
parent 87213cd4
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> 2009-11-16 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/42055 PR c++/42055
......
...@@ -3040,11 +3040,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, ...@@ -3040,11 +3040,11 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
if (!dependent_scope_p (context)) if (!dependent_scope_p (context))
/* We should only set WANT_TYPE when we're a nested typename type. /* 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. */ 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 else
t = NULL_TREE; 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); return build_typename_type (context, name, fullname, tag_type);
want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR; want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR;
...@@ -3057,6 +3057,20 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, ...@@ -3057,6 +3057,20 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
return error_mark_node; 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 (want_template && !DECL_CLASS_TEMPLATE_P (t))
{ {
if (complain & tf_error) if (complain & tf_error)
......
...@@ -908,7 +908,8 @@ dump_decl (tree t, int flags) ...@@ -908,7 +908,8 @@ dump_decl (tree t, int flags)
dump_type (TREE_TYPE (t), flags); dump_type (TREE_TYPE (t), flags);
break; break;
} }
if (flags & TFF_DECL_SPECIFIERS) if ((flags & TFF_DECL_SPECIFIERS)
&& !DECL_SELF_REFERENCE_P (t))
pp_cxx_ws_string (cxx_pp, "typedef"); pp_cxx_ws_string (cxx_pp, "typedef");
dump_simple_decl (t, DECL_ORIGINAL_TYPE (t) dump_simple_decl (t, DECL_ORIGINAL_TYPE (t)
? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t),
......
...@@ -2430,6 +2430,14 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser) ...@@ -2430,6 +2430,14 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
tree id; tree id;
cp_token *token = cp_lexer_peek_token (parser->lexer); 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); cp_parser_parse_tentatively (parser);
id = cp_parser_id_expression (parser, id = cp_parser_id_expression (parser,
/*template_keyword_p=*/false, /*template_keyword_p=*/false,
...@@ -2451,6 +2459,7 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser) ...@@ -2451,6 +2459,7 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
/* Emit a diagnostic for the invalid type. */ /* Emit a diagnostic for the invalid type. */
cp_parser_diagnose_invalid_type_name (parser, parser->scope, cp_parser_diagnose_invalid_type_name (parser, parser->scope,
id, token->location); id, token->location);
out:
/* If we aren't in the middle of a declarator (i.e. in a /* If we aren't in the middle of a declarator (i.e. in a
parameter-declaration-clause), skip to the end of the declaration; parameter-declaration-clause), skip to the end of the declaration;
there's no point in trying to process it. */ there's no point in trying to process it. */
...@@ -11086,12 +11095,11 @@ cp_parser_template_name (cp_parser* parser, ...@@ -11086,12 +11095,11 @@ cp_parser_template_name (cp_parser* parser,
/* Look up the name. */ /* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier, decl = cp_parser_lookup_name (parser, identifier,
none_type, none_type,
/*is_template=*/false, /*is_template=*/true,
/*is_namespace=*/false, /*is_namespace=*/false,
check_dependency_p, check_dependency_p,
/*ambiguous_decls=*/NULL, /*ambiguous_decls=*/NULL,
token->location); token->location);
decl = maybe_get_template_decl_from_type_decl (decl);
/* If DECL is a template, then the name was a template-name. */ /* If DECL is a template, then the name was a template-name. */
if (TREE_CODE (decl) == TEMPLATE_DECL) if (TREE_CODE (decl) == TEMPLATE_DECL)
...@@ -18045,6 +18053,10 @@ cp_parser_lookup_name (cp_parser *parser, tree name, ...@@ -18045,6 +18053,10 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
if (!decl || decl == error_mark_node) if (!decl || decl == error_mark_node)
return 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 it's a TREE_LIST, the result of the lookup was ambiguous. */
if (TREE_CODE (decl) == TREE_LIST) if (TREE_CODE (decl) == TREE_LIST)
{ {
......
...@@ -5451,7 +5451,7 @@ convert_template_argument (tree parm, ...@@ -5451,7 +5451,7 @@ convert_template_argument (tree parm,
complain, in_decl, complain, in_decl,
args)) args))
{ {
val = orig_arg; val = arg;
/* TEMPLATE_TEMPLATE_PARM node is preferred over /* TEMPLATE_TEMPLATE_PARM node is preferred over
TEMPLATE_DECL. */ TEMPLATE_DECL. */
...@@ -5459,12 +5459,8 @@ convert_template_argument (tree parm, ...@@ -5459,12 +5459,8 @@ convert_template_argument (tree parm,
{ {
if (DECL_TEMPLATE_TEMPLATE_PARM_P (val)) if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
val = TREE_TYPE (val); val = TREE_TYPE (val);
else if (TREE_CODE (val) == TYPE_PACK_EXPANSION if (TREE_CODE (orig_arg) == TYPE_PACK_EXPANSION)
&& DECL_TEMPLATE_TEMPLATE_PARM_P (arg)) val = make_pack_expansion (val);
{
val = TREE_TYPE (arg);
val = make_pack_expansion (val);
}
} }
} }
else else
...@@ -5990,15 +5986,43 @@ lookup_template_function (tree fns, tree arglist) ...@@ -5990,15 +5986,43 @@ lookup_template_function (tree fns, tree arglist)
TEMPLATE_DECL. If DECL is a TYPE_DECL for current_class_type, TEMPLATE_DECL. If DECL is a TYPE_DECL for current_class_type,
or one of its enclosing classes, and that type is a template, or one of its enclosing classes, and that type is a template,
return the associated TEMPLATE_DECL. Otherwise, the original 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 tree
maybe_get_template_decl_from_type_decl (tree decl) 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 return (decl != NULL_TREE
&& TREE_CODE (decl) == TYPE_DECL && DECL_SELF_REFERENCE_P (decl)
&& DECL_ARTIFICIAL (decl)
&& CLASS_TYPE_P (TREE_TYPE (decl))
&& CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl))) && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl; ? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;
} }
......
...@@ -63,7 +63,6 @@ static tree dfs_access_in_type (tree, void *); ...@@ -63,7 +63,6 @@ static tree dfs_access_in_type (tree, void *);
static access_kind access_in_type (tree, tree); static access_kind access_in_type (tree, tree);
static int protected_accessible_p (tree, tree, tree); static int protected_accessible_p (tree, tree, tree);
static int friend_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 *); static tree dfs_get_pure_virtuals (tree, void *);
...@@ -955,24 +954,6 @@ struct lookup_field_info { ...@@ -955,24 +954,6 @@ struct lookup_field_info {
const char *errstr; 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 /* Nonzero for a class member means that it is shared between all objects
of that class. of that class.
...@@ -1092,11 +1073,6 @@ lookup_field_r (tree binfo, void *data) ...@@ -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 /* If the lookup already found a match, and the new value doesn't
hide the old one, we might have an ambiguity. */ hide the old one, we might have an ambiguity. */
if (lfi->rval_binfo if (lfi->rval_binfo
......
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> 2009-11-16 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/42055 PR c++/42055
......
...@@ -9,5 +9,5 @@ struct Z : X<int> { }; ...@@ -9,5 +9,5 @@ struct Z : X<int> { };
int main() int main()
{ {
Z z; Z z;
z.X::f(); // { dg-error "template parameters" "" } z.X::f();
} }
// 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" }
...@@ -342,7 +342,7 @@ operator>=(const SetLD<T>& a, const SetLD<T>& b) ...@@ -342,7 +342,7 @@ operator>=(const SetLD<T>& a, const SetLD<T>& b)
{ return ! (a < b); } { return ! (a < b); }
class String { }; class String { };
class IcaseString: public 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==" } 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; const SetLD_String_IcaseString_old_tmp99& oa = a;
......
...@@ -11,5 +11,5 @@ class Y : public X<int> ...@@ -11,5 +11,5 @@ class Y : public X<int>
void Y::f() void Y::f()
{ {
X x; // { dg-error "" } X is not a type. X x;
} }
...@@ -24,7 +24,7 @@ template<template<class> class DD,class EE> int C<DD,EE>::f() ...@@ -24,7 +24,7 @@ template<template<class> class DD,class EE> int C<DD,EE>::f()
class E : C<D,int> class E : C<D,int>
{ {
public: public:
int f() { return C<D,int>::f(); } int f() { return C< ::D,int>::f(); }
}; };
int main() int main()
......
...@@ -24,7 +24,7 @@ template<template<class> class E,class D> int C<E,D>::f() ...@@ -24,7 +24,7 @@ template<template<class> class E,class D> int C<E,D>::f()
class E : C<D,int> class E : C<D,int>
{ {
public: public:
int f() { return C<D,int>::f(); } int f() { return C< ::D,int>::f(); }
}; };
int main() int main()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment