From 29ef83dee9acfdee32507bff8c536ae26f922402 Mon Sep 17 00:00:00 2001 From: Kriang Lerdsuwanakij Date: Thu, 25 Nov 2004 16:55:34 +0000 Subject: [PATCH] Friend class name lookup 2/n, PR c++/14513, c++/15410 Friend class name lookup 2/n, PR c++/14513, c++/15410 * name-lookup.c (lookup_name_real): Simplify. (lookup_type_scope): Add SCOPE parameter. Handle friend class lookup. * name-lookup.h (tag_scope): New enum type. (lookup_type_scope): Adjust declaration. * decl.c (lookup_and_check_tag, xref_tag, xref_tag_from_type): Change bool parameter GLOBALIZED to TAG_SCOPE parameter SCOPE. (start_enum): Likewise. Add assertion test that NAME is IDENTIFIER_NODE. Use anonymous name for dummy ENUMERAL_TYPE in case of error. * cp-tree.h (xref_tag, xref_tag_from_type): Adjust declarations. * parser.c (cp_parser_elaborated_type_specifier, cp_parser_class_head): Adjust call to xref_tag. * pt.c (lookup_template_class, instantiate_class_template): Likewise. * rtti.c (init_rtti_processing, build_dynamic_cast_1, tinfo_base_init, emit_support_tinfos): Likewise. * g++.dg/lookup/friend2.C: New test. * g++.dg/template/friend31.C: Likewise. From-SVN: r91299 --- gcc/cp/ChangeLog | 21 ++++++++++ gcc/cp/cp-tree.h | 4 +- gcc/cp/decl.c | 49 +++++++++++++--------- gcc/cp/name-lookup.c | 52 ++++++++++++++---------- gcc/cp/name-lookup.h | 18 +++++++- gcc/cp/parser.c | 20 ++++++--- gcc/cp/pt.c | 5 ++- gcc/cp/rtti.c | 8 ++-- gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/g++.dg/lookup/friend2.C | 21 ++++++++++ gcc/testsuite/g++.dg/template/friend31.C | 27 ++++++++++++ 11 files changed, 176 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/friend2.C create mode 100644 gcc/testsuite/g++.dg/template/friend31.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1b89a1d3ba4..8acfe55b86b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2004-11-25 Kriang Lerdsuwanakij + + Friend class name lookup 2/n, PR c++/14513, c++/15410 + * name-lookup.c (lookup_name_real): Simplify. + (lookup_type_scope): Add SCOPE parameter. Handle friend class + lookup. + * name-lookup.h (tag_scope): New enum type. + (lookup_type_scope): Adjust declaration. + * decl.c (lookup_and_check_tag, xref_tag, xref_tag_from_type): + Change bool parameter GLOBALIZED to TAG_SCOPE parameter SCOPE. + (start_enum): Likewise. Add assertion test that NAME is + IDENTIFIER_NODE. Use anonymous name for dummy ENUMERAL_TYPE in + case of error. + * cp-tree.h (xref_tag, xref_tag_from_type): Adjust declarations. + * parser.c (cp_parser_elaborated_type_specifier, + cp_parser_class_head): Adjust call to xref_tag. + * pt.c (lookup_template_class, instantiate_class_template): + Likewise. + * rtti.c (init_rtti_processing, build_dynamic_cast_1, + tinfo_base_init, emit_support_tinfos): Likewise. + 2004-11-25 Joseph S. Myers * g++spec.c, lex.c: Avoid ` as left quote in diagnostics. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 64f5ab9b8ad..0f0bfb29067 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3745,8 +3745,8 @@ extern tree get_scope_of_declarator (const cp_declarator *); extern void grok_special_member_properties (tree); extern int grok_ctor_properties (tree, tree); extern bool grok_op_properties (tree, int, bool); -extern tree xref_tag (enum tag_types, tree, bool, bool); -extern tree xref_tag_from_type (tree, tree, int); +extern tree xref_tag (enum tag_types, tree, tag_scope, bool); +extern tree xref_tag_from_type (tree, tree, tag_scope); extern void xref_basetypes (tree, tree); extern tree start_enum (tree); extern void finish_enum (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c47c342bc6f..98ca4f944ad 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -82,7 +82,7 @@ static int typename_compare (const void *, const void *); static tree local_variable_p_walkfn (tree *, int *, void *); static tree record_builtin_java_type (const char *, int); static const char *tag_name (enum tag_types); -static tree lookup_and_check_tag (enum tag_types, tree, bool globalize, bool); +static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool); static int walk_namespaces_r (tree, walk_namespaces_fn, void *); static int walk_globals_r (tree, void*); static int walk_vtables_r (tree, void*); @@ -9122,20 +9122,20 @@ check_elaborated_type_specifier (enum tag_types tag_code, } /* Lookup NAME in elaborate type specifier in scope according to - GLOBALIZE and issue diagnostics if necessary. + SCOPE and issue diagnostics if necessary. Return *_TYPE node upon success, NULL_TREE when the NAME is not found, and ERROR_MARK_NODE for type error. */ static tree lookup_and_check_tag (enum tag_types tag_code, tree name, - bool globalize, bool template_header_p) + tag_scope scope, bool template_header_p) { tree t; tree decl; - if (globalize) + if (scope == ts_global) decl = lookup_name (name, 2); else - decl = lookup_type_scope (name); + decl = lookup_type_scope (name, scope); if (decl && DECL_CLASS_TEMPLATE_P (decl)) decl = DECL_TEMPLATE_RESULT (decl); @@ -9174,16 +9174,18 @@ lookup_and_check_tag (enum tag_types tag_code, tree name, If a declaration is given, process it here, and report an error if multiple declarations are not identical. - GLOBALIZE is false when this is also a definition. Only look in + SCOPE is TS_CURRENT when this is also a definition. Only look in the current frame for the name (since C++ allows new names in any - scope.) + scope.) It is TS_WITHIN_ENCLOSING_NON_CLASS if this is a friend + declaration. Only look beginning from the current scope outward up + till the nearest non-class scope. Otherwise it is TS_GLOBAL. TEMPLATE_HEADER_P is true when this declaration is preceded by a set of template parameters. */ tree xref_tag (enum tag_types tag_code, tree name, - bool globalize, bool template_header_p) + tag_scope scope, bool template_header_p) { enum tree_code code; tree t; @@ -9215,16 +9217,16 @@ xref_tag (enum tag_types tag_code, tree name, t = NULL_TREE; else t = lookup_and_check_tag (tag_code, name, - globalize, template_header_p); + scope, template_header_p); if (t == error_mark_node) POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node); - if (globalize && t && current_class_type + if (scope != ts_current && t && current_class_type && template_class_depth (current_class_type) && template_header_p) { - /* Since GLOBALIZE is nonzero, we are not looking at a + /* Since SCOPE is not TS_CURRENT, we are not looking at a definition of this tag. Since, in addition, we are currently processing a (member) template declaration of a template class, we must be very careful; consider: @@ -9279,12 +9281,13 @@ xref_tag (enum tag_types tag_code, tree name, { t = make_aggr_type (code); TYPE_CONTEXT (t) = context; - pushtag (name, t, globalize); + /* pushtag only cares whether SCOPE is zero or not. */ + pushtag (name, t, scope != ts_current); } } else { - if (!globalize && processing_template_decl && IS_AGGR_TYPE (t)) + if (template_header_p && IS_AGGR_TYPE (t)) redeclare_class_template (t, current_template_parms); else if (!processing_template_decl && CLASS_TYPE_P (t) @@ -9299,7 +9302,7 @@ xref_tag (enum tag_types tag_code, tree name, } tree -xref_tag_from_type (tree old, tree id, int globalize) +xref_tag_from_type (tree old, tree id, tag_scope scope) { enum tag_types tag_kind; @@ -9311,7 +9314,7 @@ xref_tag_from_type (tree old, tree id, int globalize) if (id == NULL_TREE) id = TYPE_IDENTIFIER (old); - return xref_tag (tag_kind, id, globalize, false); + return xref_tag (tag_kind, id, scope, false); } /* Create the binfo hierarchy for REF with (possibly NULL) base list @@ -9499,7 +9502,7 @@ xref_basetypes (tree ref, tree base_list) /* Begin compiling the definition of an enumeration type. - NAME is its name (or null if anonymous). + NAME is its name. Returns the type object, as yet incomplete. Also records info about it so that build_enumerator may be used to declare the individual values as they are read. */ @@ -9507,14 +9510,17 @@ xref_basetypes (tree ref, tree base_list) tree start_enum (tree name) { - tree enumtype = NULL_TREE; + tree enumtype; + + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); /* If this is the real definition for a previous forward reference, fill in the contents in the same object that used to be the forward reference. */ - if (name != NULL_TREE) - enumtype = lookup_and_check_tag (enum_type, name, 0, 0); + enumtype = lookup_and_check_tag (enum_type, name, + /*tag_scope=*/ts_current, + /*template_header_p=*/false); if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE) { @@ -9525,6 +9531,11 @@ start_enum (tree name) } else { + /* In case of error, make a dummy enum to allow parsing to + continue. */ + if (enumtype == error_mark_node) + name = make_anon_name (); + enumtype = make_node (ENUMERAL_TYPE); pushtag (name, enumtype, 0); } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 29b93ffe921..a0188620759 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4088,11 +4088,7 @@ lookup_name_real (tree name, int prefer_type, int nonclass, bool block_p, /* Now lookup in namespace scopes. */ if (!val) - { - tree t = unqualified_namespace_lookup (name, flags); - if (t) - val = t; - } + val = unqualified_namespace_lookup (name, flags); if (val) { @@ -4128,15 +4124,18 @@ lookup_name (tree name, int prefer_type) } /* Look up NAME for type used in elaborated name specifier in - the current scope (possibly more if cleanup or template parameter - scope is encounter). Unlike lookup_name_real, we make sure that - NAME is actually declared in the desired scope, not from inheritance, - using declaration, nor using directive. A TYPE_DECL best matching - the NAME is returned. Catching error and issuing diagnostics are - caller's responsibility. */ + the scopes given by SCOPE. SCOPE can be either TS_CURRENT or + TS_WITHIN_ENCLOSING_NON_CLASS (possibly more scope is checked if + cleanup or template parameter scope is encountered). + + Unlike lookup_name_real, we make sure that NAME is actually + declared in the desired scope, not from inheritance, using + declaration, nor using directive. A TYPE_DECL best matching + the NAME is returned. Catching error and issuing diagnostics + are caller's responsibility. */ tree -lookup_type_scope (tree name) +lookup_type_scope (tree name, tag_scope scope) { cxx_binding *iter = NULL; tree val = NULL_TREE; @@ -4149,19 +4148,22 @@ lookup_type_scope (tree name) for (; iter; iter = outer_binding (name, iter, /*class_p=*/ true)) { /* Check if this is the kind of thing we're looking for. - Make sure it doesn't come from base class. For ITER->VALUE, - we can simply use INHERITED_VALUE_BINDING_P. For ITER->TYPE, - we have to use our own check. + If SCOPE is TS_CURRENT, also make sure it doesn't come from + base class. For ITER->VALUE, we can simply use + INHERITED_VALUE_BINDING_P. For ITER->TYPE, we have to use + our own check. We check ITER->TYPE before ITER->VALUE in order to handle typedef struct C {} C; correctly. */ if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES) - && (LOCAL_BINDING_P (iter) + && (scope != ts_current + || LOCAL_BINDING_P (iter) || DECL_CONTEXT (iter->type) == iter->scope->this_entity)) val = iter->type; - else if (!INHERITED_VALUE_BINDING_P (iter) + else if ((scope != ts_current + || !INHERITED_VALUE_BINDING_P (iter)) && qualify_lookup (iter->value, LOOKUP_PREFER_TYPES)) val = iter->value; @@ -4177,16 +4179,21 @@ lookup_type_scope (tree name) if (iter) { - /* If this is the kind of thing we're looking for, we're done. */ - if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES)) + /* If this is the kind of thing we're looking for, we're done. + Ignore names found via using declaration. See DR138 for + current status. */ + if (qualify_lookup (iter->type, LOOKUP_PREFER_TYPES) + && (CP_DECL_CONTEXT (iter->type) == iter->scope->this_entity)) val = iter->type; - else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES)) + else if (qualify_lookup (iter->value, LOOKUP_PREFER_TYPES) + && (CP_DECL_CONTEXT (iter->value) + == iter->scope->this_entity)) val = iter->value; } } - /* Type found, check if it is in the current scope, ignoring cleanup + /* Type found, check if it is in the allowed scopes, ignoring cleanup and template parameter scopes. */ if (val) { @@ -4198,6 +4205,9 @@ lookup_type_scope (tree name) if (b->kind == sk_cleanup || b->kind == sk_template_parms) b = b->level_chain; + else if (b->kind == sk_class + && scope == ts_within_enclosing_non_class) + b = b->level_chain; else break; } diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index b43fa1e4f32..08a9ba504b9 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -125,6 +125,22 @@ typedef enum scope_kind { "template <>", this scope is always empty. */ } scope_kind; +/* The scope where the class/struct/union/enum tag applies. */ +typedef enum tag_scope { + ts_current = 0, /* Current scope only. This is for the + class-key identifier; + case mentioned in [basic.lookup.elab]/2, + or the class/enum definition + class-key identifier { ... }; */ + ts_global = 1, /* All scopes. This is the 3.4.1 + [basic.lookup.unqual] lookup mentioned + in [basic.lookup.elab]/2. */ + ts_within_enclosing_non_class = 2 /* Search within enclosing non-class + only, for friend class lookup + according to [namespace.memdef]/3 + and [class.friend]/9. */ +} tag_scope; + typedef struct cp_class_binding GTY(()) { cxx_binding base; @@ -303,7 +319,7 @@ extern tree lookup_tag (enum tree_code, tree, cxx_scope *, int); extern tree lookup_tag_reverse (tree, tree); extern tree lookup_name (tree, int); extern tree lookup_name_real (tree, int, int, bool, int, int); -extern tree lookup_type_scope (tree); +extern tree lookup_type_scope (tree, tag_scope); extern tree namespace_binding (tree, tree); extern void set_namespace_binding (tree, tree, tree); extern tree lookup_namespace_name (tree, tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1a9786845c4..3548b45c117 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -9731,15 +9731,23 @@ cp_parser_elaborated_type_specifier (cp_parser* parser, definition of a new type; a new type can only be declared in a declaration context. */ + tag_scope ts; + if (is_friend) + /* Friends have special name lookup rules. */ + ts = ts_within_enclosing_non_class; + else if (is_declaration + && cp_lexer_next_token_is (parser->lexer, + CPP_SEMICOLON)) + /* This is a `class-key identifier ;' */ + ts = ts_current; + else + ts = ts_global; + /* Warn about attributes. They are ignored. */ if (attributes) warning ("type attributes are honored only at type definition"); - type = xref_tag (tag_type, identifier, - (is_friend - || !is_declaration - || cp_lexer_next_token_is_not (parser->lexer, - CPP_SEMICOLON)), + type = xref_tag (tag_type, identifier, ts, parser->num_template_parameter_lists); } } @@ -12642,7 +12650,7 @@ cp_parser_class_head (cp_parser* parser, /* If the class was unnamed, create a dummy name. */ if (!id) id = make_anon_name (); - type = xref_tag (class_key, id, /*globalize=*/false, + type = xref_tag (class_key, id, /*tag_scope=*/ts_current, parser->num_template_parameter_lists); } else diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index c171f31b083..b514cc14301 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4576,7 +4576,7 @@ lookup_template_class (tree d1, { found = xref_tag_from_type (TREE_TYPE (template), DECL_NAME (template), - /*globalize=*/1); + /*tag_scope=*/ts_global); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found); } @@ -5788,7 +5788,8 @@ instantiate_class_template (tree type) classes. */ push_nested_namespace (ns); friend_type = - xref_tag_from_type (friend_type, NULL_TREE, 1); + xref_tag_from_type (friend_type, NULL_TREE, + /*tag_scope=*/ts_global); pop_nested_namespace (ns); } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 9bb2c364bbf..cf66904b9b6 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -113,7 +113,7 @@ init_rtti_processing (void) push_namespace (std_identifier); type_info_type_node = xref_tag (class_type, get_identifier ("type_info"), - true, false); + /*tag_scope=*/ts_global, false); pop_namespace (); const_type_info_type = build_qualified_type (type_info_type_node, TYPE_QUAL_CONST); @@ -628,7 +628,7 @@ build_dynamic_cast_1 (tree type, tree expr) push_nested_namespace (ns); tinfo_ptr = xref_tag (class_type, get_identifier ("__class_type_info"), - true, false); + /*tag_scope=*/ts_global, false); tinfo_ptr = build_pointer_type (build_qualified_type @@ -808,7 +808,7 @@ tinfo_base_init (tree desc, tree target) push_nested_namespace (abi_node); real_type = xref_tag (class_type, TINFO_REAL_NAME (desc), - true, false); + /*tag_scope=*/ts_global, false); pop_nested_namespace (abi_node); if (!COMPLETE_TYPE_P (real_type)) @@ -1340,7 +1340,7 @@ emit_support_tinfos (void) push_nested_namespace (abi_node); bltn_type = xref_tag (class_type, get_identifier ("__fundamental_type_info"), - true, false); + /*tag_scope=*/ts_global, false); pop_nested_namespace (abi_node); if (!COMPLETE_TYPE_P (bltn_type)) return; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f41d675b497..e82c3fd17db 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-11-25 Kriang Lerdsuwanakij + + Friend class name lookup 2/n, PR c++/14513, c++/15410 + * g++.dg/lookup/friend2.C: New test. + * g++.dg/template/friend31.C: Likewise. + 2004-11-24 John David Anglin * lib/target-libpath.exp (orig_ld_library_path_saved): Add missing set. diff --git a/gcc/testsuite/g++.dg/lookup/friend2.C b/gcc/testsuite/g++.dg/lookup/friend2.C new file mode 100644 index 00000000000..765c69b67eb --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/friend2.C @@ -0,0 +1,21 @@ +// { dg-do compile } + +// Origin: Albert Chin +// Wolfgang Bangerth + +// PR c++/14513, unqualified lookup of friend class. + +struct S { + void test (void); +}; + +namespace NS { + class X { + friend class S; + static int *i; // { dg-error "private" } + }; +} + +void S::test () { + NS::X::i; // { dg-error "this context" } +} diff --git a/gcc/testsuite/g++.dg/template/friend31.C b/gcc/testsuite/g++.dg/template/friend31.C new file mode 100644 index 00000000000..2d62f878a21 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/friend31.C @@ -0,0 +1,27 @@ +// { dg-do compile } + +// Origin: Ivan Godard + +// PR c++/15410: Declaration of friend class template with wrong +// template parameter. + +template struct F; // { dg-error "previous declaration" } + +class W +{ + template friend class F; // { dg-error "template parameter" } + int x; +}; + +template struct F +{ + void Look(W& w) { w.x = 3; } +}; + +int main() +{ + W w; + F f; + f.Look(w); + return 0; +} -- 2.30.2