On 04/19/2016 09:39 AM, Jason Merrill wrote:
cp_binding_level_find_binding_for_name can find a binding for a hidden friend declaration, in which case we shouldn't stop looking into anonymous namespaces. This bug blocked the use of N4381 customization points.
This caused 71173: when looking up the name before ::, we need to consider namespaces as well. Previously there was no way to communicate to lookup_qualified_name that we want a type or namespace; I've fixed that by changing the is_type_p parameter to be prefer_type with the same meaning as the parameter to lookup_name_real.
I've also added a pseudo-tag "scope_type" for communicating this situation from cp_parser_class_name to cp_parser_lookup_name.
scoped10.C is a test that we can still look past a namespace to find a class with the same name when appropriate; this has never worked in GCC before.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 5f75a91908143bde6092a10f42ee63265f340270 Author: Jason Merrill <ja...@redhat.com> Date: Wed May 25 11:51:53 2016 -0400 PR c++/71173 - wrong qualified lookup PR c++/70522 * cp-tree.h (enum tag_types): Add scope_type. * parser.c (cp_parser_class_name): Use scope_type. (prefer_type_arg): Handle scope_type. (cp_parser_lookup_name): Use prefer_type_arg. * name-lookup.c (lookup_qualified_name): Change bool is_type_p to int prefer_type, use lookup_flags. * name-lookup.h: Adjust. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ad21cdf..c2be21c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4601,7 +4601,8 @@ enum tag_types { class_type, /* "class" types. */ union_type, /* "union" types. */ enum_type, /* "enum" types. */ - typename_type /* "typename" types. */ + typename_type, /* "typename" types. */ + scope_type /* namespace or tagged type of a name followed by :: */ }; /* The various kinds of lvalues we distinguish. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index d32a153..eb128db 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4507,8 +4507,10 @@ unqualified_namespace_lookup (tree name, int flags) } /* Look up NAME (an IDENTIFIER_NODE) in SCOPE (either a NAMESPACE_DECL - or a class TYPE). If IS_TYPE_P is TRUE, then ignore non-type - bindings. + or a class TYPE). + + If PREFER_TYPE is > 0, we only return TYPE_DECLs or namespaces. + If PREFER_TYPE is > 1, we only return TYPE_DECLs. Returns a DECL (or OVERLOAD, or BASELINK) representing the declaration found. If no suitable declaration can be found, @@ -4516,28 +4518,25 @@ unqualified_namespace_lookup (tree name, int flags) neither a class-type nor a namespace a diagnostic is issued. */ tree -lookup_qualified_name (tree scope, tree name, bool is_type_p, bool complain, +lookup_qualified_name (tree scope, tree name, int prefer_type, bool complain, bool find_hidden) { - int flags = 0; tree t = NULL_TREE; - if (find_hidden) - flags |= LOOKUP_HIDDEN; - if (TREE_CODE (scope) == NAMESPACE_DECL) { struct scope_binding binding = EMPTY_SCOPE_BINDING; - if (is_type_p) - flags |= LOOKUP_PREFER_TYPES; + int flags = lookup_flags (prefer_type, /*namespaces_only*/false); + if (find_hidden) + flags |= LOOKUP_HIDDEN; if (qualified_lookup_using_namespace (name, scope, &binding, flags)) t = binding.value; } else if (cxx_dialect != cxx98 && TREE_CODE (scope) == ENUMERAL_TYPE) t = lookup_enumerator (scope, name); else if (is_class_type (scope, complain)) - t = lookup_member (scope, name, 2, is_type_p, tf_warning_or_error); + t = lookup_member (scope, name, 2, prefer_type, tf_warning_or_error); if (!t) return error_mark_node; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 7e39b6c..2f8447a 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -327,7 +327,7 @@ extern tree namespace_binding (tree, tree); extern void set_namespace_binding (tree, tree, tree); extern bool hidden_name_p (tree); extern tree remove_hidden_names (tree); -extern tree lookup_qualified_name (tree, tree, bool, bool, /*hidden*/bool = false); +extern tree lookup_qualified_name (tree, tree, int, bool, /*hidden*/bool = false); extern tree lookup_name_nonclass (tree); extern tree lookup_name_innermost_nonclass_level (tree); extern bool is_local_extern (tree); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d21230f..546aada 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21190,7 +21190,7 @@ cp_parser_class_name (cp_parser *parser, resolution operator, object, function, and enumerator names are ignored. */ if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)) - tag_type = typename_type; + tag_type = scope_type; /* Look up the name. */ decl = cp_parser_lookup_name (parser, identifier, tag_type, @@ -24595,6 +24595,24 @@ cp_parser_nested_requirement (cp_parser *parser) /* Support Functions */ +/* Return the appropriate prefer_type argument for lookup_name_real based on + tag_type and template_mem_access. */ + +static inline int +prefer_type_arg (tag_types tag_type, bool template_mem_access = false) +{ + /* DR 141: When looking in the current enclosing context for a template-name + after -> or ., only consider class templates. */ + if (template_mem_access) + return 2; + switch (tag_type) + { + case none_type: return 0; // No preference. + case scope_type: return 1; // Type or namespace. + default: return 2; // Type only. + } +} + /* Looks up NAME in the current scope, as given by PARSER->SCOPE. NAME should have one of the representations used for an id-expression. If NAME is the ERROR_MARK_NODE, the ERROR_MARK_NODE @@ -24731,7 +24749,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, errors may be issued. Even if we rollback the current tentative parse, those errors are valid. */ decl = lookup_qualified_name (parser->scope, name, - tag_type != none_type, + prefer_type_arg (tag_type), /*complain=*/true); /* 3.4.3.1: In a lookup in which the constructor is an acceptable @@ -24752,7 +24770,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, && DECL_SELF_REFERENCE_P (decl) && same_type_p (DECL_CONTEXT (decl), parser->scope)) decl = lookup_qualified_name (parser->scope, ctor_identifier, - tag_type != none_type, + prefer_type_arg (tag_type), /*complain=*/true); /* If we have a single function from a using decl, pull it out. */ @@ -24808,7 +24826,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, decl = lookup_member (object_type, name, /*protect=*/0, - tag_type != none_type, + prefer_type_arg (tag_type), tf_warning_or_error); else decl = NULL_TREE; @@ -24816,7 +24834,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, if (!decl) /* Look it up in the enclosing context. DR 141: When looking for a template-name after -> or ., only consider class templates. */ - decl = lookup_name_real (name, tag_type != none_type || is_template, + decl = lookup_name_real (name, prefer_type_arg (tag_type, is_template), /*nonclass=*/0, /*block_p=*/true, is_namespace, 0); if (object_type == unknown_type_node) @@ -24828,7 +24846,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, } else { - decl = lookup_name_real (name, tag_type != none_type, + decl = lookup_name_real (name, prefer_type_arg (tag_type), /*nonclass=*/0, /*block_p=*/true, is_namespace, 0); parser->qualifying_scope = NULL_TREE; diff --git a/gcc/testsuite/g++.dg/lookup/scoped10.C b/gcc/testsuite/g++.dg/lookup/scoped10.C new file mode 100644 index 0000000..c604297 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped10.C @@ -0,0 +1,5 @@ +namespace A { } +namespace N { struct A; } +using namespace N; + +struct ::A *p; diff --git a/gcc/testsuite/g++.dg/lookup/scoped9.C b/gcc/testsuite/g++.dg/lookup/scoped9.C new file mode 100644 index 0000000..06f0902 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/scoped9.C @@ -0,0 +1,10 @@ +// PR c++/71173 + +namespace foo { + namespace bar { + class foo {}; + } + class baz {}; +} +using namespace foo::bar; +::foo::baz mybaz;