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
> 

Reply via email to