On Thu, Jul 18, 2024 at 02:33:56PM -0400, Jason Merrill wrote:
> On 7/18/24 12:33 AM, Nathaniel Shead wrote:
> > On Wed, Jul 17, 2024 at 11:36:26PM -0400, Jason Merrill wrote:
> > > On 7/17/24 11:04 PM, Nathaniel Shead wrote:
> > > > On Wed, Jul 17, 2024 at 01:12:34PM -0400, Jason Merrill wrote:
> > > > > On 5/1/24 11:27 AM, Jason Merrill wrote:
> > > > > > On 5/1/24 07:11, Patrick Palka wrote:
> > > > > > > On Wed, 1 May 2024, Nathaniel Shead wrote:
> > > > > > >
> > > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > > > > > >
> > > > > > > > -- >8 --
> > > > > > > >
> > > > > > > > When calling instantiate_pending_templates at end of parsing,
> > > > > > > > any new
> > > > > > > > functions that are instantiated from this point have their
> > > > > > > > module
> > > > > > > > purview set based on the current value of module_kind.
> > > > > > > >
> > > > > > > > This is unideal, however, as the modules code will then treat
> > > > > > > > these
> > > > > > > > instantiations as reachable and cause large swathes of the GMF
> > > > > > > > to be
> > > > > > > > emitted into the module CMI, despite no code in the actual
> > > > > > > > module
> > > > > > > > purview referencing it.
> > > > > > > >
> > > > > > > > This patch fixes this by also remembering the value of
> > > > > > > > module_kind when
> > > > > > > > the instantiation was deferred, and restoring it when doing this
> > > > > > > > deferred instantiation. That way newly instantiated
> > > > > > > > declarations
> > > > > > > > appropriately get a DECL_MODULE_PURVIEW_P appropriate for where
> > > > > > > > the
> > > > > > > > instantiation was required, meaning that GMF entities won't be
> > > > > > > > counted
> > > > > > > > as reachable unless referenced by an actually reachable entity.
> > > > > > > >
> > > > > > > > Note that purviewness and attachment etc. is generally only
> > > > > > > > determined
> > > > > > > > by the base template: this is purely for determining whether a
> > > > > > > > specialisation was declared in the module purview and hence
> > > > > > > > whether it
> > > > > > > > should be streamed out. See the comment on
> > > > > > > > 'set_instantiating_module'.
> > > > > > > >
> > > > > > > > PR c++/114630
> > > > > > > > PR c++/114795
> > > > > > > >
> > > > > > > > gcc/cp/ChangeLog:
> > > > > > > >
> > > > > > > > * cp-tree.h (struct tinst_level): Add field for tracking
> > > > > > > > module_kind.
> > > > > > > > * pt.cc (push_tinst_level_loc): Cache module_kind in
> > > > > > > > new_level.
> > > > > > > > (reopen_tinst_level): Restore module_kind from level.
> > > > > > > > (instantiate_pending_templates): Save and restore
> > > > > > > > module_kind so
> > > > > > > > it isn't affected by reopen_tinst_level.
> > > > > > >
> > > > > > > LGTM. Another approach is to instantiate all so-far deferred
> > > > > > > instantiations and vtables once we reach the start of the module
> > > > > > > purview, but your approach is much cleaner.
> > > > > >
> > > > > > Hmm, I actually think I like the approach of instantiating at that
> > > > > > point
> > > > > > better, so that instantiations in the GMF can't depend on things in
> > > > > > module purview.
> > > > > >
> > > > > > And probably do the same again when switching to the private module
> > > > > > fragment, when that's implemented.
> > > > >
> > > > > Patrick mentioned these patches again today; I still think this is
> > > > > the right
> > > > > approach, particularly for the private module fragment.
> > > > >
> > > > > That said, could we just clear module_kind at EOF? As you say, only
> > > > > the
> > > > > purviewness of the template matters for implicit instantiations. It
> > > > > is
> > > > > seeming to me like "set_instantiating_module" should only apply for
> > > > > explicit
> > > > > instantiations, at the point of the explicit instantiation
> > > > > declaration.
> > > > >
> > > > > Jason
> > > > >
> > > >
> > > > Yup, I agree that this is the right approach, since as you say we'll
> > > > need to do this for private module fragment anyway; I've just left this
> > > > on the backburner because it didn't look particularly easy to do neatly
> > > > and have been focussing on crashes instead for now.
> > > >
> > > > That sounds like a good idea, I've given that a shot and it succeeds
> > > > bootstrap + regtest (so far just modules.exp) on x86_64-pc-linux-gnu.
> > > > Here's the patch, OK for trunk if full regtest succeeds?
> > >
> > > Is there a test that an explicit instantiation in module purview is not
> > > discarded? OK if so.
> >
> > Ah, there doesn't appear to be; I created a new test but it looks like
> > all explicit instantiations are deferred, which means that they then
> > aren't marked as purview. So it doesn't look like this solution by
> > itself actually works.
> >
> > module;
> > template <typename T> void foo() {}
> > export module M;
> > template void foo<int>();
> >
> > // impl.cpp
> > module M;
> > void bar() { foo<int>(); } // error, foo has been discarded
> >
> > As I was writing this I also did a bit more testing and there are other
> > things that we don't currently detect as reachable even when they should
> > be; for instance, according to [module.global.frag] p3.1 the following
> > should probably work, but currently does not:
> >
> > module;
> > inline int x = 123;
> > export module M;
> > int y = x; // x is decl-reachable from y
> >
> > // impl.cpp
> > module M;
> > int z = x; // currently errors because 'x' has been discarded
>
> I would expect that error whether or not x is discarded; x is not exported
> or attached to M, so it's not found by name lookup under
> https://eel.is/c++draft/basic#lookup.general-2.3
>
Ah right, of course; here's a different testcase then:
module;
inline int x = 123; // #1
export module M;
int y = x;
// impl.cpp
module M;
extern "C++" double x; // #2
Since by http://eel.is/c++draft/basic.link#11 this requires a
diagnostic. The declarations have the same name, correspond, and both
declare names with external linkage, and so declare the same entity, but
with different types. And as mentioned earlier, #1 should not be
discarded (it's decl-reachable from y) and so is reachable from #2.
That said this is probably a fairly low-priority issue to fix.
> > So there's probably a fair bit of work to do here.
> >
> > It also strikes me that the standard requires us to keep decls reachable
> > when referred to from even non-inline function bodies, whereas our
> > current implementation quite deliberately tries to prevent this from
> > occurring.
>
> Hmm, I agree. That surprises me, so I just sent this to CWG:
>
> --
> The rationale for P1779 included
> "The inline keyword therefore allows a module author to choose, for each
> exposed function, whether to expose its implementation to importers, gaining
> the possibility of better performance at the expense of tighter coupling
> (and thus stronger restrictions on evolution of the library code and/or more
> frequent recompiles for the client)."
>
> But AFAICT that's not actually achieved by the wording, which primarily
> allows a module author to choose to avoid errors about exposing TU-local
> entities.
>
> I don't see anything that precludes an implementation from making non-inline
> function bodies reachable to importers; compilers will often inline
> functions that are marked inline. I suppose P1779 does avoid requiring that
> they be reachable under [basic.def.odr]/13, but does not prevent it.
>
> Typically, it seems desirable for compilers to make reachable all non-inline
> function bodies that aren't exposures, for inlining/IPA of small functions
> without needing to resort to LTO.
>
> For a function template, we generally need the implementation to be
> reachable regardless of whether it's inline, so that it can be instantiated
> by importers.
>
> [module.global.frag] seems to say that anything in the global module used in
> the implementation of a function is decl-reachable, and therefore not
> discarded, regardless of whether the function is inline.
>
> So, the actual effect of P1779 on reachability (and thus, what ends up in
> the BMI) seems to be pretty minimal. Am I missing anything?
>
> Jason
>