* [C++ PATCH] Using decls
@ 2019-05-21 14:32 Nathan Sidwell
2019-05-21 14:44 ` Marek Polacek
0 siblings, 1 reply; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 14:32 UTC (permalink / raw)
To: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 224 bytes --]
This patch reimplements using-decl handling. It removes the double
lookup of the target name, and commonizes the local- and namespace-
scope handling into a single function.
Applying to trunk.
nathan
--
Nathan Sidwell
[-- Attachment #2: using-1.diff --]
[-- Type: text/x-patch, Size: 17874 bytes --]
2019-05-21 Nathan Sidwell <nathan@acm.org>
gcc/cp/
* name-lookup.h (struct cp_binding_level): Drop usings field.
(finish_namespace_using_decl, finish_local_using_decl): Replace with ...
(finish_nonmember_using_decl): ... this.
* name-lookup.c (push_using_decl_1, push_using_decl):
(do_nonmember_using_decl): ... here. Add INSERT_P arg. Reimplement.
(validate_nonmember_using_decl, finish_namespace_using_decl)
(finish_local_using_decl): Replace with ...
(finish_nonmember_using_decl): ... this. Drop DECL parm.
* parser.c (cp_parser_using_declaration): Don't do lookup here.
* pt.c (tsubst_expr): Do not do using decl lookup here.
gcc/testsuite/
* g++.dg/lookup/using53.C: Adjust diagnostic.
libcc1/
* libcp1plugin.cc (plugin_add_using_decl): Use
finish_nonmember_using_decl.
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 271427)
+++ gcc/cp/name-lookup.c (working copy)
@@ -3830,40 +3830,4 @@ make_lambda_name (void)
}
-/* Insert another USING_DECL into the current binding level, returning
- this declaration. If this is a redeclaration, do nothing, and
- return NULL_TREE if this not in namespace scope (in namespace
- scope, a using decl might extend any previous bindings). */
-
-static tree
-push_using_decl_1 (tree scope, tree name)
-{
- tree decl;
-
- gcc_assert (TREE_CODE (scope) == NAMESPACE_DECL);
- gcc_assert (identifier_p (name));
- for (decl = current_binding_level->usings; decl; decl = DECL_CHAIN (decl))
- if (USING_DECL_SCOPE (decl) == scope && DECL_NAME (decl) == name)
- break;
- if (decl)
- return namespace_bindings_p () ? decl : NULL_TREE;
- decl = build_lang_decl (USING_DECL, name, NULL_TREE);
- USING_DECL_SCOPE (decl) = scope;
- DECL_CHAIN (decl) = current_binding_level->usings;
- current_binding_level->usings = decl;
- return decl;
-}
-
-/* Wrapper for push_using_decl_1. */
-
-static tree
-push_using_decl (tree scope, tree name)
-{
- tree ret;
- timevar_start (TV_NAME_LOOKUP);
- ret = push_using_decl_1 (scope, name);
- timevar_stop (TV_NAME_LOOKUP);
- return ret;
-}
-
/* Same as pushdecl, but define X in binding-level LEVEL. We rely on the
caller to set DECL_CONTEXT properly.
@@ -3919,89 +3883,17 @@ pushdecl_outermost_localscope (tree x)
}
-/* Check a non-member using-declaration. Return the name and scope
- being used, and the USING_DECL, or NULL_TREE on failure. */
-
-static tree
-validate_nonmember_using_decl (tree decl, tree scope, tree name)
-{
- /* [namespace.udecl]
- A using-declaration for a class member shall be a
- member-declaration. */
- if (TYPE_P (scope))
- {
- error ("%qT is not a namespace or unscoped enum", scope);
- return NULL_TREE;
- }
- else if (scope == error_mark_node)
- return NULL_TREE;
-
- if (TREE_CODE (decl) == TEMPLATE_ID_EXPR)
- {
- /* 7.3.3/5
- A using-declaration shall not name a template-id. */
- error ("a using-declaration cannot specify a template-id. "
- "Try %<using %D%>", name);
- return NULL_TREE;
- }
-
- if (TREE_CODE (decl) == NAMESPACE_DECL)
- {
- error ("namespace %qD not allowed in using-declaration", decl);
- return NULL_TREE;
- }
-
- if (TREE_CODE (decl) == SCOPE_REF)
- {
- /* It's a nested name with template parameter dependent scope.
- This can only be using-declaration for class member. */
- error ("%qT is not a namespace", TREE_OPERAND (decl, 0));
- return NULL_TREE;
- }
-
- decl = OVL_FIRST (decl);
-
- /* Make a USING_DECL. */
- tree using_decl = push_using_decl (scope, name);
-
- if (using_decl == NULL_TREE
- && at_function_scope_p ()
- && VAR_P (decl))
- /* C++11 7.3.3/10. */
- error ("%qD is already declared in this scope", name);
-
- return using_decl;
-}
-
-/* Process a local-scope or namespace-scope using declaration. SCOPE
+/* Process a local-scope or namespace-scope using declaration.
+ FIXME
is the nominated scope to search for NAME. VALUE_P and TYPE_P
point to the binding for NAME in the current scope and are
updated. */
-static void
-do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
+static bool
+do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p,
+ bool insert_p, tree *value_p, tree *type_p)
{
- name_lookup lookup (name, 0);
-
- if (!qualified_namespace_lookup (scope, &lookup))
- {
- error ("%qD not declared", name);
- return;
- }
- else if (TREE_CODE (lookup.value) == TREE_LIST)
- {
- error ("reference to %qD is ambiguous", name);
- print_candidates (lookup.value);
- lookup.value = NULL_TREE;
- }
-
- if (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)
- {
- error ("reference to %qD is ambiguous", name);
- print_candidates (lookup.type);
- lookup.type = NULL_TREE;
- }
-
tree value = *value_p;
tree type = *type_p;
+ bool failed = false;
/* Shift the old and new bindings around so we're comparing class and
@@ -4019,77 +3911,93 @@ do_nonmember_using_decl (tree scope, tre
}
- if (lookup.value && lookup.value != value)
- {
- /* Check for using functions. */
- if (OVL_P (lookup.value) && (!value || OVL_P (value)))
- {
- for (lkp_iterator usings (lookup.value); usings; ++usings)
+ if (!lookup.value)
+ /* Nothing. */;
+ else if (OVL_P (lookup.value) && (!value || OVL_P (value)))
+ {
+ for (lkp_iterator usings (lookup.value); usings; ++usings)
+ {
+ tree new_fn = *usings;
+
+ /* [namespace.udecl]
+
+ If a function declaration in namespace scope or block
+ scope has the same name and the same parameter types as a
+ function introduced by a using declaration the program is
+ ill-formed. */
+ bool found = false;
+ for (ovl_iterator old (value); !found && old; ++old)
{
- tree new_fn = *usings;
+ tree old_fn = *old;
- /* [namespace.udecl]
-
- If a function declaration in namespace scope or block
- scope has the same name and the same parameter types as a
- function introduced by a using declaration the program is
- ill-formed. */
- bool found = false;
- for (ovl_iterator old (value); !found && old; ++old)
+ if (new_fn == old_fn)
{
- tree old_fn = *old;
-
- if (new_fn == old_fn)
- /* The function already exists in the current
- namespace. */
- found = true;
- else if (old.using_p ())
- continue; /* This is a using decl. */
- else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
- continue; /* This is an anticipated builtin. */
- else if (!matching_fn_p (new_fn, old_fn))
- continue; /* Parameters do not match. */
- else if (decls_match (new_fn, old_fn))
- found = true;
- else
- {
- diagnose_name_conflict (new_fn, old_fn);
- found = true;
- }
+ /* The function already exists in the current
+ namespace. */
+ found = true;
+ break;
+ }
+ else if (old.using_p ())
+ continue; /* This is a using decl. */
+ else if (old.hidden_p () && !DECL_HIDDEN_FRIEND_P (old_fn))
+ continue; /* This is an anticipated builtin. */
+ else if (!matching_fn_p (new_fn, old_fn))
+ continue; /* Parameters do not match. */
+ else if (decls_match (new_fn, old_fn))
+ {
+ /* Extern "C" in different namespaces. */
+ found = true;
+ break;
+ }
+ else
+ {
+ diagnose_name_conflict (new_fn, old_fn);
+ failed = true;
+ found = true;
+ break;
}
-
- if (!found)
- /* Unlike the overload case we don't drop anticipated
- builtins here. They don't cause a problem, and
- we'd like to match them with a future
- declaration. */
- value = ovl_insert (new_fn, value, true);
}
- }
- else if (value
- /* Ignore anticipated builtins. */
- && !anticipated_builtin_p (value)
- && !decls_match (lookup.value, value))
- diagnose_name_conflict (lookup.value, value);
- else
- value = lookup.value;
+
+ if (!found && insert_p)
+ /* Unlike the decl-pushing case we don't drop anticipated
+ builtins here. They don't cause a problem, and we'd
+ like to match them with a future declaration. */
+ value = ovl_insert (new_fn, value, true);
+ }
+ }
+ else if (value
+ /* Ignore anticipated builtins. */
+ && !anticipated_builtin_p (value)
+ && (fn_scope_p || !decls_match (lookup.value, value)))
+ {
+ diagnose_name_conflict (lookup.value, value);
+ failed = true;
}
+ else if (insert_p)
+ value = lookup.value;
if (lookup.type && lookup.type != type)
{
if (type && !decls_match (lookup.type, type))
- diagnose_name_conflict (lookup.type, type);
- else
+ {
+ diagnose_name_conflict (lookup.type, type);
+ failed = true;
+ }
+ else if (insert_p)
type = lookup.type;
}
- /* If bind->value is empty, shift any class or enumeration name back. */
- if (!value)
+ if (insert_p)
{
- value = type;
- type = NULL_TREE;
+ /* If value is empty, shift any class or enumeration name back. */
+ if (!value)
+ {
+ value = type;
+ type = NULL_TREE;
+ }
+ *value_p = value;
+ *type_p = type;
}
- *value_p = value;
- *type_p = type;
+ return failed;
}
@@ -5121,82 +5029,113 @@ pushdecl_namespace_level (tree x, bool i
}
-/* Process a using-declaration appearing in namespace scope. */
+/* Process a using declaration in non-class scope. */
void
-finish_namespace_using_decl (tree decl, tree scope, tree name)
+finish_nonmember_using_decl (tree scope, tree name)
{
- tree orig_decl = decl;
+ gcc_checking_assert (current_binding_level->kind != sk_class);
+ gcc_checking_assert (identifier_p (name));
- gcc_checking_assert (current_binding_level->kind == sk_namespace
- && !processing_template_decl);
- decl = validate_nonmember_using_decl (decl, scope, name);
- if (decl == NULL_TREE)
- return;
+ name_lookup lookup (name, 0);
- tree *slot = find_namespace_slot (current_namespace, name, true);
- tree val = slot ? MAYBE_STAT_DECL (*slot) : NULL_TREE;
- tree type = slot ? MAYBE_STAT_TYPE (*slot) : NULL_TREE;
- do_nonmember_using_decl (scope, name, &val, &type);
- if (STAT_HACK_P (*slot))
+ if (TREE_CODE (scope) != NAMESPACE_DECL)
{
- STAT_DECL (*slot) = val;
- STAT_TYPE (*slot) = type;
+ error ("%qE is not a namespace or unscoped enum", scope);
+ return;
}
- else if (type)
- *slot = stat_hack (val, type);
- else
- *slot = val;
- /* Emit debug info. */
- cp_emit_debug_info_for_using (orig_decl, current_namespace);
-}
+ qualified_namespace_lookup (scope, &lookup);
-/* Process a using-declaration at function scope. */
+ if (!lookup.value)
+ {
+ error ("%qD has not been declared in %qE", name, scope);
+ return;
+ }
-void
-finish_local_using_decl (tree decl, tree scope, tree name)
-{
- tree orig_decl = decl;
+ if (TREE_CODE (lookup.value) == TREE_LIST
+ /* But we can (independently) have ambiguous implicit typedefs. */
+ || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
+ {
+ error ("reference to %qD is ambiguous", name);
+ print_candidates (TREE_CODE (lookup.value) == TREE_LIST
+ ? lookup.value : lookup.type);
+ return;
+ }
- gcc_checking_assert (current_binding_level->kind != sk_class
- && current_binding_level->kind != sk_namespace);
- decl = validate_nonmember_using_decl (decl, scope, name);
- if (decl == NULL_TREE)
- return;
+ if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
+ {
+ error ("using-declaration may not name namespace %qD", lookup.value);
+ return;
+ }
+
+ /* Emit debug info. */
+ if (!processing_template_decl)
+ cp_emit_debug_info_for_using (lookup.value,
+ current_binding_level->this_entity);
- add_decl_expr (decl);
+ if (current_binding_level->kind == sk_namespace)
+ {
+ tree *slot = find_namespace_slot (current_namespace, name, true);
- cxx_binding *binding = find_local_binding (current_binding_level, name);
- tree value = binding ? binding->value : NULL_TREE;
- tree type = binding ? binding->type : NULL_TREE;
+ tree value = MAYBE_STAT_DECL (*slot);
+ tree type = MAYBE_STAT_TYPE (*slot);
- do_nonmember_using_decl (scope, name, &value, &type);
+ do_nonmember_using_decl (lookup, false, true, &value, &type);
- if (!value)
- ;
- else if (binding && value == binding->value)
- ;
- else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
- {
- update_local_overload (IDENTIFIER_BINDING (name), value);
- IDENTIFIER_BINDING (name)->value = value;
+ if (STAT_HACK_P (*slot))
+ {
+ STAT_DECL (*slot) = value;
+ STAT_TYPE (*slot) = type;
+ }
+ else if (type)
+ *slot = stat_hack (value, type);
+ else
+ *slot = value;
}
else
- /* Install the new binding. */
- push_local_binding (name, value, true);
-
- if (!type)
- ;
- else if (binding && type == binding->type)
- ;
- else
{
- push_local_binding (name, type, true);
- set_identifier_type_value (name, type);
+ tree using_decl = build_lang_decl (USING_DECL, name, NULL_TREE);
+ USING_DECL_SCOPE (using_decl) = scope;
+ add_decl_expr (using_decl);
+
+ cxx_binding *binding = find_local_binding (current_binding_level, name);
+ tree value = NULL;
+ tree type = NULL;
+ if (binding)
+ {
+ value = binding->value;
+ type = binding->type;
+ }
+
+ /* DR 36 questions why using-decls at function scope may not be
+ duplicates. Disallow it, as C++11 claimed and PR 20420
+ implemented. */
+ do_nonmember_using_decl (lookup, true, true, &value, &type);
+
+ if (!value)
+ ;
+ else if (binding && value == binding->value)
+ ;
+ else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
+ {
+ update_local_overload (IDENTIFIER_BINDING (name), value);
+ IDENTIFIER_BINDING (name)->value = value;
+ }
+ else
+ /* Install the new binding. */
+ // FIXME: Short circuit P_L_B
+ push_local_binding (name, value, true);
+
+ if (!type)
+ ;
+ else if (binding && type == binding->type)
+ ;
+ else
+ {
+ push_local_binding (name, type, true);
+ set_identifier_type_value (name, type);
+ }
}
- /* Emit debug info. */
- if (!processing_template_decl)
- cp_emit_debug_info_for_using (orig_decl, current_scope ());
}
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h (revision 271427)
+++ gcc/cp/name-lookup.h (working copy)
@@ -177,7 +177,4 @@ struct GTY(()) cp_binding_level {
tree names;
- /* A list of USING_DECL nodes. */
- tree usings;
-
/* Using directives. */
vec<tree, va_gc> *using_directives;
@@ -316,7 +313,6 @@ extern cxx_binding *outer_binding (tree,
extern void cp_emit_debug_info_for_using (tree, tree);
-extern void finish_namespace_using_decl (tree, tree, tree);
-extern void finish_local_using_decl (tree, tree, tree);
-extern void finish_using_directive (tree, tree);
+extern void finish_nonmember_using_decl (tree scope, tree name);
+extern void finish_using_directive (tree target, tree attribs);
extern tree pushdecl (tree, bool is_friend = false);
extern tree pushdecl_outermost_localscope (tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 271427)
+++ gcc/cp/parser.c (working copy)
@@ -19520,22 +19520,5 @@ cp_parser_using_declaration (cp_parser*
}
else
- {
- decl = cp_parser_lookup_name_simple (parser,
- identifier,
- token->location);
- if (decl == error_mark_node)
- cp_parser_name_lookup_error (parser, identifier,
- decl, NLE_NULL,
- token->location);
- else if (check_for_bare_parameter_packs (decl))
- {
- cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
- return false;
- }
- else if (!at_namespace_scope_p ())
- finish_local_using_decl (decl, qscope, identifier);
- else
- finish_namespace_using_decl (decl, qscope, identifier);
- }
+ finish_nonmember_using_decl (qscope, identifier);
}
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 271427)
+++ gcc/cp/pt.c (working copy)
@@ -17061,11 +17061,5 @@ tsubst_expr (tree t, tree args, tsubst_f
scope = tsubst (scope, args, complain, in_decl);
- decl = lookup_qualified_name (scope, name,
- /*is_type_p=*/false,
- /*complain=*/false);
- if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
- qualified_name_lookup_error (scope, name, decl, input_location);
- else
- finish_local_using_decl (decl, scope, name);
+ finish_nonmember_using_decl (scope, name);
}
else if (is_capture_proxy (decl)
Index: gcc/testsuite/g++.dg/lookup/using53.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using53.C (revision 271427)
+++ gcc/testsuite/g++.dg/lookup/using53.C (working copy)
@@ -50,4 +50,4 @@ f ()
{
using N::i;
- using N::i; // { dg-error "declared" }
+ using N::i; // { dg-error "redeclaration" }
}
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc (revision 271427)
+++ libcc1/libcp1plugin.cc (working copy)
@@ -1020,5 +1020,5 @@ plugin_add_using_decl (cc1_plugin::conne
/* We can't be at local scope. */
gcc_assert (at_namespace_scope_p ());
- finish_namespace_using_decl (target, tcontext, identifier);
+ finish_nonmember_using_decl (tcontext, identifier);
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [C++ PATCH] Using decls
2019-05-21 14:32 [C++ PATCH] Using decls Nathan Sidwell
@ 2019-05-21 14:44 ` Marek Polacek
2019-05-21 14:47 ` Nathan Sidwell
2019-05-21 15:30 ` Nathan Sidwell
0 siblings, 2 replies; 5+ messages in thread
From: Marek Polacek @ 2019-05-21 14:44 UTC (permalink / raw)
To: Nathan Sidwell; +Cc: GCC Patches
Thanks for the patch and sorry for nitpicking:
On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
> -/* Process a local-scope or namespace-scope using declaration. SCOPE
> +/* Process a local-scope or namespace-scope using declaration.
> + FIXME
This ain't look right. You meant to document the INSERT_P param, right.
> + /* DR 36 questions why using-decls at function scope may not be
> + duplicates. Disallow it, as C++11 claimed and PR 20420
> + implemented. */
> + do_nonmember_using_decl (lookup, true, true, &value, &type);
> +
> + if (!value)
> + ;
> + else if (binding && value == binding->value)
> + ;
> + else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
> + {
> + update_local_overload (IDENTIFIER_BINDING (name), value);
> + IDENTIFIER_BINDING (name)->value = value;
> + }
> + else
> + /* Install the new binding. */
> + // FIXME: Short circuit P_L_B
Was this FIXME meant to be here?
Marek
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [C++ PATCH] Using decls
2019-05-21 14:44 ` Marek Polacek
@ 2019-05-21 14:47 ` Nathan Sidwell
2019-05-21 15:30 ` Nathan Sidwell
1 sibling, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 14:47 UTC (permalink / raw)
To: gcc-patches
On 5/21/19 10:43 AM, Marek Polacek wrote:
> Thanks for the patch and sorry for nitpicking:
>
> On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
>> -/* Process a local-scope or namespace-scope using declaration. SCOPE
>> +/* Process a local-scope or namespace-scope using declaration.
>> + FIXME
>
> This ain't look right. You meant to document the INSERT_P param, right.
Yes indeed. Found these when merging back to modules. Thanks for noticing!
--
Nathan Sidwell
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [C++ PATCH] Using decls
2019-05-21 14:44 ` Marek Polacek
2019-05-21 14:47 ` Nathan Sidwell
@ 2019-05-21 15:30 ` Nathan Sidwell
1 sibling, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2019-05-21 15:30 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 554 bytes --]
On 5/21/19 10:43 AM, Marek Polacek wrote:
> Thanks for the patch and sorry for nitpicking:
>
> On Tue, May 21, 2019 at 10:32:31AM -0400, Nathan Sidwell wrote:
>> -/* Process a local-scope or namespace-scope using declaration. SCOPE
>> +/* Process a local-scope or namespace-scope using declaration.
>> + FIXME
>
> This ain't look right. You meant to document the INSERT_P param, right.
The INSERT_P parameter is not (yet) needed. This patch removes it and
cleans up the inadvertent stray FIXMEs. Sorry for the noise.
nathan
--
Nathan Sidwell
[-- Attachment #2: ns-using-2.diff --]
[-- Type: text/x-patch, Size: 5340 bytes --]
2019-05-20 Nathan Sidwell <nathan@acm.org>
gcc/cp/
* name-lookup.c (finish_namespace_using_directive)
(finish_local_using_directive): Merge to ...
(finish_using_directive): ... here. Handle both contexts.
* name-lookup.h (finish_namespace_using_directive)
(finish_local_using_directive): Replace with ...
(finish_using_directive): ... this.
* parser.c (cp_parser_using_directive): Adjust.
* pt.c (tsubst_expr): Likewise.
libcc1/
* libcp1plugin.cc (plugin_add_using_namespace): Call renamed
finish_using_directive.
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 271416)
+++ gcc/cp/name-lookup.c (working copy)
@@ -7235,52 +7235,36 @@ emit_debug_info_using_namespace (tree fr
}
-/* Process a namespace-scope using directive. */
+/* Process a using directive. */
void
-finish_namespace_using_directive (tree target, tree attribs)
+finish_using_directive (tree target, tree attribs)
{
- gcc_checking_assert (namespace_bindings_p ());
if (target == error_mark_node)
return;
- add_using_namespace (current_binding_level->using_directives,
- ORIGINAL_NAMESPACE (target));
- emit_debug_info_using_namespace (current_namespace,
- ORIGINAL_NAMESPACE (target), false);
-
- if (attribs == error_mark_node)
- return;
-
- for (tree a = attribs; a; a = TREE_CHAIN (a))
- {
- tree name = get_attribute_name (a);
- if (is_attribute_p ("strong", name))
- {
- warning (0, "strong using directive no longer supported");
- if (CP_DECL_CONTEXT (target) == current_namespace)
- inform (DECL_SOURCE_LOCATION (target),
- "you may use an inline namespace instead");
- }
- else
- warning (OPT_Wattributes, "%qD attribute directive ignored", name);
- }
-}
-
-/* Process a function-scope using-directive. */
-
-void
-finish_local_using_directive (tree target, tree attribs)
-{
- gcc_checking_assert (local_bindings_p ());
- if (target == error_mark_node)
- return;
-
- if (attribs)
- warning (OPT_Wattributes, "attributes ignored on local using directive");
-
- add_stmt (build_stmt (input_location, USING_STMT, target));
+ if (current_binding_level->kind != sk_namespace)
+ add_stmt (build_stmt (input_location, USING_STMT, target));
+ else
+ emit_debug_info_using_namespace (current_binding_level->this_entity,
+ ORIGINAL_NAMESPACE (target), false);
add_using_namespace (current_binding_level->using_directives,
ORIGINAL_NAMESPACE (target));
+
+ if (attribs != error_mark_node)
+ for (tree a = attribs; a; a = TREE_CHAIN (a))
+ {
+ tree name = get_attribute_name (a);
+ if (current_binding_level->kind == sk_namespace
+ && is_attribute_p ("strong", name))
+ {
+ warning (0, "strong using directive no longer supported");
+ if (CP_DECL_CONTEXT (target) == current_namespace)
+ inform (DECL_SOURCE_LOCATION (target),
+ "you may use an inline namespace instead");
+ }
+ else
+ warning (OPT_Wattributes, "%qD attribute directive ignored", name);
+ }
}
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h (revision 271416)
+++ gcc/cp/name-lookup.h (working copy)
@@ -1,3 +1,3 @@
-/* Declarations for C++ name lookup routines.
+/* Declarations for -*- C++ -*- name lookup routines.
Copyright (C) 2003-2019 Free Software Foundation, Inc.
Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
@@ -318,6 +318,5 @@ extern void cp_emit_debug_info_for_using
extern void finish_namespace_using_decl (tree, tree, tree);
extern void finish_local_using_decl (tree, tree, tree);
-extern void finish_namespace_using_directive (tree, tree);
-extern void finish_local_using_directive (tree, tree);
+extern void finish_using_directive (tree, tree);
extern tree pushdecl (tree, bool is_friend = false);
extern tree pushdecl_outermost_localscope (tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 271416)
+++ gcc/cp/parser.c (working copy)
@@ -19738,8 +19738,5 @@ cp_parser_using_directive (cp_parser* pa
/* Update the symbol table. */
- if (namespace_bindings_p ())
- finish_namespace_using_directive (namespace_decl, attribs);
- else
- finish_local_using_directive (namespace_decl, attribs);
+ finish_using_directive (namespace_decl, attribs);
/* Look for the final `;'. */
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 271416)
+++ gcc/cp/pt.c (working copy)
@@ -17044,6 +17044,5 @@ tsubst_expr (tree t, tree args, tsubst_f
case USING_STMT:
- finish_local_using_directive (USING_STMT_NAMESPACE (t),
- /*attribs=*/NULL_TREE);
+ finish_using_directive (USING_STMT_NAMESPACE (t), /*attribs=*/NULL_TREE);
break;
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc (revision 271416)
+++ libcc1/libcp1plugin.cc (working copy)
@@ -942,5 +942,5 @@ plugin_add_using_namespace (cc1_plugin::
gcc_assert (TREE_CODE (used_ns) == NAMESPACE_DECL);
- finish_namespace_using_directive (used_ns, NULL_TREE);
+ finish_using_directive (used_ns, NULL_TREE);
return 1;
^ permalink raw reply [flat|nested] 5+ messages in thread
* [C++ PATCH] using decls
@ 2017-05-23 11:07 Nathan Sidwell
0 siblings, 0 replies; 5+ messages in thread
From: Nathan Sidwell @ 2017-05-23 11:07 UTC (permalink / raw)
To: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 441 bytes --]
This patch addresses namespace and local scope using declarations.
Unlike the using directive case, we already had separate workers for
these, they just needed a bit of cleanup to use the new iterator and
make them ready for the pushdecl change that's coming. I renamed them
consistently with the directive name change I made yesterday.
There'll be a final change to these once the other pieces have landed.
nathan
--
Nathan Sidwell
[-- Attachment #2: udecl.diff --]
[-- Type: text/x-patch, Size: 25705 bytes --]
2017-05-23 Nathan Sidwell <nathan@acm.org>
gcc/cp
* cp-tree.h (OVL_P): New.
* name-lookup.h (push_local_binding): Delete.
(do_toplevel_using_decl, do_local_using_decl): Rename to ...
(finish_namespace_using_decl, finish_local_using_decl): ... here
* name-lookup.c (add_decl_to_level): Swap args.
(pop_bindings_and_leave_scope): Look inside TREE_LIST.
(diagnose_name_conflict): Check contexts are same for redecl.
(update_local_overload): New.
(compparms_for_decl_and_using): Rename to ...
(matching_fn_p): ... here.
(pushdecl_maybe_friend_1): Adjust add_decl_to_level,
push_local_bindings call.
(push_local_binding): Make static, replace FLAGS arg with
IS_USING.
(validate_nonmember_using_decl): Use OVL_FIRST.
(do_nonmember_using_decl): Use in/out parameters. Use
lkp_iterator and simplify.
(do_toplevel_using_decl, do_local_using_decl): Rename to ...
(finish_namespace_using_decl, finish_local_using_decl): ... here.
Adjust.
(lookup_type_current_level): Delete.
* parser.c (cp_parser_using_declaration): Adjust.
* pt.c (tsubst_expr): Adjust.
libcc1/
* libcp1plugin.cc (plugin_add_using_decl): Call
finish_namespace_using_decl. Use assert not unreachable.
gcc/testsuite/
* g++.dg/lookup/using13.C: Adjust expected error.
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 248338)
+++ gcc/cp/cp-tree.h (working copy)
@@ -671,6 +671,11 @@ typedef struct ptrmem_cst * ptrmem_cst_t
/* The name of the overload set. */
#define OVL_NAME(NODE) DECL_NAME (OVL_FIRST (NODE))
+/* Whether this is a set of overloaded functions. TEMPLATE_DECLS are
+ always wrapped in an OVERLOAD, so we don't need to check them
+ here. */
+#define OVL_P(NODE) \
+ (TREE_CODE (NODE) == FUNCTION_DECL || TREE_CODE (NODE) == OVERLOAD)
/* Whether this is a single member overload. */
#define OVL_SINGLE_P(NODE) \
(TREE_CODE (NODE) != OVERLOAD || !OVL_CHAIN (NODE))
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 248338)
+++ gcc/cp/name-lookup.c (working copy)
@@ -38,6 +38,7 @@ static cp_binding_level *innermost_noncl
static void set_identifier_type_value_with_scope (tree id, tree decl,
cp_binding_level *b);
static void set_namespace_binding (tree scope, tree name, tree val);
+static void push_local_binding (tree, tree, bool);
/* The bindings for a particular name in a particular scope. */
@@ -58,14 +59,13 @@ static void consider_binding_level (tree
cp_binding_level *lvl,
bool look_within_fields,
enum lookup_name_fuzzy_kind kind);
-static tree lookup_type_current_level (tree);
static tree push_using_directive (tree);
static void diagnose_name_conflict (tree, tree);
/* Add DECL to the list of things declared in B. */
static void
-add_decl_to_level (tree decl, cp_binding_level *b)
+add_decl_to_level (cp_binding_level *b, tree decl)
{
/* We used to record virtual tables as if they were ordinary
variables, but no longer do so. */
@@ -995,7 +995,13 @@ void
pop_bindings_and_leave_scope (void)
{
for (tree t = get_local_decls (); t; t = DECL_CHAIN (t))
- pop_local_binding (DECL_NAME (t), t);
+ {
+ tree decl = TREE_CODE (t) == TREE_LIST ? TREE_VALUE (t) : t;
+ tree name = OVL_NAME (decl);
+
+ pop_local_binding (name, decl);
+ }
+
leave_scope ();
}
@@ -1179,7 +1185,8 @@ diagnose_name_conflict (tree decl, tree
&& (TREE_CODE (decl) != TYPE_DECL
|| (DECL_ARTIFICIAL (decl) && DECL_ARTIFICIAL (bval))
|| (!DECL_ARTIFICIAL (decl) && !DECL_ARTIFICIAL (bval)))
- && !is_overloaded_fn (decl))
+ && !DECL_DECLARES_FUNCTION_P (decl)
+ && CP_DECL_CONTEXT (decl) == CP_DECL_CONTEXT (bval))
error ("redeclaration of %q#D", decl);
else
error ("%q#D conflicts with a previous declaration", decl);
@@ -1199,6 +1206,56 @@ supplement_binding (cxx_binding *binding
return ret;
}
+/* Replace BINDING's current value on its scope's name list with
+ NEWVAL. */
+
+static void
+update_local_overload (cxx_binding *binding, tree newval)
+{
+ tree *d;
+
+ for (d = &binding->scope->names; ; d = &TREE_CHAIN (*d))
+ if (*d == binding->value)
+ {
+ /* Stitch new list node in. */
+ *d = tree_cons (NULL_TREE, NULL_TREE, TREE_CHAIN (*d));
+ break;
+ }
+ else if (TREE_CODE (*d) == TREE_LIST && TREE_VALUE (*d) == binding->value)
+ break;
+
+ TREE_VALUE (*d) = newval;
+}
+
+/* Compares the parameter-type-lists of ONE and TWO and
+ returns false if they are different. If the DECLs are template
+ functions, the return types and the template parameter lists are
+ compared too (DR 565). */
+
+static bool
+matching_fn_p (tree one, tree two)
+{
+ if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (one)),
+ TYPE_ARG_TYPES (TREE_TYPE (two))))
+ return false;
+
+ if (TREE_CODE (one) == TEMPLATE_DECL
+ && TREE_CODE (two) == TEMPLATE_DECL)
+ {
+ /* Compare template parms. */
+ if (!comp_template_parms (DECL_TEMPLATE_PARMS (one),
+ DECL_TEMPLATE_PARMS (two)))
+ return false;
+
+ /* And return type. */
+ if (!same_type_p (TREE_TYPE (TREE_TYPE (one)),
+ TREE_TYPE (TREE_TYPE (two))))
+ return false;
+ }
+
+ return true;
+}
+
/* Map of identifiers to extern C functions (or LISTS thereof). */
static GTY(()) hash_map<lang_identifier *, tree> *extern_c_fns;
@@ -1699,7 +1756,7 @@ pushdecl_maybe_friend_1 (tree x, bool is
{
t = push_overloaded_decl (x, PUSH_GLOBAL, is_friend);
if (t == x)
- add_decl_to_level (x, NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)));
+ add_decl_to_level (NAMESPACE_LEVEL (CP_DECL_CONTEXT (t)), x);
}
if (DECL_DECLARES_FUNCTION_P (t))
@@ -1814,7 +1871,7 @@ pushdecl_maybe_friend_1 (tree x, bool is
if (need_new_binding)
{
- push_local_binding (name, x, 0);
+ push_local_binding (name, x, false);
/* Because push_local_binding will hook X on to the
current_binding_level's name list, we don't want to
do that again below. */
@@ -1881,10 +1938,9 @@ pushdecl_maybe_friend_1 (tree x, bool is
}
if (need_new_binding)
- add_decl_to_level (x,
- DECL_NAMESPACE_SCOPE_P (x)
+ add_decl_to_level (DECL_NAMESPACE_SCOPE_P (x)
? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
- : current_binding_level);
+ : current_binding_level, x);
return x;
}
@@ -1932,12 +1988,11 @@ maybe_push_decl (tree decl)
}
/* Bind DECL to ID in the current_binding_level, assumed to be a local
- binding level. If PUSH_USING is set in FLAGS, we know that DECL
- doesn't really belong to this binding level, that it got here
- through a using-declaration. */
+ binding level. If IS_USING is true, DECL got here through a
+ using-declaration. */
-void
-push_local_binding (tree id, tree decl, int flags)
+static void
+push_local_binding (tree id, tree decl, bool is_using)
{
cp_binding_level *b;
@@ -1958,15 +2013,14 @@ push_local_binding (tree id, tree decl,
/* Create a new binding. */
push_binding (id, decl, b);
- if (TREE_CODE (decl) == OVERLOAD || (flags & PUSH_USING))
- /* We must put the OVERLOAD into a TREE_LIST since the
- TREE_CHAIN of an OVERLOAD is already used. Similarly for
- decls that got here through a using-declaration. */
+ if (TREE_CODE (decl) == OVERLOAD || is_using)
+ /* We must put the OVERLOAD or using into a TREE_LIST since we
+ cannot use the decl's chain itself. */
decl = build_tree_list (NULL_TREE, decl);
/* And put DECL on the list of things declared by the current
binding level. */
- add_decl_to_level (decl, b);
+ add_decl_to_level (b, decl);
}
/* Check to see whether or not DECL is a variable that would have been
@@ -2840,28 +2894,6 @@ pushdecl_outermost_localscope (tree x)
return ret;
}
-/* Helper function for push_overloaded_decl_1 and do_nonmember_using_decl.
- Compares the parameter-type-lists of DECL1 and DECL2 and returns false
- if they are different. If the DECLs are template functions, the return
- types and the template parameter lists are compared too (DR 565). */
-
-static bool
-compparms_for_decl_and_using_decl (tree decl1, tree decl2)
-{
- if (!compparms (TYPE_ARG_TYPES (TREE_TYPE (decl1)),
- TYPE_ARG_TYPES (TREE_TYPE (decl2))))
- return false;
-
- if (! DECL_FUNCTION_TEMPLATE_P (decl1)
- || ! DECL_FUNCTION_TEMPLATE_P (decl2))
- return true;
-
- return (comp_template_parms (DECL_TEMPLATE_PARMS (decl1),
- DECL_TEMPLATE_PARMS (decl2))
- && same_type_p (TREE_TYPE (TREE_TYPE (decl1)),
- TREE_TYPE (TREE_TYPE (decl2))));
-}
-
/* DECL is a FUNCTION_DECL for a non-member function, which may have
other definitions already in place. We get around this by making
the value of the identifier point to a list of all the things that
@@ -2918,7 +2950,7 @@ push_overloaded_decl_1 (tree decl, int f
if (TREE_CODE (tmp) == OVERLOAD && OVL_USING_P (tmp)
&& !(flags & PUSH_USING)
- && compparms_for_decl_and_using_decl (fn, decl)
+ && matching_fn_p (fn, decl)
&& ! decls_match (fn, decl))
diagnose_name_conflict (decl, fn);
@@ -3047,10 +3079,7 @@ validate_nonmember_using_decl (tree decl
return NULL_TREE;
}
- if (is_overloaded_fn (decl))
- decl = get_first_fn (decl);
-
- gcc_assert (DECL_P (decl));
+ decl = OVL_FIRST (decl);
/* Make a USING_DECL. */
tree using_decl = push_using_decl (scope, name);
@@ -3064,60 +3093,64 @@ validate_nonmember_using_decl (tree decl
return using_decl;
}
-/* Process local and global using-declarations. */
+/* Process a local-scope or namespace-scope using declaration. SCOPE
+ is the nominated scope to search for NAME. VALUE_P and TYPE_P
+ point to the binding for NAME in the current scope and are
+ updated. */
static void
-do_nonmember_using_decl (tree scope, tree name, tree oldval, tree oldtype,
- tree *newval, tree *newtype)
+do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
{
- struct scope_binding decls = EMPTY_SCOPE_BINDING;
+ struct scope_binding lookup = EMPTY_SCOPE_BINDING;
- *newval = *newtype = NULL_TREE;
- if (!qualified_lookup_using_namespace (name, scope, &decls, 0))
+ if (!qualified_lookup_using_namespace (name, scope, &lookup, 0))
/* Lookup error */
return;
- if (!decls.value && !decls.type)
+ if (!lookup.value)
{
error ("%qD not declared", name);
return;
}
+ else if (TREE_CODE (lookup.value) == TREE_LIST)
+ {
+ error ("reference to %qD is ambiguous", name);
+ print_candidates (lookup.value);
+ lookup.value = NULL_TREE;
+ }
+
+ if (lookup.type && TREE_CODE (lookup.type) == TREE_LIST)
+ {
+ error ("reference to %qD is ambiguous", name);
+ print_candidates (lookup.type);
+ lookup.type = NULL_TREE;
+ }
+
+ tree value = *value_p;
+ tree type = *type_p;
/* Shift the old and new bindings around so we're comparing class and
enumeration names to each other. */
- if (oldval && DECL_IMPLICIT_TYPEDEF_P (oldval))
+ if (value && DECL_IMPLICIT_TYPEDEF_P (value))
{
- oldtype = oldval;
- oldval = NULL_TREE;
+ type = value;
+ value = NULL_TREE;
}
- if (decls.value && DECL_IMPLICIT_TYPEDEF_P (decls.value))
+ if (lookup.value && DECL_IMPLICIT_TYPEDEF_P (lookup.value))
{
- decls.type = decls.value;
- decls.value = NULL_TREE;
+ lookup.type = lookup.value;
+ lookup.value = NULL_TREE;
}
- if (decls.value)
+ if (lookup.value && lookup.value != value)
{
/* Check for using functions. */
- if (is_overloaded_fn (decls.value))
+ if (OVL_P (lookup.value) && (!value || OVL_P (value)))
{
- tree tmp, tmp1;
-
- if (oldval && !is_overloaded_fn (oldval))
+ for (lkp_iterator usings (lookup.value); usings; ++usings)
{
- error ("%qD is already declared in this scope", name);
- oldval = NULL_TREE;
- }
-
- *newval = oldval;
- for (tmp = decls.value; tmp; tmp = OVL_NEXT (tmp))
- {
- tree new_fn = OVL_CURRENT (tmp);
-
- /* Don't import functions that haven't been declared. */
- if (DECL_ANTICIPATED (new_fn))
- continue;
+ tree new_fn = *usings;
/* [namespace.udecl]
@@ -3125,138 +3158,67 @@ do_nonmember_using_decl (tree scope, tre
scope has the same name and the same parameter types as a
function introduced by a using declaration the program is
ill-formed. */
- for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
+ bool found = false;
+ for (ovl_iterator old (value); !found && old; ++old)
{
- tree old_fn = OVL_CURRENT (tmp1);
+ tree old_fn = *old;
if (new_fn == old_fn)
- /* The function already exists in the current namespace. */
- break;
- else if (TREE_CODE (tmp1) == OVERLOAD && OVL_USING_P (tmp1))
- continue; /* this is a using decl */
- else if (compparms_for_decl_and_using_decl (new_fn, old_fn))
+ /* The function already exists in the current
+ namespace. */
+ found = true;
+ else if (old.using_p ())
+ continue; /* This is a using decl. */
+ else if (DECL_ANTICIPATED (old_fn)
+ && !DECL_HIDDEN_FRIEND_P (old_fn))
+ continue; /* This is an anticipated builtin. */
+ else if (!matching_fn_p (new_fn, old_fn))
+ continue; /* Parameters do not match. */
+ else if (decls_match (new_fn, old_fn))
+ found = true;
+ else
{
- /* There was already a non-using declaration in
- this scope with the same parameter types. If both
- are the same extern "C" functions, that's ok. */
- if (DECL_ANTICIPATED (old_fn)
- && !DECL_HIDDEN_FRIEND_P (old_fn))
- /* Ignore anticipated built-ins. */;
- else if (decls_match (new_fn, old_fn))
- break;
- else
- {
- diagnose_name_conflict (new_fn, old_fn);
- break;
- }
+ diagnose_name_conflict (new_fn, old_fn);
+ found = true;
}
}
- /* If we broke out of the loop, there's no reason to add
- this function to the using declarations for this
- scope. */
- if (tmp1)
- continue;
-
- /* If we are adding to an existing OVERLOAD, then we no
- longer know the type of the set of functions. */
- if (*newval && TREE_CODE (*newval) == OVERLOAD)
- TREE_TYPE (*newval) = unknown_type_node;
- /* Add this new function to the set. */
- *newval = ovl_insert (OVL_CURRENT (tmp), *newval, true);
+ if (!found)
+ /* Unlike the overload case we don't drop anticipated
+ builtins here. They don't cause a problem, and
+ we'd like to match them with a future
+ declaration. */
+ value = ovl_insert (new_fn, value, true);
}
}
+ else if (value
+ /* Ignore anticipated builtins. */
+ && !(TREE_CODE (value) == FUNCTION_DECL
+ && DECL_ANTICIPATED (value)
+ && !DECL_HIDDEN_FRIEND_P (value))
+ && !decls_match (lookup.value, value))
+ diagnose_name_conflict (lookup.value, value);
else
- {
- /* If we're declaring a non-function and OLDVAL is an anticipated
- built-in, just pretend it isn't there. */
- if (oldval
- && TREE_CODE (oldval) == FUNCTION_DECL
- && DECL_ANTICIPATED (oldval)
- && !DECL_HIDDEN_FRIEND_P (oldval))
- oldval = NULL_TREE;
-
- *newval = decls.value;
- if (oldval && !decls_match (*newval, oldval))
- error ("%qD is already declared in this scope", name);
- }
+ value = lookup.value;
}
- else
- *newval = oldval;
- if (decls.type && TREE_CODE (decls.type) == TREE_LIST)
- {
- error ("reference to %qD is ambiguous", name);
- print_candidates (decls.type);
- }
- else
+ if (lookup.type && lookup.type != type)
{
- *newtype = decls.type;
- if (oldtype && *newtype && !decls_match (oldtype, *newtype))
- error ("%qD is already declared in this scope", name);
- }
-
- /* If *newval is empty, shift any class or enumeration name down. */
- if (!*newval)
- {
- *newval = *newtype;
- *newtype = NULL_TREE;
- }
-}
-
-/* Process a using-declaration at function scope. */
-
-void
-do_local_using_decl (tree decl, tree scope, tree name)
-{
- tree oldval, oldtype, newval, newtype;
- tree orig_decl = decl;
-
- decl = validate_nonmember_using_decl (decl, scope, name);
- if (decl == NULL_TREE)
- return;
-
- if (building_stmt_list_p ()
- && at_function_scope_p ())
- add_decl_expr (decl);
-
- oldval = lookup_name_innermost_nonclass_level (name);
- oldtype = lookup_type_current_level (name);
-
- do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
-
- if (newval)
- {
- if (is_overloaded_fn (newval))
- {
- tree fn, term;
-
- /* We only need to push declarations for those functions
- that were not already bound in the current level.
- The old value might be NULL_TREE, it might be a single
- function, or an OVERLOAD. */
- if (oldval && TREE_CODE (oldval) == OVERLOAD)
- term = OVL_FUNCTION (oldval);
- else
- term = oldval;
- for (fn = newval; fn && OVL_CURRENT (fn) != term;
- fn = OVL_NEXT (fn))
- push_overloaded_decl (OVL_CURRENT (fn),
- PUSH_LOCAL | PUSH_USING,
- false);
- }
+ if (type && !decls_match (lookup.type, type))
+ diagnose_name_conflict (lookup.type, type);
else
- push_local_binding (name, newval, PUSH_USING);
+ type = lookup.type;
}
- if (newtype)
+
+ /* If bind->value is empty, shift any class or enumeration name back. */
+ if (!value)
{
- push_local_binding (name, newtype, PUSH_USING);
- set_identifier_type_value (name, newtype);
+ value = type;
+ type = NULL_TREE;
}
- /* Emit debug info. */
- if (!processing_template_decl)
- cp_emit_debug_info_for_using (orig_decl, current_scope());
+ *value_p = value;
+ *type_p = type;
}
/* Returns true if ANCESTOR encloses DESCENDANT, including matching.
@@ -4337,35 +4299,86 @@ pushdecl_namespace_level (tree x, bool i
return t;
}
-/* Process a using-declaration not appearing in class or local scope. */
+/* Process a using-declaration appearing in namespace scope. */
void
-do_toplevel_using_decl (tree decl, tree scope, tree name)
+finish_namespace_using_decl (tree decl, tree scope, tree name)
{
- tree oldval, oldtype, newval, newtype;
tree orig_decl = decl;
- cxx_binding *binding;
+ gcc_checking_assert (current_binding_level->kind == sk_namespace);
decl = validate_nonmember_using_decl (decl, scope, name);
if (decl == NULL_TREE)
return;
- binding = binding_for_name (NAMESPACE_LEVEL (current_namespace), name);
+ cxx_binding *binding
+ = binding_for_name (NAMESPACE_LEVEL (current_namespace), name);
+
+ tree value = binding->value;
+ tree type = binding->type;
- oldval = binding->value;
- oldtype = binding->type;
+ do_nonmember_using_decl (scope, name, &value, &type);
- do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
+ /* Copy declarations found. */
+ binding->value = value;
+ binding->type = type;
/* Emit debug info. */
+ gcc_assert (!processing_template_decl);
if (!processing_template_decl)
cp_emit_debug_info_for_using (orig_decl, current_namespace);
+}
- /* Copy declarations found. */
- if (newval)
- binding->value = newval;
- if (newtype)
- binding->type = newtype;
+/* Process a using-declaration at local scope. */
+
+void
+finish_local_using_decl (tree decl, tree scope, tree name)
+{
+ tree orig_decl = decl;
+
+ gcc_checking_assert (current_binding_level->kind != sk_class
+ && current_binding_level->kind != sk_namespace);
+ decl = validate_nonmember_using_decl (decl, scope, name);
+ if (decl == NULL_TREE)
+ return;
+
+ gcc_assert (building_stmt_list_p ());
+ if (building_stmt_list_p ()
+ && at_function_scope_p ())
+ add_decl_expr (decl);
+
+ cxx_binding *binding = find_local_binding (current_binding_level, name);
+ tree value = binding ? binding->value : NULL_TREE;
+ tree type = binding ? binding->type : NULL_TREE;
+
+ do_nonmember_using_decl (scope, name, &value, &type);
+
+ if (!value)
+ ;
+ else if (binding && value == binding->value)
+ ;
+ else if (binding && binding->value && TREE_CODE (value) == OVERLOAD)
+ {
+ update_local_overload (IDENTIFIER_BINDING (name), value);
+ IDENTIFIER_BINDING (name)->value = value;
+ }
+ else
+ /* Install the new binding. */
+ push_local_binding (name, value, true);
+
+ if (!type)
+ ;
+ else if (binding && type == binding->type)
+ ;
+ else
+ {
+ push_local_binding (name, type, true);
+ set_identifier_type_value (name, type);
+ }
+
+ /* Emit debug info. */
+ if (!processing_template_decl)
+ cp_emit_debug_info_for_using (orig_decl, current_scope ());
}
/* Combines two sets of overloaded functions into an OVERLOAD chain, removing
@@ -5651,38 +5664,6 @@ is_local_extern (tree decl)
return false;
}
-/* Like lookup_name_innermost_nonclass_level, but for types. */
-
-static tree
-lookup_type_current_level (tree name)
-{
- tree t = NULL_TREE;
-
- timevar_start (TV_NAME_LOOKUP);
- gcc_assert (current_binding_level->kind != sk_namespace);
-
- if (REAL_IDENTIFIER_TYPE_VALUE (name) != NULL_TREE
- && REAL_IDENTIFIER_TYPE_VALUE (name) != global_type_node)
- {
- cp_binding_level *b = current_binding_level;
- while (1)
- {
- if (purpose_member (name, b->type_shadowed))
- {
- t = REAL_IDENTIFIER_TYPE_VALUE (name);
- break;
- }
- if (b->kind == sk_cleanup)
- b = b->level_chain;
- else
- break;
- }
- }
-
- timevar_stop (TV_NAME_LOOKUP);
- return t;
-}
-
/* Add namespace to using_directives. Return NULL_TREE if nothing was
changed (i.e. there was already a directive), or the fresh
TREE_LIST otherwise. */
Index: gcc/cp/name-lookup.h
===================================================================
--- gcc/cp/name-lookup.h (revision 248338)
+++ gcc/cp/name-lookup.h (working copy)
@@ -315,7 +315,6 @@ extern tree lookup_name_nonclass (tree);
extern tree lookup_name_innermost_nonclass_level (tree);
extern bool is_local_extern (tree);
extern tree lookup_function_nonclass (tree, vec<tree, va_gc> *, bool);
-extern void push_local_binding (tree, tree, int);
extern bool pushdecl_class_level (tree);
extern tree pushdecl_namespace_level (tree, bool);
extern bool push_class_level_binding (tree, tree);
@@ -326,8 +325,6 @@ extern void set_decl_namespace (tree, tr
extern void push_decl_namespace (tree);
extern void pop_decl_namespace (void);
extern void do_namespace_alias (tree, tree);
-extern void do_toplevel_using_decl (tree, tree, tree);
-extern void do_local_using_decl (tree, tree, tree);
extern tree do_class_using_decl (tree, tree);
extern void do_using_directive (tree);
extern cp_expr lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
@@ -336,6 +333,8 @@ extern tree innermost_non_namespace_valu
extern cxx_binding *outer_binding (tree, cxx_binding *, bool);
extern void cp_emit_debug_info_for_using (tree, tree);
+extern void finish_namespace_using_decl (tree, tree, tree);
+extern void finish_local_using_decl (tree, tree, tree);
extern void finish_namespace_using_directive (tree, tree);
extern void finish_local_using_directive (tree, tree);
extern tree pushdecl_outermost_localscope (tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 248338)
+++ gcc/cp/parser.c (working copy)
@@ -18499,9 +18499,9 @@ cp_parser_using_declaration (cp_parser*
return false;
}
else if (!at_namespace_scope_p ())
- do_local_using_decl (decl, qscope, identifier);
+ finish_local_using_decl (decl, qscope, identifier);
else
- do_toplevel_using_decl (decl, qscope, identifier);
+ finish_namespace_using_decl (decl, qscope, identifier);
}
}
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 248338)
+++ gcc/cp/pt.c (working copy)
@@ -15696,7 +15696,7 @@ tsubst_expr (tree t, tree args, tsubst_f
if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
qualified_name_lookup_error (scope, name, decl, input_location);
else
- do_local_using_decl (decl, scope, name);
+ finish_local_using_decl (decl, scope, name);
}
else if (DECL_PACK_P (decl))
{
Index: libcc1/libcp1plugin.cc
===================================================================
--- libcc1/libcp1plugin.cc (revision 248338)
+++ libcc1/libcp1plugin.cc (working copy)
@@ -1030,13 +1030,12 @@ plugin_add_using_decl (cc1_plugin::conne
finish_member_declaration (decl);
}
- else if (!at_namespace_scope_p ())
+ else
{
- gcc_unreachable ();
- do_local_using_decl (target, tcontext, identifier);
+ /* We can't be at local scope. */
+ gcc_assert (at_namespace_scope_p ());
+ finish_namespace_using_decl (target, tcontext, identifier);
}
- else
- do_toplevel_using_decl (target, tcontext, identifier);
return 1;
}
Index: gcc/testsuite/g++.dg/lookup/using13.C
===================================================================
--- gcc/testsuite/g++.dg/lookup/using13.C (revision 248338)
+++ gcc/testsuite/g++.dg/lookup/using13.C (working copy)
@@ -8,5 +8,5 @@ namespace A { int a; }
namespace C{
int a;
- using A::a; // { dg-error "already declared" }
+ using A::a; // { dg-error "conflicts with a previous" }
}
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-05-21 15:30 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-21 14:32 [C++ PATCH] Using decls Nathan Sidwell
2019-05-21 14:44 ` Marek Polacek
2019-05-21 14:47 ` Nathan Sidwell
2019-05-21 15:30 ` Nathan Sidwell
-- strict thread matches above, loose matches on Subject: below --
2017-05-23 11:07 [C++ PATCH] using decls Nathan Sidwell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).