On Fri, Jul 26, 2024 at 01:17:57PM -0400, Jason Merrill wrote:
> On 7/26/24 12:52 AM, Nathaniel Shead wrote:
> > On Tue, Jul 23, 2024 at 04:17:22PM -0400, Jason Merrill wrote:
> > > On 6/15/24 10:29 PM, Nathaniel Shead wrote:
> > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
> > > >
> > > > This probably isn't the most efficient approach, since we need to do
> > > > name lookup to find deduction guides for a type which will also
> > > > potentially do a bunch of pointless lazy loading from imported modules,
> > > > but I wasn't able to work out a better approach without completely
> > > > reworking how deduction guides are stored and represented.
> > >
> > > Indeed. We likely want to find them more directly from the template; it's
> > > not clear to me that DECL_INITIAL is used for TEMPLATE_DECL, or we could
> > > put
> > > them in an internal attribute or a separate hash table.
> > >
> > > > -- >8 --
> > > >
> > > > Deduction guides are represented as 'normal' functions currently, and
> > > > have no special handling in modules. However, this causes some issues;
> > > > by [temp.deduct.guide] a deduction guide is not found by normal name
> > > > lookup and instead all reachable deduction guides for a class template
> > > > should be considered, but this does not happen currently.
> > > >
> > > > To solve this, this patch ensures that all deduction guides are
> > > > considered exported to ensure that they are always visible to importers
> > > > if they are reachable. Another alternative here would be to add a new
> > > > kind of "all reachable" flag to name lookup, but that is complicated by
> > > > some difficulties in handling GM entities; this may be a better way to
> > > > go if more kinds of entities end up needing this handling, however.
> > > >
> > > > Another issue here is that because deduction guides are "unrelated"
> > > > functions, they will usually get discarded from the GMF, so this patch
> > > > ensures that when finding dependencies, GMF deduction guides will also
> > > > have bindings created. We do this in find_dependencies so that we don't
> > > > unnecessarily create bindings for GMF deduction guides that are never
> > > > reached; for consistency we do this for *all* deduction guides, not just
> > > > GM ones.
> > >
> > > If you fixed the dependency calculation, why do they also need to be
> > > exported?
> >
> > Deduction guides aren't found using normal name lookup, but any
> > reachable deduction guide must be considered. This means that even if
> > the module interface exports no declarations whatsoever, a deduction
> > guide declared in the module purview must still be considered by
> > importers.
>
> Ah, I was missing the name lookup issue.
>
> > The other option I've considered is adding a new "ANY_REACHABLE" flag to
> > name lookup which would also consider non-exported reachable decls. On
> > further consideration I might actually go this way; I've been thinking
> > about how to resolve some issues adjacent to supporting textual
> > redefinitions that I believe this will be necessary for anyway, and we
> > can probably use this in tsubst_friend_class as well rather than the
> > current relatively ad-hoc solution.
>
> There's also my hack in lookup_elaborated_type for ABI namespace types.
>
> I'm not sure that it should be necessary to do this for redefinitions,
> though; what's the advantage over merging in check_module_override (apart
> from that needing to be fixed)?
>
My thought had been because currently type redefinitions don't go
through 'check_module_override' at all, if the existing type name is
visible, and so I was thinking to fix it at that end instead. This was
also to fix things that aren't strictly redefinitions but also fail
currently, e.g.
module;
template <typename T> struct S;
export module M;
export S<int> foo(); // declares a specialisation of S
// ...
import M;
template <typename T> struct S {}; // definition of template
int main() {
foo(); // error: invalid use of incomplete type, because
// we don't ever go through redeclare_class_template in xref_tag
}
But on further thought maybe it would be more consistent to ensure that
check_module_override handles this, since I suppose we still need to
handle things like the following anyway:
export module M;
struct S {}; // not exported
// ...
import M;
template <typename T> struct S {};
Though the names correspond ([basic.scope.scope] p4), they don't declare
the same entity ([basic.link] p8) since they have different attachment,
and they don't potentially conflict ([basic.scope.scope] p6) because S@M
doesn't precede the template decl because it's not visible to name
lookup. So an "any reachable" flag would be incorrect here regardless.
(Personally, I now even wonder whether it'd be make sense to be more
consistent here, by type declarations always being a new type that is
then merged with an existing one where necessary, rather than xref_tag
always returning an existing type if it finds one, which would help with
compiler errors in the presence of using-decls and help avoid the
duplication of checks for redefining existing names spread across
various places in parser.cc, decl.cc, and name-lookup.cc?)
> > That said, I've realised that this patch isn't completely sufficient
> > anyway; consider:
> >
> > // m.cpp
> > module;
> > template <typename T> struct S;
> > export module M;
> > S(int) -> S<double>;
> >
> > // x.cpp
> > template <typename T> struct S { S(int); };
> > import M;
> > int main() {
> > S s(10); // should be S<double> s;
> > }
> >
> > This patch doesn't correctly handle this case yet, we need to also
> > consider cases where only the deduction guide is in purview.
>
> Indeed.
>
> Jason
>