diff mbox

C++ PATCH for c++/70522 (friend hides name in unnamed namespace)

Message ID 5209b005-4f84-f768-ec07-df156a989fe7@redhat.com
State New
Headers show

Commit Message

Jason Merrill May 25, 2016, 6:25 p.m. UTC
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.
diff mbox

Patch

commit 5f75a91908143bde6092a10f42ee63265f340270
Author: Jason Merrill <jason@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;