alexander-shaposhnikov planned changes to this revision. alexander-shaposhnikov added inline comments.
================ Comment at: clang/lib/Sema/SemaConcept.cpp:773 + // ConstrExpr for the inner template will properly adjust the depths. + if (isa<CXXRecordDecl>(ND) && isa<CXXRecordDecl>(OtherND)) + ForConstraintInstantiation = true; ---------------- erichkeane wrote: > erichkeane wrote: > > erichkeane wrote: > > > alexander-shaposhnikov wrote: > > > > erichkeane wrote: > > > > > alexander-shaposhnikov wrote: > > > > > > erichkeane wrote: > > > > > > > alexander-shaposhnikov wrote: > > > > > > > > erichkeane wrote: > > > > > > > > > Hmm... this seems really strange to have to do. > > > > > > > > > `ForConstraintInstantiation` shouldn't be used here, the > > > > > > > > > point of that is to make sure we 'keep looking upward' once > > > > > > > > > we hit a spot we normally stop with. What exactly is the > > > > > > > > > issue that you end up running into here? Perhaps I can spend > > > > > > > > > some time debugging what we should really be doign. > > > > > > > > yeah, I agree. I haven't found a proper solution or at least a > > > > > > > > better workaround (but would be happy to). > > > > > > > > This kicks in for the case > > > > > > > > > > > > > > > > ``` > > > > > > > > template <class T0> > > > > > > > > concept Constraint = true; > > > > > > > > > > > > > > > > > > > > > > > > template<Constraint T1> > > > > > > > > struct Iterator { > > > > > > > > template <Constraint T2> > > > > > > > > friend class Iterator; > > > > > > > > void operator*(); > > > > > > > > }; > > > > > > > > > > > > > > > > Iterator<char*> I2; > > > > > > > > ``` > > > > > > > > yeah, I agree. I haven't found a proper solution or at least a > > > > > > > > better workaround (but would be happy to). > > > > > > > > This kicks in for the case > > > > > > > > > > > > > > > > ``` > > > > > > > > template <class T0> > > > > > > > > concept Constraint = true; > > > > > > > > > > > > > > > > > > > > > > > > template<Constraint T1> > > > > > > > > struct Iterator { > > > > > > > > template <Constraint T2> > > > > > > > > friend class Iterator; > > > > > > > > void operator*(); > > > > > > > > }; > > > > > > > > > > > > > > > > Iterator<char*> I2; > > > > > > > > ``` > > > > > > > > > > > > > > Alright, well, I should have time later in the week to poke at > > > > > > > this, perhaps I can come up with something better? I DO remember > > > > > > > self-friend is a little wacky, and I spent a bunch of time on it > > > > > > > last time. > > > > > > Ok, sounds good + maybe Richard will give it another look. > > > > > So IMO, `ForConstraintInstantiation` should be 'true' always, and > > > > > that makes those examples pass. However, I'm now seeing that it > > > > > causes a failure in the concepts-out-of-line-def.cpp file. > > > > > > > > > > I took the example of `foo3`: > > > > > > > > > > ``` > > > > > template<typename T0> concept C = true; > > > > > template <typename T1> > > > > > struct S { > > > > > template <typename F3> requires C<F3> > > > > > void foo3(F3 f); // #1 > > > > > }; > > > > > template <typename T4> > > > > > template <typename F6> requires C<F6> > > > > > void S<T4>::foo3(F6 f) {} // #3 > > > > > ``` > > > > > > > > > > Which, seems to require `ForConstraintInstantiation` to be false to > > > > > pass. However, I don't think this is correct. This is only working > > > > > because when evaluating the in-line one (#1 above!) its skipping the > > > > > application of `T1`, which is wrong. > > > > > > > > > > However, I think the problem here is that the `out of line` version > > > > > (#3) is not applying the T4 like it should be. SO, I think the > > > > > `HandleFunctionTemplateDecl` I provided you earlier needs > > > > > modification. > > > > > > > > > > FIRST, though not related to this, I think we might need to add > > > > > `FunctionTemplateDecl::getInjectedTemplateArgs` to the `Result`, but > > > > > only because that 'sounds right' to me? IDK what other problem that > > > > > would cause, but it is worth evaluating/saving for later. It might > > > > > just not matter, since we're treating them as equal at the moment, I > > > > > don't think injecting them would cause anything. > > > > > > > > > > Secondly: I see that the we can get to the `T4` via the > > > > > `FTD->getTemplatedDecl()->getQualifier()->getAsType()->getAs<TemplateSpecializationType>()->template_arguments()`. > > > > > > > > > > > > > > > HOWEVER, the problem that comes with picking THOSE up, is that it > > > > > ALSO applies with a `FunctionTemplateDecl` inside of an out-of-line > > > > > `ClassTemplateSpecializationDecl` (which doesn't NEED the > > > > > specialization's template args). > > > > > > > > > > SO I think the fix here is something in `HandleFunctionTemplateDecl` > > > > > to make sure we pick up the right list of template arguments. I > > > > > haven't figured out the magic incantation to make it work > > > > > unfortunately, perhaps @rsmith has some hints? Else I'll keep poking > > > > > at it. > > > > > > > > > > BUT, my debugging has shown me that I'm quite convinced the setting > > > > > `ForConstraintInstantiation ` to false is incorrect. > > > > p.s. Richard is on vacation. > > > > > > > > to quote his comment above (where the story began): > > > > > > > > >The right way to fix that and the issue being addressed here is that, > > > > >rather than adjusting the depths, we ?>should substitute the outer > > > > >template arguments from the scope specifier (A<int>::) into the > > > > >constraint before >performing the comparison. (In the special case > > > > >where none of the outer template parameters are used by the >inner > > > > >template, that does effectively just adjust the depths of any inner > > > > >template parameters.) > > > > > > > > A. the formal meaning of ForConstraintInstantiation=true/false is > > > > unclear, @eirchkean - if you happen to understand it - mind expanding > > > > the comment a bit ? (and we can add this to the documentation) > > > > > > > > B. <related to A> T1 - maybe it should be collected as a retained layer > > > > ? > > > > > > > I also notice that the work in `HandleRecordDecl` inside of the > > > `ForConstraintInstantiation` is a little odd, I don't recall why I put > > > that in place, but it DOES result in 5 failed tests if I remove it. > > > Perhaps we just need to be more careful when we substitute in these > > > arguments? It seems to me that putting those arguments in place is > > > perhaps not the right thing to do, since they don't have any meaningful > > > values yet? Perhaps something else for us to poke at. > > Ah, didn't know he was away :) > > > > My understanding is that is what you're doing (the quote). By collecting > > the instantiation args correctly, that is what should be happening here. > > > > A: > > The `ForConstraintInstantiation`s intent is to make it so we collect > > arguments 'all the way up' rather than stopping at some points where normal > > instantiation would. The idea is that a Constraint is never stored in the > > AST as substituted, so the depth is always relative to the TU. Other > > situations where we collect arguments is relative to the 'last thing that > > has been instantiated'. So thats the difference (is where we are > > substituting 'relative' to). > > > > B: At this point, we COULD and probably SHOULD collect T1 as a retained > > outer layer, but that would still cause a problem with that example. I > > think the issue here is that we're not ALSO collecting `T4`. > To answer this question: > > ``` > namespace DelayedInst { > template<unsigned I> > struct AAA { > template<typename T> > requires (sizeof(T) == I) > struct B { > static_constexpr int a = 0; > }; > > static constexpr auto foo() { > return B<int>::a; > } > }; > ``` > Ends up instantiating `B<int>` to get `a` despite `I` not being filled in > yet, but we still try instantiation into the requires clause for various > syntactic checking. So we need something to take up the space of the `I`. > We cant just do the retained layer, since `AAA` might be inside of ANOTHER > class template (perhaps a specialization?), so we'd need that one as well. > > So that code goes to try to introduce the `I`. So I think this solution ends > up coming down to 'how do we get `T4` into `foo3`'s MLTAL. Regarding ForConstraintInstantiation=true - I agree, i think i got confused by a particular example i was looking at. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D146178/new/ https://reviews.llvm.org/D146178 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits