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