From patchwork Tue May 21 14:32:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 1102847 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-501343-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=acm.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 457dXM6H4Xz9s1c for ; Wed, 22 May 2019 00:32:47 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=iiLmzaER539O0483wk7OHNLIoL+mHC0tceVu4wluVipz1AQMcf Zq95a5hgSrgw2oY4uZD1r3xvwxRjFrdCVzgPTd7h29iw3ll8fGyMYQRzd2GxHfaV wTc7/kcrks2fWh1aKjovuZEV16d4KSgsruER7HY1t4rG2HwlD/Ckv+i2k= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to :from:subject:message-id:date:mime-version:content-type; s= default; bh=Ef56e5MKMANQ84X2/sD5Pgia0DY=; b=EVleJqjtp7Y98yFlRVFu /FDNz4LFz6DJKIidj66mYSwlbf0a60P2SzwUestHSBUvxlIIBvutirUZY+Ai81AE Oo07Oqyj/ULbHEbWQL2Y8nj5HVraVv5ZsW9qQiOtkdqUXQvHgynxBCayh4NpGwX0 KWqldGKHgySejEVvCqZDnn0= Received: (qmail 52187 invoked by alias); 21 May 2019 14:32:40 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 52165 invoked by uid 89); 21 May 2019 14:32:39 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=circuit, anticipated, nominated, Short X-HELO: mail-pf1-f175.google.com Received: from mail-pf1-f175.google.com (HELO mail-pf1-f175.google.com) (209.85.210.175) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 21 May 2019 14:32:36 +0000 Received: by mail-pf1-f175.google.com with SMTP id g9so9157826pfo.11 for ; Tue, 21 May 2019 07:32:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:to:from:subject:message-id:date:user-agent:mime-version :content-language; bh=vPrcQ1xwDd7F88JRUkoHm7VKC5OH+WpFSl75zJoGBlA=; b=jhGqZl4+e5FmNeeaU4v0gNNK2r4FP/CmzRgVYa9BJ+rMHQFeN/8Z8oB+R+y88SY8vp xMDNTvfoL5XtuBKECiAC8GvoNeqOP+5FELyh5WcJDsYLDghgCws743teVi8q4bKYCnWb leUuDB7+aSgq5Eum0a62Tu7JqgR6Tlxi9onw2HDu1PMOeODiy8sqPBt5KoexFiGUc64M jynMZKG8deGIheFn0CG6PavsLksLERfqusA4+AxRkU6sMdLjbhGXzkU+UgJufrXhDStC f1QXQKjWJPL2p3lVlbajDwiSvd+H69WOk0ZObthVeC3Qk4QFD/gCCmqHmQ9SQ32N+r7P lJXg== Received: from ?IPv6:2620:10d:c0a3:1407:6077:ec57:6cfa:c95c? ([2620:10d:c091:500::3:8245]) by smtp.googlemail.com with ESMTPSA id a7sm40016860pgj.42.2019.05.21.07.32.33 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Tue, 21 May 2019 07:32:34 -0700 (PDT) To: GCC Patches From: Nathan Sidwell Subject: [C++ PATCH] Using decls Message-ID: <328937e0-531e-a7be-3151-e3a622be0efa@acm.org> Date: Tue, 21 May 2019 10:32:31 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 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 2019-05-21 Nathan Sidwell 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 %", 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 *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); }