From 692af872fa50106af090e17cef92481207c33e89 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 21 May 2019 14:33:24 +0000 Subject: [PATCH] [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 --- gcc/cp/ChangeLog | 13 + gcc/cp/name-lookup.c | 391 +++++++++++--------------- gcc/cp/name-lookup.h | 8 +- gcc/cp/parser.c | 19 +- gcc/cp/pt.c | 8 +- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/lookup/using53.C | 2 +- libcc1/ChangeLog | 5 + libcc1/libcp1plugin.cc | 2 +- 9 files changed, 193 insertions(+), 259 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f895f139ca7..2095e1f5b4b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2019-05-21 Nathan Sidwell + + * 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 * decl2.c (cpp_check) : New case. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 476ba509231..1c21adba682 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 %", 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 aa6180f2d2a..b44687e96bb 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 *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 b2d6c33300d..290f897ec14 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 3519c7a34a6..592adfcf5c1 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 d68685ba9db..bdc58ba14e4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-05-21 Nathan Sidwell + + * g++.dg/lookup/using53.C: Adjust diagnostic. + 2019-05-21 Richard Biener PR middle-end/90510 diff --git a/gcc/testsuite/g++.dg/lookup/using53.C b/gcc/testsuite/g++.dg/lookup/using53.C index a108b50ef89..595612e4efe 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" } } diff --git a/libcc1/ChangeLog b/libcc1/ChangeLog index 376e3622410..e243e554d64 100644 --- a/libcc1/ChangeLog +++ b/libcc1/ChangeLog @@ -1,3 +1,8 @@ +2019-05-21 Nathan Sidwell + + * libcp1plugin.cc (plugin_add_using_decl): Use + finish_nonmember_using_decl. + 2019-05-20 Nathan Sidwell * libcp1plugin.cc (plugin_add_using_namespace): Call renamed diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc index eed94662f85..d241ea1033d 100644 --- a/libcc1/libcp1plugin.cc +++ b/libcc1/libcp1plugin.cc @@ -1019,7 +1019,7 @@ plugin_add_using_decl (cc1_plugin::connection *, { /* 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); } return 1; -- 2.30.2