Commit 1cb801bc by Jason Merrill Committed by Jason Merrill

re PR c++/9634 ([DR224] Injected class name as qualifier should not make the name dependent)

        PR c++/9634
        PR c++/29469
        PR c++/29607
        * decl.c (make_typename_type): Do look inside currently open classes.
        * parser.c (cp_parser_lookup_name): Likewise.
        (cp_parser_template_name): Likewise.
        * pt.c (dependent_scope_p): New function.
        * cp-tree.h: Declare it.
        * class.c (currently_open_class): Return fast if T isn't a class.

Co-Authored-By: Giovanni Bajo <giovannibajo@gcc.gnu.org>

From-SVN: r144618
parent f017bf5e
2009-03-04 Jason Merrill <jason@redhat.com>
PR c++/9634
PR c++/29469
PR c++/29607
* decl.c (make_typename_type): Do look inside currently open classes.
* parser.c (cp_parser_lookup_name): Likewise.
(cp_parser_template_name): Likewise.
* pt.c (dependent_scope_p): New function.
* cp-tree.h: Declare it.
* class.c (currently_open_class): Return fast if T isn't a class.
2009-02-26 H.J. Lu <hongjiu.lu@intel.com> 2009-02-26 H.J. Lu <hongjiu.lu@intel.com>
PR c++/37789 PR c++/37789
......
...@@ -5787,6 +5787,9 @@ currently_open_class (tree t) ...@@ -5787,6 +5787,9 @@ currently_open_class (tree t)
{ {
int i; int i;
if (!CLASS_TYPE_P (t))
return false;
/* We start looking from 1 because entry 0 is from global scope, /* We start looking from 1 because entry 0 is from global scope,
and has no type. */ and has no type. */
for (i = current_class_depth; i > 0; --i) for (i = current_class_depth; i > 0; --i)
......
...@@ -4594,6 +4594,7 @@ extern struct tinst_level *current_instantiation(void); ...@@ -4594,6 +4594,7 @@ extern struct tinst_level *current_instantiation(void);
extern tree maybe_get_template_decl_from_type_decl (tree); extern tree maybe_get_template_decl_from_type_decl (tree);
extern int processing_template_parmlist; extern int processing_template_parmlist;
extern bool dependent_type_p (tree); extern bool dependent_type_p (tree);
extern bool dependent_scope_p (tree);
extern bool any_dependent_template_arguments_p (const_tree); extern bool any_dependent_template_arguments_p (const_tree);
extern bool dependent_template_p (tree); extern bool dependent_template_p (tree);
extern bool dependent_template_id_p (tree, tree); extern bool dependent_template_id_p (tree, tree);
......
...@@ -2977,12 +2977,6 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, ...@@ -2977,12 +2977,6 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
gcc_assert (TYPE_P (context)); gcc_assert (TYPE_P (context));
/* 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 (!MAYBE_CLASS_TYPE_P (context)) if (!MAYBE_CLASS_TYPE_P (context))
{ {
if (complain & tf_error) if (complain & tf_error)
...@@ -2990,11 +2984,23 @@ make_typename_type (tree context, tree name, enum tag_types tag_type, ...@@ -2990,11 +2984,23 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
return error_mark_node; return error_mark_node;
} }
/* When the CONTEXT is a dependent type, NAME could refer to a
dependent base class of CONTEXT. But look inside it anyway
if CONTEXT is a currently open scope, in case it refers to a
member of the current instantiation or a non-dependent base;
lookup will stop when we hit a dependent base. */
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);
else
t = NULL_TREE;
if (!t && dependent_type_p (context))
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;
/* 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 (!t)
{ {
if (complain & tf_error) if (complain & tf_error)
......
...@@ -10323,7 +10323,7 @@ cp_parser_template_name (cp_parser* parser, ...@@ -10323,7 +10323,7 @@ cp_parser_template_name (cp_parser* parser,
&& !template_keyword_p && !template_keyword_p
&& parser->scope && TYPE_P (parser->scope) && parser->scope && TYPE_P (parser->scope)
&& check_dependency_p && check_dependency_p
&& dependent_type_p (parser->scope) && dependent_scope_p (parser->scope)
/* Do not do this for dtors (or ctors), since they never /* Do not do this for dtors (or ctors), since they never
need the template keyword before their name. */ need the template keyword before their name. */
&& !constructor_name_p (identifier, parser->scope)) && !constructor_name_p (identifier, parser->scope))
...@@ -17023,35 +17023,11 @@ cp_parser_lookup_name (cp_parser *parser, tree name, ...@@ -17023,35 +17023,11 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
cannot look up the name if the scope is not a class type; it cannot look up the name if the scope is not a class type; it
might, for example, be a template type parameter. */ might, for example, be a template type parameter. */
dependent_p = (TYPE_P (parser->scope) dependent_p = (TYPE_P (parser->scope)
&& !(parser->in_declarator_p && dependent_scope_p (parser->scope));
&& currently_open_class (parser->scope))
&& dependent_type_p (parser->scope));
if ((check_dependency || !CLASS_TYPE_P (parser->scope)) if ((check_dependency || !CLASS_TYPE_P (parser->scope))
&& dependent_p) && dependent_p)
{ /* Defer lookup. */
if (tag_type) decl = error_mark_node;
{
tree type;
/* The resolution to Core Issue 180 says that `struct
A::B' should be considered a type-name, even if `A'
is dependent. */
type = make_typename_type (parser->scope, name, tag_type,
/*complain=*/tf_error);
decl = TYPE_NAME (type);
}
else if (is_template
&& (cp_parser_next_token_ends_template_argument_p (parser)
|| cp_lexer_next_token_is (parser->lexer,
CPP_CLOSE_PAREN)))
decl = make_unbound_class_template (parser->scope,
name, NULL_TREE,
/*complain=*/tf_error);
else
decl = build_qualified_name (/*type=*/NULL_TREE,
parser->scope, name,
is_template);
}
else else
{ {
tree pushed_scope = NULL_TREE; tree pushed_scope = NULL_TREE;
...@@ -17072,14 +17048,42 @@ cp_parser_lookup_name (cp_parser *parser, tree name, ...@@ -17072,14 +17048,42 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
/*complain=*/true); /*complain=*/true);
/* If we have a single function from a using decl, pull it out. */ /* If we have a single function from a using decl, pull it out. */
if (decl if (TREE_CODE (decl) == OVERLOAD
&& TREE_CODE (decl) == OVERLOAD
&& !really_overloaded_fn (decl)) && !really_overloaded_fn (decl))
decl = OVL_FUNCTION (decl); decl = OVL_FUNCTION (decl);
if (pushed_scope) if (pushed_scope)
pop_scope (pushed_scope); pop_scope (pushed_scope);
} }
/* If the scope is a dependent type and either we deferred lookup or
we did lookup but didn't find the name, rememeber the name. */
if (decl == error_mark_node && TYPE_P (parser->scope)
&& dependent_type_p (parser->scope))
{
if (tag_type)
{
tree type;
/* The resolution to Core Issue 180 says that `struct
A::B' should be considered a type-name, even if `A'
is dependent. */
type = make_typename_type (parser->scope, name, tag_type,
/*complain=*/tf_error);
decl = TYPE_NAME (type);
}
else if (is_template
&& (cp_parser_next_token_ends_template_argument_p (parser)
|| cp_lexer_next_token_is (parser->lexer,
CPP_CLOSE_PAREN)))
decl = make_unbound_class_template (parser->scope,
name, NULL_TREE,
/*complain=*/tf_error);
else
decl = build_qualified_name (/*type=*/NULL_TREE,
parser->scope, name,
is_template);
}
parser->qualifying_scope = parser->scope; parser->qualifying_scope = parser->scope;
parser->object_scope = NULL_TREE; parser->object_scope = NULL_TREE;
} }
......
...@@ -16067,6 +16067,16 @@ dependent_type_p (tree type) ...@@ -16067,6 +16067,16 @@ dependent_type_p (tree type)
return TYPE_DEPENDENT_P (type); return TYPE_DEPENDENT_P (type);
} }
/* Returns TRUE if SCOPE is a dependent scope, in which we can't do any
lookup. In other words, a dependent type that is not the current
instantiation. */
bool
dependent_scope_p (tree scope)
{
return dependent_type_p (scope) && !currently_open_class (scope);
}
/* Returns TRUE if EXPRESSION is dependent, according to CRITERION. */ /* Returns TRUE if EXPRESSION is dependent, according to CRITERION. */
static bool static bool
...@@ -16088,7 +16098,7 @@ dependent_scope_ref_p (tree expression, bool criterion (tree)) ...@@ -16088,7 +16098,7 @@ dependent_scope_ref_p (tree expression, bool criterion (tree))
An id-expression is type-dependent if it contains a An id-expression is type-dependent if it contains a
nested-name-specifier that contains a class-name that names a nested-name-specifier that contains a class-name that names a
dependent type. */ dependent type. */
/* The suggested resolution to Core Issue 2 implies that if the /* The suggested resolution to Core Issue 224 implies that if the
qualifying type is the current class, then we must peek qualifying type is the current class, then we must peek
inside it. */ inside it. */
if (DECL_P (name) if (DECL_P (name)
......
2009-03-04 Jason Merrill <jason@redhat.com>
Giovanni Bajo <giovannibajo@gcc.gnu.org>
PR c++/9634
PR c++/29469
PR c++/29607
* g++.dg/template/dependent-name5.C: New test.
2009-03-04 Steve Ellcey <sje@cup.hp.com> 2009-03-04 Steve Ellcey <sje@cup.hp.com>
PR testsuite/39357 PR testsuite/39357
......
// PR c++/9634, c++/29469, c++/29607
// Contributed by: Giovanni Bajo <giovannibajo at gcc dot gnu dot org>
// DR224: Make sure that a name is *truly* semantically dependent.
struct D {
typedef int K;
};
template <typename T>
struct A
{
typedef int Bar;
template <typename>
struct N {};
typedef Bar type1;
typedef A::Bar type2;
typedef A<T>::Bar type3;
typedef A<T*>::Bar type4; // { dg-error "" }
typedef typename A<T*>::Bar type5;
typedef N<int> type6;
typedef A::N<int> type7;
typedef A<T>::N<int> type8;
typedef A<T*>::template N<int> type9; // { dg-error "" }
typedef typename A<T*>::template N<int> type10;
typedef D Bar2;
struct N2 { typedef int K; };
// Check that A::N2 is still considered dependent (because it
// could be specialized), while A::Bar2 (being just ::D) is not.
typedef A::Bar2 type11;
typedef type11::K k3;
typedef A::N2 type12;
typedef typename type12::K k2;
typedef type12::K k1; // { dg-error "" }
// Check that A::Bar2 is not considered dependent even if we use
// the typename keyword.
typedef typename A::Bar2 type13;
typedef type13::K k4;
};
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