diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c3bb4f32614..629ba67d3f0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2006-08-25 Nathan Sidwell + + PR c++/27787 + * decl.c (make_typename_type): Only try and resolve it when + context is not dependent. Refactor. + * decl2.c (check_classfn): Push to class scope before looking for + the function. + 2006-08-24 Danny Smith PR driver/28528 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f45459603ad..8ba2a13578a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2779,6 +2779,8 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, tsubst_flags_t complain) { tree fullname; + tree t; + bool want_template; if (name == error_mark_node || context == NULL_TREE @@ -2816,73 +2818,60 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); gcc_assert (TYPE_P (context)); - if (!dependent_type_p (context) - || currently_open_class (context)) - { - if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR) - { - tree tmpl = NULL_TREE; - if (IS_AGGR_TYPE (context)) - tmpl = lookup_field (context, name, 0, false); - if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) - { - if (complain & tf_error) - error ("no class template named %q#T in %q#T", - name, context); - return error_mark_node; - } + /* When the CONTEXT is a dependent type, NAME could refer to a + dependent base class of CONTEXT. So we cannot peek inside it, + even if CONTEXT is a currently open scope. */ + if (dependent_type_p (context)) + return build_typename_type (context, name, fullname, tag_type); - if (complain & tf_error) - perform_or_defer_access_check (TYPE_BINFO (context), tmpl); - - return lookup_template_class (tmpl, - TREE_OPERAND (fullname, 1), - NULL_TREE, context, - /*entering_scope=*/0, - tf_warning_or_error | tf_user); - } - else - { - tree t; - - if (!IS_AGGR_TYPE (context)) - { - if (complain & tf_error) - error ("no type named %q#T in %q#T", name, context); - return error_mark_node; - } - - t = lookup_field (context, name, 0, true); - if (t) - { - if (TREE_CODE (t) != TYPE_DECL) - { - if (complain & tf_error) - error ("no type named %q#T in %q#T", name, context); - return error_mark_node; - } - - if (complain & tf_error) - perform_or_defer_access_check (TYPE_BINFO (context), t); - - if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) - t = TREE_TYPE (t); - - return t; - } - } - } - - /* If the CONTEXT is not a template type, then either the field is - there now or its never going to be. */ - if (!dependent_type_p (context)) + if (!IS_AGGR_TYPE (context)) { if (complain & tf_error) - error ("no type named %q#T in %q#T", name, context); + error ("%q#T is not a class", context); return error_mark_node; } + + want_template = TREE_CODE (fullname) == TEMPLATE_ID_EXPR; + + /* 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); + if (!t) + { + if (complain & tf_error) + error (want_template ? "no class template named %q#T in %q#T" + : "no type named %q#T in %q#T", name, context); + return error_mark_node; + } + + if (want_template && !DECL_CLASS_TEMPLATE_P (t)) + { + if (complain & tf_error) + error ("% names %q#T, which is not a class template", + context, name, t); + return error_mark_node; + } + if (!want_template && TREE_CODE (t) != TYPE_DECL) + { + if (complain & tf_error) + error ("% names %q#T, which is not a type", + context, name, t); + return error_mark_node; + } + + if (complain & tf_error) + perform_or_defer_access_check (TYPE_BINFO (context), t); - return build_typename_type (context, name, fullname, tag_type); + if (want_template) + return lookup_template_class (t, TREE_OPERAND (fullname, 1), + NULL_TREE, context, + /*entering_scope=*/0, + tf_warning_or_error | tf_user); + + if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl)) + t = TREE_TYPE (t); + + return t; } /* Resolve `CONTEXT::template NAME'. Returns a TEMPLATE_DECL if the name diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 0de2756620e..db1e9179a2b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -553,7 +553,8 @@ check_classfn (tree ctype, tree function, tree template_parms) { int ix; bool is_template; - + tree pushed_scope; + if (DECL_USE_TEMPLATE (function) && !(TREE_CODE (function) == TEMPLATE_DECL && DECL_TEMPLATE_SPECIALIZATION (function)) @@ -583,16 +584,18 @@ check_classfn (tree ctype, tree function, tree template_parms) /* OK, is this a definition of a member template? */ is_template = (template_parms != NULL_TREE); + /* We must enter the scope here, because conversion operators are + named by target type, and type equivalence relies on typenames + resolving within the scope of CTYPE. */ + pushed_scope = push_scope (ctype); ix = class_method_index_for_fn (complete_type (ctype), function); if (ix >= 0) { VEC(tree,gc) *methods = CLASSTYPE_METHOD_VEC (ctype); tree fndecls, fndecl = 0; bool is_conv_op; - tree pushed_scope; const char *format = NULL; - pushed_scope = push_scope (ctype); for (fndecls = VEC_index (tree, methods, ix); fndecls; fndecls = OVL_NEXT (fndecls)) { @@ -631,10 +634,13 @@ check_classfn (tree ctype, tree function, tree template_parms) == DECL_TI_TEMPLATE (fndecl)))) break; } - if (pushed_scope) - pop_scope (pushed_scope); if (fndecls) - return OVL_CURRENT (fndecls); + { + if (pushed_scope) + pop_scope (pushed_scope); + return OVL_CURRENT (fndecls); + } + error ("prototype for %q#D does not match any in class %qT", function, ctype); is_conv_op = DECL_CONV_FN_P (fndecl); @@ -682,6 +688,9 @@ check_classfn (tree ctype, tree function, tree template_parms) properly within the class. */ if (COMPLETE_TYPE_P (ctype)) add_method (ctype, function, NULL_TREE); + + if (pushed_scope) + pop_scope (pushed_scope); return NULL_TREE; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2a1485c2da3..8e9e60a35ae 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2006-08-25 Nathan Sidwell + + PR c++/27787 + * g++.dg/template/typename10.C: New. + * g++.dg/template/lookup4.C: Remove bogus error marker. + 2006-08-25 Richard Guenther PR testsuite/28829 diff --git a/gcc/testsuite/g++.dg/template/lookup4.C b/gcc/testsuite/g++.dg/template/lookup4.C index d64006133c3..3bd73a34e60 100644 --- a/gcc/testsuite/g++.dg/template/lookup4.C +++ b/gcc/testsuite/g++.dg/template/lookup4.C @@ -2,5 +2,5 @@ template struct Base {}; template struct Derived: public Base { - typename Derived::template Base* p1; // { dg-error "" } + typename Derived::template Base* p1; }; diff --git a/gcc/testsuite/g++.dg/template/typename10.C b/gcc/testsuite/g++.dg/template/typename10.C new file mode 100644 index 00000000000..f6f9931dfaf --- /dev/null +++ b/gcc/testsuite/g++.dg/template/typename10.C @@ -0,0 +1,24 @@ +// { dg-do compile } + +// Copyright (C) 2006 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 25 Aug 2006 + +// Origin: Tobias Schwinger +// PR 27787. Too eager to resolve a typename + +template +struct x +{ + template + struct y + { + typedef Y type; + }; +}; + +template +struct a : x +{ + template + typename a::template y::type f(B); +};