+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
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;
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)
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),
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,
/* 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. */
/* 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)
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)
{
complain, in_decl,
args))
{
- val = orig_arg;
+ val = arg;
/* TEMPLATE_TEMPLATE_PARM node is preferred over
TEMPLATE_DECL. */
{
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
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;
}
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 *);
\f
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.
}
}
- /* 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
+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
int main()
{
Z z;
- z.X::f(); // { dg-error "template parameters" "" }
+ z.X::f();
}
--- /dev/null
+// 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" }
{ 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;
void Y::f()
{
- X x; // { dg-error "" } X is not a type.
+ X x;
}
class E : C<D,int>
{
public:
- int f() { return C<D,int>::f(); }
+ int f() { return C< ::D,int>::f(); }
};
int main()
class E : C<D,int>
{
public:
- int f() { return C<D,int>::f(); }
+ int f() { return C< ::D,int>::f(); }
};
int main()