From patchwork Thu Dec 10 19:36:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Sidwell X-Patchwork-Id: 1414436 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=rfTBBesH; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4CsPLH3WMbz9sWQ for ; Fri, 11 Dec 2020 06:36:39 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E7FAB3833033; Thu, 10 Dec 2020 19:36:36 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qt1-x832.google.com (mail-qt1-x832.google.com [IPv6:2607:f8b0:4864:20::832]) by sourceware.org (Postfix) with ESMTPS id 97233385802D for ; Thu, 10 Dec 2020 19:36:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 97233385802D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nathanmsidwell@gmail.com Received: by mail-qt1-x832.google.com with SMTP id z3so4625269qtw.9 for ; Thu, 10 Dec 2020 11:36:33 -0800 (PST) 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=jMTs/ihxLnFw2V0UobzKQVEAMxGvAIk5efTubNzzoM8=; b=rfTBBesHYrNws6i/quLBhtWyKLuFaeO4Avb6sv238JbCQzO8w/PHAeZ+SWP7Wvz4Bp hnwqNjc8tT5CWnLWVbKVqWvejceul0c6QRAf5zX7w9kyb9dEQmcr29ho4CWbF7rXIyec KgaCyEO2TT6hvpCeFPSCOfNGPTbWOtBWlyA0eCvzV0fT/n1zgBIjmMbzh+Dsnr36SR/U 6PW/X/hrwSdOBiYFDTh84me3ljsv51IdS0MBq8Kdll2LpwCDGIX15+bBUG/SnYWRsjTE 9NpcyDoap4aZJf1zauscI1q+bTX33c7jNIosb9ZzqgG76agjF3u7vQsUKOF8aF/Ft7Ao w2OA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:to:from:subject:message-id:date :user-agent:mime-version:content-language; bh=jMTs/ihxLnFw2V0UobzKQVEAMxGvAIk5efTubNzzoM8=; b=XQYWNuyYtROQvbg85M0UrBbntiLBBRNc7r8lWJTTEb4rQVdzebgUUJFINHuIxXNxsI TIeVByLoTZjWzrMkgwyUZRDkrFh5hpKv0kngjH4axnq/C7L2jKn0NdIGLWmBgu1PlZCh tAaK4DnrNW5tknsl31i5DWo6qILnDElvCJuqMTOyp2gDxKhC6eSqIKGUtb7NOfFRnwLn j7K1G4zrTsMpcH9H0WTyn+R7d0AU+hzBqyKTAKXe461/hSiZdsS/t2bjHR9saYat6ixC 86QWt53D53RmB5vpVs+fK1WJoUzZ9RJHPvnUTvKswJvBEL4+sH8iIm7w63trfpwj4qub EC4A== X-Gm-Message-State: AOAM531KMPjqwkLuL0NJ9YchwTQzkECwlc0ueQBqeEn+qYmAx4oeHCNr Ls3z6V6NA3JcqnNGc5XE23Q= X-Google-Smtp-Source: ABdhPJxLbdTTJrZVWh+bF5OBz2YoTIo7pvKKk/TNi+0XLJcEs2pg9L+W2Y94r9d6wY3O3ZvbkmheEw== X-Received: by 2002:aed:2e63:: with SMTP id j90mr11148710qtd.338.1607628992648; Thu, 10 Dec 2020 11:36:32 -0800 (PST) Received: from ?IPv6:2620:10d:c0a8:1102:7d2d:1a8a:7a22:aa55? ([2620:10d:c091:480::1:6e18]) by smtp.googlemail.com with ESMTPSA id u26sm4569209qke.57.2020.12.10.11.36.31 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 10 Dec 2020 11:36:31 -0800 (PST) To: GCC Patches From: Nathan Sidwell Subject: c++: modules & using-decls Message-ID: Date: Thu, 10 Dec 2020 14:36:30 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 MIME-Version: 1.0 Content-Language: en-US X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" This extends using-decls to modules. In modules you can export a using decl, but the exported decl must have external linkage already. One thing you can do is export something from the GMF. The novel thing is that now 'export using foo::bar;' *in namespace bar* can mean something significant (rather than be an obscure nop). gcc/cp/ * name-lookup.c (do_nonmember_using_decl): Add INSERT_P parm. Deal with exporting using decls. (finish_nonmember_using_decl): Examine BINDING_VECTOR. pushing to trunk diff --git i/gcc/cp/name-lookup.c w/gcc/cp/name-lookup.c index 9c945842fa1..7dd4efa0a85 100644 --- i/gcc/cp/name-lookup.c +++ w/gcc/cp/name-lookup.c @@ -4567,7 +4567,7 @@ pushdecl_outermost_localscope (tree x) static bool do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, - tree *value_p, tree *type_p) + bool insert_p, tree *value_p, tree *type_p) { tree value = *value_p; tree type = *type_p; @@ -4587,13 +4587,33 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, lookup.value = NULL_TREE; } + /* Only process exporting if we're going to be inserting. */ + bool revealing_p = insert_p && !fn_scope_p && module_has_cmi_p (); + + /* First do the value binding. */ if (!lookup.value) - /* Nothing. */; + /* Nothing (only implicit typedef found). */ + gcc_checking_assert (lookup.type); else if (OVL_P (lookup.value) && (!value || OVL_P (value))) { for (lkp_iterator usings (lookup.value); usings; ++usings) { tree new_fn = *usings; + bool exporting = revealing_p && module_exporting_p (); + if (exporting) + { + /* If the using decl is exported, the things it refers + to must also be exported (or not in module purview). */ + if (!DECL_MODULE_EXPORT_P (new_fn) + && (DECL_LANG_SPECIFIC (new_fn) + && DECL_MODULE_PURVIEW_P (new_fn))) + { + error ("%q#D does not have external linkage", new_fn); + inform (DECL_SOURCE_LOCATION (new_fn), + "%q#D declared here", new_fn); + exporting = false; + } + } /* [namespace.udecl] @@ -4601,6 +4621,10 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, scope has the same name and the same parameter types as a function introduced by a using declaration the program is ill-formed. */ + /* This seems overreaching, asking core -- why do we care + about decls in the namespace that we cannot name (because + they are not transitively imported. We just check the + decls that are in this TU. */ bool found = false; for (ovl_iterator old (value); !found && old; ++old) { @@ -4609,8 +4633,25 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, if (new_fn == old_fn) { /* The function already exists in the current - namespace. */ + namespace. We will still want to insert it if + it is revealing a not-revealed thing. */ found = true; + if (!revealing_p) + ; + else if (old.using_p ()) + { + if (exporting) + /* Update in place. 'tis ok. */ + OVL_EXPORT_P (old.get_using ()) = true; + ; + } + else if (DECL_MODULE_EXPORT_P (new_fn)) + ; + else + { + value = old.remove_node (value); + found = false; + } break; } else if (old.using_p ()) @@ -4634,11 +4675,11 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, } } - if (!found) + 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); + value = ovl_insert (new_fn, value, 1 + exporting); } } else if (value @@ -4649,28 +4690,34 @@ do_nonmember_using_decl (name_lookup &lookup, bool fn_scope_p, diagnose_name_conflict (lookup.value, value); failed = true; } - else + else if (insert_p) + // FIXME:what if we're newly exporting lookup.value value = lookup.value; - + + /* Now the type binding. */ if (lookup.type && lookup.type != type) { + // FIXME: What if we're exporting lookup.type? if (type && !decls_match (lookup.type, type)) { diagnose_name_conflict (lookup.type, type); failed = true; } - else + else if (insert_p) type = lookup.type; } - /* If 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; } @@ -5506,8 +5553,10 @@ do_class_using_decl (tree scope, tree name) } -/* Return the binding for NAME in NS. If NS is NULL, look in - global_namespace. */ +/* Return the binding for NAME in NS in the current TU. If NS is + NULL, look in global_namespace. We will not find declarations + from imports. Users of this who, having found nothing, push a new + decl must be prepared for that pushing to match an existing decl. */ tree get_namespace_binding (tree ns, tree name) @@ -5908,21 +5957,94 @@ finish_nonmember_using_decl (tree scope, tree name) if (current_binding_level->kind == sk_namespace) { tree *slot = find_namespace_slot (current_namespace, name, true); + tree *mslot = get_fixed_binding_slot (slot, name, + BINDING_SLOT_CURRENT, true); + bool failed = false; - tree value = MAYBE_STAT_DECL (*slot); - tree type = MAYBE_STAT_TYPE (*slot); + if (mslot != slot) + { + /* A module vector. I presume the binding list is going to + be sparser than the import bitmap. Hence iterate over + the former checking for bits set in the bitmap. */ + bitmap imports = get_import_bitmap (); + binding_cluster *cluster = BINDING_VECTOR_CLUSTER_BASE (*slot); - do_nonmember_using_decl (lookup, false, &value, &type); + /* Scan the imported bindings. */ + unsigned ix = BINDING_VECTOR_NUM_CLUSTERS (*slot); + if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED) + { + ix--; + cluster++; + } - if (STAT_HACK_P (*slot)) + /* Do this in forward order, so we load modules in an order + the user expects. */ + for (; ix--; cluster++) + for (unsigned jx = 0; jx != BINDING_VECTOR_SLOTS_PER_CLUSTER; jx++) + { + /* Are we importing this module? */ + if (unsigned base = cluster->indices[jx].base) + if (unsigned span = cluster->indices[jx].span) + do + if (bitmap_bit_p (imports, base)) + goto found; + while (++base, --span); + continue; + + found:; + /* Is it loaded? */ + if (cluster->slots[jx].is_lazy ()) + { + gcc_assert (cluster->indices[jx].span == 1); + lazy_load_binding (cluster->indices[jx].base, + scope, name, &cluster->slots[jx]); + } + + tree value = cluster->slots[jx]; + if (!value) + /* Load errors could mean there's nothing here. */ + continue; + + /* Extract what we can see from here. If there's no + stat_hack, then everything was exported. */ + tree type = NULL_TREE; + + /* If no stat hack, everything is visible. */ + if (STAT_HACK_P (value)) + { + if (STAT_TYPE_VISIBLE_P (value)) + type = STAT_TYPE (value); + value = STAT_VISIBLE (value); + } + + if (do_nonmember_using_decl (lookup, false, false, + &value, &type)) + { + failed = true; + break; + } + } + } + + if (!failed) { - STAT_DECL (*slot) = value; - STAT_TYPE (*slot) = type; + /* Now do the current slot. */ + tree value = MAYBE_STAT_DECL (*mslot); + tree type = MAYBE_STAT_TYPE (*mslot); + + do_nonmember_using_decl (lookup, false, true, &value, &type); + + // FIXME: Partition mergeableness? + if (STAT_HACK_P (*mslot)) + { + STAT_DECL (*mslot) = value; + STAT_TYPE (*mslot) = type; + } + else if (type) + *mslot = stat_hack (value, type); + else + *mslot = value; } - else if (type) - *slot = stat_hack (value, type); - else - *slot = value; } else { @@ -5940,7 +6062,7 @@ finish_nonmember_using_decl (tree scope, tree name) /* 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, &value, &type); + do_nonmember_using_decl (lookup, true, true, &value, &type); if (!value) ;