Bug 104111 - [DR2589] Concept evaluation depends on context where it was first checked
Summary: [DR2589] Concept evaluation depends on context where it was first checked
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: 11.4
Assignee: Patrick Palka
URL:
Keywords: accepts-invalid, rejects-valid, wrong-code
Depends on:
Blocks: concepts
  Show dependency treegraph
 
Reported: 2022-01-19 08:21 UTC by Fedor Chelnokov
Modified: 2022-11-06 21:52 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-01-19 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fedor Chelnokov 2022-01-19 08:21:36 UTC
Please consider a concept and a class definitions:
```
template<class T>
concept has_private = requires(){ &T::private_;};

class B{
   int private_;
   friend class A;
};
```

If we first check the concept inside `A` then it will be always evaluated to true:
```
class A{
   static_assert( has_private<B> );
};
static_assert( has_private<B> );
```
Demo: https://godbolt.org/z/eYP6Tq7Y7

But if we first check the concept outside `A` then it will be always evaluated to false:
```
static_assert( !has_private<B> );
class A{
   static_assert( !has_private<B> );
};

```
Demo: https://godbolt.org/z/vsTx4oTaE

Clang has the same behavior. At the same time MSVC always evaluates the concept to false, and it looks correct, because context evaluation shall not depend on the context.

Related discussion: https://godbolt.org/z/vsTx4oTaE
Comment 1 Fedor Chelnokov 2022-01-19 08:22:26 UTC
Sorry, related discussion: https://stackoverflow.com/q/53263299/7325599
Comment 2 Andrew Pinski 2022-01-19 08:42:39 UTC
Confirmed.
Comment 3 Patrick Palka 2022-01-21 14:27:33 UTC
> because concept-id evaluation shall not depend on the context.

One consequence of making this change to concept-id evaluation would be that for:

  template<class T> void f() requires (!C<T>);

during constraint checking for say f<int>(), we no longer evaluate C<int> (as part of evaluation of the atomic constraint !C<T>) in the access context of f, which seems surprising to me.

CC'ing Jason for guidance.
Comment 4 Richard Biener 2022-04-21 07:51:07 UTC
GCC 11.3 is being released, retargeting bugs to GCC 11.4.
Comment 5 Jason Merrill 2022-05-27 17:58:21 UTC
(In reply to Patrick Palka from comment #3)
> > because concept-id evaluation shall not depend on the context.
> 
> One consequence of making this change to concept-id evaluation would be that
> for:
> 
>   template<class T> void f() requires (!C<T>);
> 
> during constraint checking for say f<int>(), we no longer evaluate C<int>
> (as part of evaluation of the atomic constraint !C<T>) in the access context
> of f, which seems surprising to me.
> 
> CC'ing Jason for guidance.

This issue was discussed on the CWG mailing list back in 2018, but seems never to have made it to the issues list.  There was general agreement at the time that access should be checked in the lexical context of the atomic constraint, as with other expressions; this does indeed have the consequence that you mention.  Which means that since we don't have class-scope concepts, any constraints that need to depend on access control need to be written directly in the requires-clause rather than through a concept.  Or just give up on trying to express constraints that depend on access.

An alternative fix for this bug would be to include the evaluation context in the satisfaction cache.
Comment 6 Jason Merrill 2022-05-27 22:02:29 UTC
(In reply to Jason Merrill from comment #5)
> An alternative fix for this bug would be to include the evaluation context
> in the satisfaction cache.

...if the evaluation involved access checking of a private or protected member.
Comment 7 Jason Merrill 2022-05-31 19:29:46 UTC
https://cplusplus.github.io/CWG/issues/2589.html