From: Jason Merrill <jason@redhat.com>
To: Nathaniel Shead <nathanieloshead@gmail.com>
Cc: gcc-patches@gcc.gnu.org, Nathan Sidwell <nathan@acm.org>
Subject: Re: [PATCH v2] c++: Check module attachment instead of just purview when necessary [PR112631]
Date: Mon, 11 Mar 2024 14:13:34 -0400 [thread overview]
Message-ID: <8eeb8781-7625-4482-a9b2-576638e0b971@redhat.com> (raw)
In-Reply-To: <65eb9cae.a70a0220.5c928.117d@mx.google.com>
On 3/8/24 18:18, Nathaniel Shead wrote:
> On Fri, Mar 08, 2024 at 10:19:52AM -0500, Jason Merrill wrote:
>> On 3/7/24 21:55, Nathaniel Shead wrote:
>>> On Mon, Nov 27, 2023 at 03:59:39PM +1100, Nathaniel Shead wrote:
>>>> On Thu, Nov 23, 2023 at 03:03:37PM -0500, Nathan Sidwell wrote:
>>>>> On 11/20/23 04:47, Nathaniel Shead wrote:
>>>>>> Bootstrapped and regtested on x86_64-pc-linux-gnu. I don't have write
>>>>>> access.
>>>>>>
>>>>>> -- >8 --
>>>>>>
>>>>>> Block-scope declarations of functions or extern values are not allowed
>>>>>> when attached to a named module. Similarly, class member functions are
>>>>>> not inline if attached to a named module. However, in both these cases
>>>>>> we currently only check if the declaration is within the module purview;
>>>>>> it is possible for such a declaration to occur within the module purview
>>>>>> but not be attached to a named module (e.g. in an 'extern "C++"' block).
>>>>>> This patch makes the required adjustments.
>>>>>
>>>>>
>>>>> Ah I'd been puzzling over the default inlinedness of member-fns of
>>>>> block-scope structs. Could you augment the testcase to make sure that's
>>>>> right too?
>>>>>
>>>>> Something like:
>>>>>
>>>>> // dg-module-do link
>>>>> export module Mod;
>>>>>
>>>>> export auto Get () {
>>>>> struct X { void Fn () {} };
>>>>> return X();
>>>>> }
>>>>>
>>>>>
>>>>> ///
>>>>> import Mod
>>>>> void Frob () { Get().Fn(); }
>>>>>
>>>>
>>>> I gave this a try and it indeed doesn't work correctly; 'Fn' needs to be
>>>> marked 'inline' for this to link (whether or not 'Get' itself is
>>>> inline). I've tried tracing the code to work out what's going on but
>>>> I've been struggling to work out how all the different flags (e.g.
>>>> TREE_PUBLIC, TREE_EXTERNAL, TREE_COMDAT, DECL_NOT_REALLY_EXTERN)
>>>> interact, which flags we want to be set where, and where the decision of
>>>> what function definitions to emit is actually made.
>>>>
>>>> I did find that doing 'mark_used(decl)' on all member functions in
>>>> block-scope structs seems to work however, but I wonder if that's maybe
>>>> too aggressive or if there's something else we should be doing?
>>>
>>> I got around to looking at this again, here's an updated version of this
>>> patch. Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
>>>
>>> (I'm not sure if 'start_preparsed_function' is the right place to be
>>> putting this kind of logic or if it should instead be going in
>>> 'grokfndecl', e.g. decl.cc:10761 where the rules for making local
>>> functions have no linkage are initially determined, but I found this
>>> easier to implement: happy to move around though if preferred.)
>>>
>>> -- >8 --
>>>
>>> Block-scope declarations of functions or extern values are not allowed
>>> when attached to a named module. Similarly, class member functions are
>>> not inline if attached to a named module. However, in both these cases
>>> we currently only check if the declaration is within the module purview;
>>> it is possible for such a declaration to occur within the module purview
>>> but not be attached to a named module (e.g. in an 'extern "C++"' block).
>>> This patch makes the required adjustments.
>>>
>>> While implementing this we discovered that block-scope local functions
>>> are not correctly emitted, causing link failures; this patch also
>>> corrects some assumptions here and ensures that they are emitted when
>>> needed.
>>>
>>> PR c++/112631
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * cp-tree.h (named_module_attach_p): New function.
>>> * decl.cc (start_decl): Check for attachment not purview.
>>> (grokmethod): Likewise.
>>
>> These changes are OK; the others I want to consider more.
>
> Thanks, I can commit this as a separate commit if you prefer?
Please.
>>> +export auto n_n() {
>>> + internal();
>>> + struct X { void f() { internal(); } };
>>> + return X{};
>>
>> Hmm, is this not a prohibited exposure? Seems like X has no linkage because
>> it's at block scope, and the deduced return type names it.
>>
>> I know we try to support this "voldemort" pattern, but is that actually
>> correct?
>
> I had similar doubts, but this is not an especially uncommon pattern in
> the wild either. I also asked some other people for their thoughts and
> got told:
>
> "no linkage" doesn't mean it's ill-formed to name it in other scopes.
> It means a declaration in another scope cannot correspond to it
>
> And that the wording in [basic.link] p2.4 is imprecise. (Apparently they
> were going to raise a core issue about this too, I think?)
>
> As for whether it's an exposure, looking at [basic.link] p15, the entity
> 'X' doesn't actually appear to be TU-local: it doesn't have a name with
> internal linkage (no linkage is different) and is not declared or
> introduced within the definition of a TU-local entity (n_n is not
> TU-local).
Hmm, I think you're right. And this rule:
> - /* DR 757: A type without linkage shall not be used as the type of a
> - variable or function with linkage, unless
> - o the variable or function has extern "C" linkage (7.5 [dcl.link]), or
> - o the variable or function is not used (3.2 [basic.def.odr]) or is
> - defined in the same translation unit.
is no longer part of the standard since C++20; the remnant of this rule
is the example in
https://eel.is/c++draft/basic#def.odr-11
> auto f() {
> struct A {};
> return A{};
> }
> decltype(f()) g();
> auto x = g();
> A program containing this translation unit is ill-formed because g is odr-used but not defined, and cannot be defined in any other translation unit because the local class A cannot be named outside this translation unit.
But g could be defined in another translation unit if f is inline or in
a module interface unit.
So, I think no_linkage_check needs to consider module_has_cmi_p as well
as vague_linkage_p for relaxed mode. And in no_linkage_error if
no_linkage_check returns null in relaxed mode, reduce the permerror to a
pedwarn before C++20, and no diagnostic at all in C++20 and above.
> + if (ctx != NULL_TREE && TREE_PUBLIC (ctx) && module_has_cmi_p ())
> + {
> + /* Ensure that functions in local classes within named modules
> + have their definitions exported, in case they are (directly
> + or indirectly) used by an importer. */
> + TREE_PUBLIC (decl1) = true;
> + if (DECL_DECLARED_INLINE_P (decl1))
> + comdat_linkage (decl1);
> + else
> + mark_needed (decl1);
> + }
Isn't the inline case handled by the comdat_linkage just above?
Jason
next prev parent reply other threads:[~2024-03-11 18:13 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-20 9:47 [PATCH] c++: Check module attachment instead of " Nathaniel Shead
2023-11-23 20:03 ` Nathan Sidwell
2023-11-27 4:59 ` Nathaniel Shead
2024-03-08 2:55 ` [PATCH v2] c++: Check module attachment instead of just " Nathaniel Shead
2024-03-08 15:19 ` Jason Merrill
2024-03-08 23:18 ` Nathaniel Shead
2024-03-11 18:13 ` Jason Merrill [this message]
2024-03-16 11:23 ` [PATCH v3] c++: Fix handling of no-linkage decls for modules Nathaniel Shead
2024-03-19 0:58 ` Jason Merrill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8eeb8781-7625-4482-a9b2-576638e0b971@redhat.com \
--to=jason@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=nathan@acm.org \
--cc=nathanieloshead@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).