royjacobson added inline comments.

================
Comment at: clang/lib/Sema/SemaDecl.cpp:17899
+      ConstraintSatisfaction Satisfaction;
+      if (S.CheckFunctionConstraints(Method, Satisfaction))
+        SatisfactionStatus.push_back(false);
----------------
cor3ntin wrote:
> erichkeane wrote:
> > royjacobson wrote:
> > > erichkeane wrote:
> > > > royjacobson wrote:
> > > > > erichkeane wrote:
> > > > > > cor3ntin wrote:
> > > > > > > erichkeane wrote:
> > > > > > > > cor3ntin wrote:
> > > > > > > > > royjacobson wrote:
> > > > > > > > > > erichkeane wrote:
> > > > > > > > > > > This seems problematic, doesn't it?  Checking this 
> > > > > > > > > > > constraint will (once I figure out how to get deferred 
> > > > > > > > > > > instantiation to work) cause instantiation, which can 
> > > > > > > > > > > cause issues with incomplete types/CRTP/etc.
> > > > > > > > > > > 
> > > > > > > > > > > I think the result is that we cannot 'calculate' this 
> > > > > > > > > > > until it is queried, else we will cause incorrect errors.
> > > > > > > > > > Making this queried on demand is a relatively big change to 
> > > > > > > > > > how we handle type triviality, so I want to be sure we 
> > > > > > > > > > actually need to do this to be conformant.
> > > > > > > > > > 
> > > > > > > > > > When I started working on this I checked what GCC does and 
> > > > > > > > > > it instantiates those constraints during class completion 
> > > > > > > > > > as well. For example this CRTP case: 
> > > > > > > > > > https://godbolt.org/z/EdoYf96zq. MSVC seem to do it as well.
> > > > > > > > > > 
> > > > > > > > > > So maybe it's OK to check the constraints of SMFs 
> > > > > > > > > > specifically?
> > > > > > > > > > 
> > > > > > > > > I think this is done on completeness already in this patch, 
> > > > > > > > > unless i misunderstood the code.
> > > > > > > > > I don't think doing it on demand is a great direction, as 
> > > > > > > > > this does not only affect type traits but also code gen, etc. 
> > > > > > > > > It would create instanciations in unexpected places. wouldn't 
> > > > > > > > > it.
> > > > > > > > > Does the standard has wording suggesting it should be done 
> > > > > > > > > later than on type completeness?
> > > > > > > > The problem, at least for the deferred concepts, is that it 
> > > > > > > > breaks in the CRTP as required to implement ranges.  So 
> > > > > > > > something like this: https://godbolt.org/z/hPqrcqhx5 breaks.
> > > > > > > > 
> > > > > > > > I'm currently working to 'fix' that, so if this patch causes us 
> > > > > > > > to 'check' constraints early, it'll go back to breaking that 
> > > > > > > > example.  The example that Roy showed seems to show that it is 
> > > > > > > > actually checking 'delayed' right now (that is, on demand) in 
> > > > > > > > GCC/MSVC.  I don't know of the consequence/standardeeze that 
> > > > > > > > causes that though.
> > > > > > > Thanks, 
> > > > > > > Follow up stupid question then, do we care about the triviality 
> > > > > > > of dependant types?
> > > > > > > I think doing the check on complete non-dependant types might be 
> > > > > > > a better solution than trying to do it lazily on triviality 
> > > > > > > checks?
> > > > > > I would think it would be not a problem on non-dependent types.  
> > > > > > BUT concepts are only allowed on templated functions (note not only 
> > > > > > on function-templates!) anyway, so I don't think this would be a 
> > > > > > problem?  
> > > > > Erich, I'm a bit confused by your response. I think my example 
> > > > > demonstrates that for default constructors (and other SMFs) GCC and 
> > > > > MSVC instantiate the constraints on class completion and **not** on 
> > > > > demand. This is what I would like to do as well, if we don't have a 
> > > > > good reason not to. (For destructors, performing the checks is even 
> > > > > explicit in the standard.)
> > > > > 
> > > > > Not doing this can introduce some REALLY bad edge cases. What does 
> > > > > this do if we defer the triviality computation?
> > > > > 
> > > > > ```c++
> > > > > 
> > > > > template <class T>
> > > > > struct Base<T> {
> > > > >   Base() = default;
> > > > >   Base() requires (!std::is_trivial_v<T>);
> > > > > };
> > > > > 
> > > > > struct Child : Base<Child> { };
> > > > > ```
> > > > > We defer the computation of the constraints on `Base`, and complete 
> > > > > `Child` somehow, but if `Child` is complete then 
> > > > > `std::is_trivial_v<Child>` should be well-formed, right? But we get a 
> > > > > logical contradiction instead.
> > > > > 
> > > > > 
> > > > >Erich, I'm a bit confused by your response
> > > > It is entirely possible we're talking past eachother, or 
> > > > misunderstanding eachothers examples.  I'm totally open to that being 
> > > > part of this issue.
> > > > 
> > > > In that example, if we calculate the triviality at '`Base` Class 
> > > > completion', `Child` is not yet complete, right?  So the is_trivial_v 
> > > > would be UB.  If you instead require `sizeof(T)`, we typically give a 
> > > > diagnostic.
> > > > 
> > > > In this case, you'd at MINIMUM have to wait to calculate the 
> > > > requires-clause until after `Child` is complete.  And it isn't clear to 
> > > > me that we're delaying it until then.
> > > > 
> > > > That is what I intend to show with: https://godbolt.org/z/1YjsdY73P
> > > > 
> > > > As far as doing it 'on demand', I definitely see your circular argument 
> > > > here, but I think the is_trivial_v test is UB if we calculate it at 
> > > > `Base' completion.
> > > I'm arguing for checking the constraints at the completion of `Base`, and 
> > > for making `is_trivial_v/sizeof` ill formed in this context.
> > > 
> > > Your GCC example is a bit misleading, I think. They check the `sizeof(T) 
> > > > 0` constraint at the completion of `Base` but they just swallow the 
> > > error and declare the constraint unsatisfied or something. They should've 
> > > probably issued a diagnostic or something. But if you look at which 
> > > constructor they choose, they choose the unconstrained one: 
> > > https://godbolt.org/z/rKj4q5Yx9
> > Hmm.  I think based on that example, I agree with you.  We can do the 
> > instantiation and mark it unviable at the end of `Base`.  I think I'm 
> > getting confused by Clang's lack of deferred instantiation in this part.
> > 
> > Thanks for talking this through with me!
> > 
> > I AM concerned about how this will work with my deferred instantiations, so 
> > a test that validates that (and has a FIXME that shows it is broken right 
> > now) would be appreciated.
> > I'm arguing for checking the constraints at the completion of `Base`, and 
> > for making `is_trivial_v/sizeof` ill formed in this context.
> > 
> > Your GCC example is a bit misleading, I think. They check the `sizeof(T) > 
> > 0` constraint at the completion of `Base` but they just swallow the error 
> > and declare the constraint unsatisfied or something. They should've 
> > probably issued a diagnostic or something. But if you look at which 
> > constructor they choose, they choose the unconstrained one: 
> > https://godbolt.org/z/rKj4q5Yx9
> 
> I don't think gcc is wrong per 
> http://eel.is/c++draft/temp.constr.constr#temp.constr.op-5.sentence-3 
> The constrained overload is sfinea away silently, no diagnostic should be 
> emitted.
> It's no different from https://godbolt.org/z/ThMPrhs93 , for example 
> 
I added the test, could you take a look and tell me if that's what you meant or 
if you want some changes? @erichkeane 
I hope it isn't disruptive to the deferred patch itself, it's a bit concerning 
indeed but I'm moderately optimistic :)

@cor3ntin thanks for the explanation!



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D128619/new/

https://reviews.llvm.org/D128619

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to