2017-05-16 Nathan Sidwell * cp-tree.h (SCOPE_DEPTH): New. * name-lookup.h (is_nested_namespace): Declare. * name-lookup.c (is_nested_namespace): New. (is_ancestor): Use it. (set_decl_namespace): Likewise. (push_namespace): Set SCOPE_DEPTH. * pt.c (check_specialization_namespace): Use is_nested_namespace. (check_unqualigied_spec_or_inst): Likewise. Index: cp-tree.h =================================================================== --- cp-tree.h (revision 248094) +++ cp-tree.h (working copy) @@ -2917,6 +2917,11 @@ struct GTY(()) lang_decl { #define LOCAL_CLASS_P(NODE) \ (decl_function_context (TYPE_MAIN_DECL (NODE)) != NULL_TREE) +/* The nesting depth of namespace, class or function. Makes is_ancestor much + simpler. Only 8 bits available. */ +#define SCOPE_DEPTH(NODE) \ + (NAMESPACE_DECL_CHECK (NODE)->base.u.bits.address_space) + /* Whether the namepace is an inline namespace. */ #define DECL_NAMESPACE_INLINE_P(NODE) \ TREE_LANG_FLAG_0 (NAMESPACE_DECL_CHECK (NODE)) Index: name-lookup.c =================================================================== --- name-lookup.c (revision 248094) +++ name-lookup.c (working copy) @@ -3327,6 +3327,25 @@ do_local_using_decl (tree decl, tree sco cp_emit_debug_info_for_using (orig_decl, current_scope()); } +/* Returns true if ANCESTOR encloses DESCENDANT, including matching. + Both are namespaces. */ + +bool +is_nested_namespace (tree ancestor, tree descendant, bool inline_only) +{ + int depth = SCOPE_DEPTH (ancestor); + + if (!depth && !inline_only) + /* The global namespace encloses everything. */ + return true; + + while (SCOPE_DEPTH (descendant) > depth + && (!inline_only || DECL_NAMESPACE_INLINE_P (descendant))) + descendant = CP_DECL_CONTEXT (descendant); + + return ancestor == descendant; +} + /* Returns true if ROOT (a namespace, class, or function) encloses CHILD. CHILD may be either a class type or a namespace. */ @@ -3343,19 +3362,22 @@ is_ancestor (tree root, tree child) if (root == global_namespace) return true; - while (true) + /* Search until we reach namespace scope. */ + while (TREE_CODE (child) != NAMESPACE_DECL) { - /* If we've run out of scopes, stop. */ - if (!child) - return false; /* If we've reached the ROOT, it encloses CHILD. */ if (root == child) return true; /* Go out one level. */ if (TYPE_P (child)) child = TYPE_NAME (child); - child = DECL_CONTEXT (child); + child = CP_DECL_CONTEXT (child); } + + if (TREE_CODE (root) == NAMESPACE_DECL) + return is_nested_namespace (root, child); + + return false; } /* Enter the class or namespace scope indicated by T suitable for name @@ -4076,7 +4098,7 @@ set_decl_namespace (tree decl, tree scop scope = ORIGINAL_NAMESPACE (scope); /* It is ok for friends to be qualified in parallel space. */ - if (!friendp && !is_ancestor (current_namespace, scope)) + if (!friendp && !is_nested_namespace (current_namespace, scope)) error ("declaration of %qD not in a namespace surrounding %qD", decl, scope); DECL_CONTEXT (decl) = FROB_CONTEXT (scope); @@ -4153,7 +4175,7 @@ set_decl_namespace (tree decl, tree scop } if (found) { - if (!is_associated_namespace (scope, CP_DECL_CONTEXT (found))) + if (!is_nested_namespace (scope, CP_DECL_CONTEXT (found), true)) goto complain; if (DECL_HIDDEN_FRIEND_P (found)) { @@ -6499,6 +6521,11 @@ push_namespace (tree name, bool make_inl if (!ns) { ns = build_lang_decl (NAMESPACE_DECL, name, void_type_node); + SCOPE_DEPTH (ns) = SCOPE_DEPTH (current_namespace) + 1; + if (!SCOPE_DEPTH (ns)) + /* We only allow depth 255. */ + sorry ("cannot nest more than %d namespaces", + SCOPE_DEPTH (current_namespace)); DECL_CONTEXT (ns) = FROB_CONTEXT (current_namespace); new_ns = true; Index: name-lookup.h =================================================================== --- name-lookup.h (revision 248094) +++ name-lookup.h (working copy) @@ -292,6 +292,8 @@ extern void print_binding_stack (void); extern void pop_everything (void); extern void keep_next_level (bool); extern bool is_ancestor (tree ancestor, tree descendant); +extern bool is_nested_namespace (tree parent, tree descendant, + bool inline_only = false); extern tree push_scope (tree); extern void pop_scope (tree); extern tree push_inner_scope (tree); Index: pt.c =================================================================== --- pt.c (revision 248094) +++ pt.c (working copy) @@ -784,9 +784,7 @@ check_specialization_namespace (tree tmp return false; } - if (cxx_dialect < cxx11 - ? is_associated_namespace (current_namespace, tpl_ns) - : is_ancestor (current_namespace, tpl_ns)) + if (is_nested_namespace (current_namespace, tpl_ns, cxx_dialect < cxx11)) /* Same or enclosing namespace. */ return true; else @@ -810,7 +808,7 @@ check_explicit_instantiation_namespace ( /* DR 275: An explicit instantiation shall appear in an enclosing namespace of its template. */ ns = decl_namespace_context (spec); - if (!is_ancestor (current_namespace, ns)) + if (!is_nested_namespace (current_namespace, ns)) permerror (input_location, "explicit instantiation of %qD in namespace %qD " "(which does not enclose namespace %qD)", spec, current_namespace, ns); @@ -2594,8 +2592,8 @@ check_unqualified_spec_or_inst (tree t, { tree tmpl = most_general_template (t); if (DECL_NAMESPACE_SCOPE_P (tmpl) - && !is_associated_namespace (current_namespace, - CP_DECL_CONTEXT (tmpl))) + && !is_nested_namespace (current_namespace, + CP_DECL_CONTEXT (tmpl), true)) { if (processing_specialization) permerror (loc, "explicit specialization of %qD outside its "