This fixes 81124, where we used ovl_iterate to iterate over a lookup
result. We should always use lkp_iterate in those circumstances.
However, regular lookup is not what we want here. We don't want to
follow using directives -- just look in the local inline hierarchy.
Plus also ignore decls found by using declarations.
Finally, I could also fix 79766, by moving the excessive-qualification
check to after finding the decl. '::foo' is perfectly fine to discover
foo in an inline child namespace.
nathan
--
Nathan Sidwell
2017-06-19 Nathan Sidwell <nat...@acm.org>
PR c++/81124
PR c++/79766
* name-lookup.c (set_decl_namespace): Don't follow using
directives and ignore using decls. Only check overly-explicit
scope after discovering decl.
* g++.dg/lookup/pr79766.C: New.
* g++.dg/lookup/pr81124.C: New.
* g++.dg/template/explicit6.C: Adjust.
* g++.old-deja/g++.other/decl5.C: Adjust.
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c (revision 249369)
+++ cp/name-lookup.c (working copy)
@@ -4266,8 +4266,6 @@ set_global_binding (tree name, tree val)
void
set_decl_namespace (tree decl, tree scope, bool friendp)
{
- tree old;
-
/* Get rid of namespace aliases. */
scope = ORIGINAL_NAMESPACE (scope);
@@ -4277,41 +4275,49 @@ set_decl_namespace (tree decl, tree scop
decl, scope);
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
- /* Writing "int N::i" to declare a variable within "N" is invalid. */
- if (scope == current_namespace)
- {
- if (at_namespace_scope_p ())
- error ("explicit qualification in declaration of %qD",
- decl);
- return;
- }
+ /* See whether this has been declared in the namespace or inline
+ children. */
+ tree old = NULL_TREE;
+ {
+ name_lookup lookup (DECL_NAME (decl), LOOKUP_HIDDEN);
+ if (!lookup.search_qualified (scope, /*usings=*/false))
+ /* No old declaration at all. */
+ goto not_found;
+ old = lookup.value;
+ }
- /* See whether this has been declared in the namespace. */
- old = lookup_qualified_name (scope, DECL_NAME (decl), /*type*/false,
- /*complain*/true, /*hidden*/true);
- if (old == error_mark_node)
- /* No old declaration at all. */
- goto complain;
/* If it's a TREE_LIST, the result of the lookup was ambiguous. */
if (TREE_CODE (old) == TREE_LIST)
{
+ ambiguous:
+ DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
error ("reference to %qD is ambiguous", decl);
print_candidates (old);
return;
}
- if (!OVL_P (decl))
+
+ if (!DECL_DECLARES_FUNCTION_P (decl))
{
- /* We might have found OLD in an inline namespace inside SCOPE. */
- if (TREE_CODE (decl) == TREE_CODE (old))
- DECL_CONTEXT (decl) = DECL_CONTEXT (old);
/* Don't compare non-function decls with decls_match here, since
it can't check for the correct constness at this
- point. pushdecl will find those errors later. */
+ point. pushdecl will find those errors later. */
+
+ /* We might have found it in an inline namespace child of SCOPE. */
+ if (TREE_CODE (decl) == TREE_CODE (old))
+ DECL_CONTEXT (decl) = DECL_CONTEXT (old);
+
+ found:
+ /* Writing "N::i" to declare something directly in "N" is invalid. */
+ if (CP_DECL_CONTEXT (decl) == current_namespace
+ && at_namespace_scope_p ())
+ error ("explicit qualification in declaration of %qD", decl);
return;
}
+
/* Since decl is a function, old should contain a function decl. */
if (!OVL_P (old))
- goto complain;
+ goto not_found;
+
/* We handle these in check_explicit_instantiation_namespace. */
if (processing_explicit_instantiation)
return;
@@ -4325,53 +4331,48 @@ set_decl_namespace (tree decl, tree scop
friends in any namespace. */
if (friendp && DECL_USE_TEMPLATE (decl))
return;
- if (OVL_P (old))
+
+ tree found;
+ found = NULL_TREE;
+
+ for (lkp_iterator iter (old); iter; ++iter)
{
- tree found = NULL_TREE;
+ if (iter.using_p ())
+ continue;
- for (ovl_iterator iter (old); iter; ++iter)
- {
- tree ofn = *iter;
- /* Adjust DECL_CONTEXT first so decls_match will return true
- if DECL will match a declaration in an inline namespace. */
- DECL_CONTEXT (decl) = DECL_CONTEXT (ofn);
- if (decls_match (decl, ofn))
- {
- if (found && !decls_match (found, ofn))
- {
- DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
- error ("reference to %qD is ambiguous", decl);
- print_candidates (old);
- return;
- }
- found = ofn;
- }
- }
- if (found)
+ tree ofn = *iter;
+
+ /* Adjust DECL_CONTEXT first so decls_match will return true
+ if DECL will match a declaration in an inline namespace. */
+ DECL_CONTEXT (decl) = DECL_CONTEXT (ofn);
+ if (decls_match (decl, ofn))
{
- if (!is_nested_namespace (scope, CP_DECL_CONTEXT (found), true))
- goto complain;
- if (DECL_HIDDEN_FRIEND_P (found))
+ if (found)
{
- pedwarn (DECL_SOURCE_LOCATION (decl), 0,
- "%qD has not been declared within %qD", decl, scope);
- inform (DECL_SOURCE_LOCATION (found),
- "only here as a %<friend%>");
+ /* We found more than one matching declaration. */
+ DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
+ goto ambiguous;
}
- DECL_CONTEXT (decl) = DECL_CONTEXT (found);
- return;
+ found = ofn;
}
}
- else
+
+ if (found)
{
- DECL_CONTEXT (decl) = DECL_CONTEXT (old);
- if (decls_match (decl, old))
- return;
+ if (DECL_HIDDEN_FRIEND_P (found))
+ {
+ pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+ "%qD has not been declared within %qD", decl, scope);
+ inform (DECL_SOURCE_LOCATION (found),
+ "only here as a %<friend%>");
+ }
+ DECL_CONTEXT (decl) = DECL_CONTEXT (found);
+ goto found;
}
+ not_found:
/* It didn't work, go back to the explicit scope. */
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
- complain:
error ("%qD should have been declared inside %qD", decl, scope);
}
Index: testsuite/g++.dg/lookup/pr79766.C
===================================================================
--- testsuite/g++.dg/lookup/pr79766.C (nonexistent)
+++ testsuite/g++.dg/lookup/pr79766.C (working copy)
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+// PR 79766 qualified name to find inline namespace is ok
+
+namespace Y
+{
+ inline namespace X
+ {
+ void Q ();
+ }
+}
+
+void Y::Q () // OK -> Y::X::Q
+{
+}
+
+inline namespace Z
+{
+ void R ();
+}
+
+void ::R () // OK -> Z::R
+{
+}
+
+void S ();
+
+void ::S () // { dg-error "explicit qualification" }
+{
+}
Index: testsuite/g++.dg/lookup/pr81124.C
===================================================================
--- testsuite/g++.dg/lookup/pr81124.C (nonexistent)
+++ testsuite/g++.dg/lookup/pr81124.C (working copy)
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+// c++/81124 ICE with inline namespace
+
+namespace std {
+inline namespace {
+int to_string();
+void to_string(int);
+}
+void to_string();
+}
+int std::to_string();
Index: testsuite/g++.dg/template/explicit6.C
===================================================================
--- testsuite/g++.dg/template/explicit6.C (revision 249364)
+++ testsuite/g++.dg/template/explicit6.C (working copy)
@@ -5,4 +5,4 @@
// Bug 19895: ICE on invalid
struct A;
-template A<>::A(); // { dg-error "(not a template)|(explicit qualification)" }
+template A<>::A(); // { dg-error "(should have been)|(not a template)" }
Index: testsuite/g++.old-deja/g++.other/decl5.C
===================================================================
--- testsuite/g++.old-deja/g++.other/decl5.C (revision 249364)
+++ testsuite/g++.old-deja/g++.other/decl5.C (working copy)
@@ -53,8 +53,8 @@ namespace N {
namespace NMS
{
- void NMS::fn(); // { dg-error "explicit qual" }
- int NMS::i; // { dg-error "explicit qual" }
+ void NMS::fn(); // { dg-error "should have been" }
+ int NMS::i; // { dg-error "should have been" }
struct NMS::D { // { dg-error "does not name a class" }
int i;
};