aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>2004-11-25 16:55:34 +0000
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>2004-11-25 16:55:34 +0000
commit29ef83dee9acfdee32507bff8c536ae26f922402 (patch)
tree09d2e60d7ceba6434ad38c297762a3642c26dfda /gcc
parent3c13948a7e6fcce9f01ae3ec4f6153fb9d696fa6 (diff)
downloadgcc-29ef83dee9acfdee32507bff8c536ae26f922402.zip
gcc-29ef83dee9acfdee32507bff8c536ae26f922402.tar.gz
gcc-29ef83dee9acfdee32507bff8c536ae26f922402.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog21
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c49
-rw-r--r--gcc/cp/name-lookup.c52
-rw-r--r--gcc/cp/name-lookup.h18
-rw-r--r--gcc/cp/parser.c20
-rw-r--r--gcc/cp/pt.c5
-rw-r--r--gcc/cp/rtti.c8
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/lookup/friend2.C21
-rw-r--r--gcc/testsuite/g++.dg/template/friend31.C27
11 files changed, 176 insertions, 55 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1b89a1d..8acfe55b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,24 @@
+2004-11-25 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ 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 <joseph@codesourcery.com>
* 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 64f5ab9..0f0bfb2 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 c47c342..98ca4f9 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 29b93ff..a018862 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 b43fa1e..08a9ba5 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 1a97868..3548b45 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 c171f31..b514cc1 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 9bb2c36..cf66904 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 f41d675..e82c3fd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2004-11-25 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ 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 <dave.anglin@nrc-cnrc.gc.ca>
* 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 0000000..765c69b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/friend2.C
@@ -0,0 +1,21 @@
+// { dg-do compile }
+
+// Origin: Albert Chin <bugzilla-gcc@thewrittenword.com>
+// Wolfgang Bangerth <bangerth@dealii.org>
+
+// 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 0000000..2d62f87
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend31.C
@@ -0,0 +1,27 @@
+// { dg-do compile }
+
+// Origin: Ivan Godard <igodard@pacbell.net>
+
+// PR c++/15410: Declaration of friend class template with wrong
+// template parameter.
+
+template <typename T, typename U> struct F; // { dg-error "previous declaration" }
+
+class W
+{
+ template<int i> friend class F; // { dg-error "template parameter" }
+ int x;
+};
+
+template <typename T, typename U> struct F
+{
+ void Look(W& w) { w.x = 3; }
+};
+
+int main()
+{
+ W w;
+ F<char, bool> f;
+ f.Look(w);
+ return 0;
+}