On Fri, Sep 27, 2024 at 11:56:27AM -0400, Jason Merrill wrote:
> On 9/23/24 7:46 PM, Nathaniel Shead wrote:
> > Currently I just stream DECL_NAME in TU_LOCAL_ENTITYs for use in 
> > diagnostics,
> > but this feels perhaps insufficient.  Are there any better approached here?
> > Otherwise I don't think it matters too much, as which entity it is will also
> > be hopefully clear from the 'declared here' notes.
> > 
> > I've put the new warning in Wextra, but maybe it would be better to just
> > leave it out of any of the normal warning groups since there's currently
> > no good way to work around the warnings it produces?
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > 
> > -- >8 --
> > 
> > [basic.link] p14 lists a number of circumstances where a declaration
> > naming a TU-local entity is not an exposure, notably the bodies of
> > non-inline templates and friend declarations in classes.  This patch
> > ensures that these references do not error when exporting the module.
> > 
> > We do need to still error on instantiation from a different module,
> > however, in case this refers to a TU-local entity.  As such this patch
> > adds a new tree TU_LOCAL_ENTITY which is used purely as a placeholder to
> > poison any attempted template instantiations that refer to it.
> > 
> > This is also streamed for friend decls so that merging (based on the
> > index of an entity into the friend decl list) doesn't break and to
> > prevent complicating the logic; I imagine this shouldn't ever come up
> > though.
> > 
> > We also add a new warning, '-Wignored-exposures', to handle the case
> > where someone accidentally refers to a TU-local value from within a
> > non-inline function template.  This will compile without errors as-is,
> > but any attempt to instantiate the decl will fail; this warning can be
> > used to ensure that this doesn't happen.  Unfortunately the warning has
> > quite some false positives; for instance, a user could deliberately only
> > call explicit instantiations of the decl, or use 'if constexpr' to avoid
> > instantiating the TU-local entity from other TUs, neither of which are
> > currently detected.
> 
> I disagree with the term "ignored exposure", in the warning name and in the
> rest of the patch; these references are not exposures.  It's the naming of a
> TU-local entity that is ignored in basic.link/14.
> 
> I like the warning, just would change the name. "-Wtemplate-names-tu-local"?
> "-Wtu-local-in-template"?
> 

I wasn't too happy with "ignored exposures" either, I much prefer these
names.  I'll use these in the next version of this patch.

> I'm not too concerned about false positives, as long as it can be
> effectively suppressed with #pragma GCC diagnostic ignored.  If you only use
> explicit instantiations you don't need to have the template body in the
> interface anyway.
> 

The main case I'm thinking of that would be annoying would be

  static void tu_local_fn() { /* ... */ }

  export template <typename T>
  void foo() {
    if constexpr (std::is_same_v<T, int>)
      tu_local_fn();
    // ...
  }
  template foo<int>();

But this should be able to silenced with #pragma so I suppose that's OK
for Wextra (and is probably fairly unusual code to begin with).  And
even more so if the following is fixed...

> > +     /* Ideally we would only warn in cases where there are no explicit
> > +        instantiations of the template, but we don't currently track this
> > +        in an easy-to-find way.  */
> 
> You can't walk DECL_TEMPLATE_INSTANTIATIONS checking
> DECL_EXPLICIT_INSTANTIATION?
> 

I tried, but it looks like DECL_TEMPLATE_INSTANTIATIONS doesn't include
explicit instantiations for function templates definitions once we get
to module processing: it's only recorded for namespace-scope primary
function templates without definitions.

I think I would be able to update 'register_specialization' to more
eagerly include instantiations for every function template in this list,
but I wasn't sure if we wanted to do that just for this if it's not
already necessary, since that would potentially grow it quite a lot.

It strikes me as I write this though that the fact we currently
correctly mark GMF explicit instantiations as reachable is not because
looking through DECL_TEMPLATE_INSTANTIATIONS works, but because of the
issue we've discussed earlier where GMF instantiations are deferred
until the end of the TU and then get marked as purview... so I suppose
we do need to fix this anyway in anticipation of solving that issue.

See e.g.

  module;
  template <typename T> void foo();
  template void foo<int>();
  export module M;

with -fdump-lang-module-graph which shows that we emit the instantiation
despite never referencing it from purview.

> What happens with a non-templated, non-inline function body that names a
> TU-local entity?  I don't see any specific handling or testcase.  Should we
> just omit its definition, like you do in the previous patch for TU-local
> variable initializers?
> 

Non-template, non-inline function bodies already have their definitions
omitted by has_definition, so this patch didn't need to do anything
special.  There's a testcase for this in internal-5, see e.g.

  // The function body for a non-inline function or function template
  export void function() {
    internal_t i {};
    internal_tmpl_t<int> ii {};
    internal_ovl(internal_x);
    internal_tmpl<int>();
  }
  
  export template <typename T> void function_tmpl() {  // { dg-warning "refers 
to TU-local entity" }
    internal_t i {};
    internal_tmpl_t<T> ii {};
    internal_ovl(internal_x);
    internal_tmpl<T>();
  }
  template void function_tmpl<ok_inst_tag>();

and matching calls in the importer.  I should probably add a test for
explicit specialisations too, however; I'll update that in the next
version.

Nathaniel

Reply via email to