aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2019-05-21 14:33:24 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2019-05-21 14:33:24 +0000
commit692af872fa50106af090e17cef92481207c33e89 (patch)
tree2ef4422c1eeae7e57ee71a77da6262876febb002 /gcc
parentf445f0f06cf6c5d44675a5c3aaeb54e7258a4e01 (diff)
downloadgcc-692af872fa50106af090e17cef92481207c33e89.zip
gcc-692af872fa50106af090e17cef92481207c33e89.tar.gz
gcc-692af872fa50106af090e17cef92481207c33e89.tar.bz2
[C++ PATCH] Using decls
https://gcc.gnu.org/ml/gcc-patches/2019-05/msg01396.html 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. From-SVN: r271467
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog13
-rw-r--r--gcc/cp/name-lookup.c391
-rw-r--r--gcc/cp/name-lookup.h8
-rw-r--r--gcc/cp/parser.c19
-rw-r--r--gcc/cp/pt.c8
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/lookup/using53.C2
7 files changed, 187 insertions, 258 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f895f13..2095e1f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2019-05-21 Nathan Sidwell <nathan@acm.org>
+
+ * 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.
+
2019-05-21 Eric Botcazou <ebotcazou@adacore.com>
* decl2.c (cpp_check) <IS_ASSIGNMENT_OPERATOR>: New case.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 476ba50..1c21adb 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -3829,42 +3829,6 @@ make_lambda_name (void)
return get_identifier (buf);
}
-/* 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.
@@ -3918,91 +3882,19 @@ pushdecl_outermost_localscope (tree x)
return ret;
}
-/* 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
enumeration names to each other. */
@@ -4018,79 +3910,95 @@ do_nonmember_using_decl (tree scope, tree name, tree *value_p, tree *type_p)
lookup.value = NULL_TREE;
}
- if (lookup.value && lookup.value != value)
+ if (!lookup.value)
+ /* Nothing. */;
+ else if (OVL_P (lookup.value) && (!value || OVL_P (value)))
{
- /* Check for using functions. */
- if (OVL_P (lookup.value) && (!value || OVL_P (value)))
+ for (lkp_iterator usings (lookup.value); usings; ++usings)
{
- for (lkp_iterator usings (lookup.value); usings; ++usings)
- {
- tree new_fn = *usings;
+ tree new_fn = *usings;
- /* [namespace.udecl]
+ /* [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 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 old_fn = *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);
}
+
+ 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)
- && !decls_match (lookup.value, value))
- diagnose_name_conflict (lookup.value, value);
- else
- value = lookup.value;
}
+ 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;
}
/* Returns true if ANCESTOR encloses DESCENDANT, including matching.
@@ -5120,84 +5028,115 @@ pushdecl_namespace_level (tree x, bool is_friend)
return t;
}
-/* 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;
+ }
- add_decl_expr (decl);
+ /* Emit debug info. */
+ if (!processing_template_decl)
+ cp_emit_debug_info_for_using (lookup.value,
+ current_binding_level->this_entity);
- cxx_binding *binding = find_local_binding (current_binding_level, name);
- tree value = binding ? binding->value : NULL_TREE;
- tree type = binding ? binding->type : NULL_TREE;
+ if (current_binding_level->kind == sk_namespace)
+ {
+ tree *slot = find_namespace_slot (current_namespace, name, true);
- do_nonmember_using_decl (scope, name, &value, &type);
+ tree value = MAYBE_STAT_DECL (*slot);
+ tree type = MAYBE_STAT_TYPE (*slot);
- 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);
+ do_nonmember_using_decl (lookup, false, true, &value, &type);
- if (!type)
- ;
- else if (binding && type == binding->type)
- ;
+ 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
{
- 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 ());
}
/* Return the declarations that are members of the namespace NS. */
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index aa6180f..b44687e 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -176,9 +176,6 @@ struct GTY(()) cp_binding_level {
are wrapped in TREE_LISTs; the TREE_VALUE is the OVERLOAD. */
tree names;
- /* A list of USING_DECL nodes. */
- tree usings;
-
/* Using directives. */
vec<tree, va_gc> *using_directives;
@@ -315,9 +312,8 @@ extern tree innermost_non_namespace_value (tree);
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_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);
extern tree pushdecl_top_level (tree, bool is_friend = false);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b2d6c33..290f897 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19519,24 +19519,7 @@ cp_parser_using_declaration (cp_parser* parser,
finish_member_declaration (decl);
}
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);
}
if (!access_declaration_p
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3519c7a..592adfc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17072,13 +17072,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
tree name = DECL_NAME (decl);
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)
&& !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d68685b..bdc58ba 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2019-05-21 Nathan Sidwell <nathan@acm.org>
+
+ * g++.dg/lookup/using53.C: Adjust diagnostic.
+
2019-05-21 Richard Biener <rguenther@suse.de>
PR middle-end/90510
diff --git a/gcc/testsuite/g++.dg/lookup/using53.C b/gcc/testsuite/g++.dg/lookup/using53.C
index a108b50..595612e 100644
--- a/gcc/testsuite/g++.dg/lookup/using53.C
+++ b/gcc/testsuite/g++.dg/lookup/using53.C
@@ -49,5 +49,5 @@ void
f ()
{
using N::i;
- using N::i; // { dg-error "declared" }
+ using N::i; // { dg-error "redeclaration" }
}