public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/97059] New: C++20: compound requirement uses inconsistent return type (adds ref)
@ 2020-09-15 21:15 dimitri.gorokhovik at free dot fr
  2020-09-24 20:13 ` [Bug c++/97059] " dimitri.gorokhovik at free dot fr
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: dimitri.gorokhovik at free dot fr @ 2020-09-15 21:15 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97059

            Bug ID: 97059
           Summary: C++20: compound requirement uses inconsistent return
                    type (adds ref)
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dimitri.gorokhovik at free dot fr
  Target Milestone: ---

The following code:

#include <concepts>

template <std::size_t N>
struct s { constexpr static auto const n = N; };

template <typename T>
concept S = requires (T t)
{
  { t.n } -> std::same_as <const std::size_t
#if NOBUG
&
#endif
>;
  requires std::is_same_v <decltype (t.n), const std::size_t>;
};

decltype (auto) f (S s) { return s.n; };

static_assert (std::is_same_v <decltype (f (s <1> {})), std::size_t>);
static_assert (S <s <1>>);

when compiled as:
g++  -std=c++20 -fconcepts-ts -fconcepts-diagnostics-depth=25 -Wall -Wextra -W
-O3  -o bug-4.o -c  bug-4.cpp

breaks (messages below).

Compilation succeeds when NOBUG is defined, i.e., the compound requirement '{
t.n } ->' produces the return type as 'const std::size_t &' instead of 'const
std::size_t'. Which is inconsistent elsewhere (see the source code above).

Version: g++ (GCC) 11.0.0 20200910 (experimental)

Diagnostic messages:
bug-4.cpp:15:53: error: no matching function for call to ‘f(s<1>)’
   15 | static_assert (std::is_same_v <decltype (f (s <1> {})), std::size_t>);
      |                                                     ^
bug-4.cpp:13:17: note: candidate: ‘template<class auto:1>  requires  S<auto:1>
decltype(auto) f(auto:1)’
   13 | decltype (auto) f (S v) { return v.n; };
      |                 ^
bug-4.cpp:13:17: note:   template argument deduction/substitution failed:
bug-4.cpp:13:17: note: constraints not satisfied
bug-4.cpp: In substitution of ‘template<class auto:1>  requires  S<auto:1>
decltype(auto) f(auto:1) [with auto:1 = s<1>]’:
bug-4.cpp:15:53:   required from here
bug-4.cpp:7:9:   required for the satisfaction of ‘S<auto:1>’ [with auto:1 =
s<1>]
bug-4.cpp:7:13:   in requirements with ‘T t’ [with T = s<1>]
bug-4.cpp:9:5: note: ‘t.n’ does not satisfy return-type-requirement, because
    9 |   { t.n } -> std::same_as <const std::size_t>;
      |   ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bug-4.cpp:9:5: error: deduced expression type does not satisfy placeholder
constraints
bug-4.cpp:9:5: note: constraints not satisfied
In file included from bug-4.cpp:1:
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:15:  
required for the satisfaction of ‘__same_as<_Tp, _Up>’ [with _Tp = const long
unsigned int&; _Up = const long unsigned int]
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:62:13:  
required for the satisfaction of ‘same_as<const long unsigned int&, const long
unsigned int>’
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:32: note:
the expression ‘is_same_v<_Tp, _Up> [with _Tp = const long unsigned int&; _Up =
const long unsigned int]’ evaluated to ‘false’
   57 |       concept __same_as = std::is_same_v<_Tp, _Up>;
      |                           ~~~~~^~~~~~~~~~~~~~~~~~~
bug-4.cpp:15:53: error: no matching function for call to ‘f(s<1>)’
   15 | static_assert (std::is_same_v <decltype (f (s <1> {})), std::size_t>);
      |                                                     ^
bug-4.cpp:13:17: note: candidate: ‘template<class auto:1>  requires  S<auto:1>
decltype(auto) f(auto:1)’
   13 | decltype (auto) f (S v) { return v.n; };
      |                 ^
bug-4.cpp:13:17: note:   template argument deduction/substitution failed:
bug-4.cpp:13:17: note: constraints not satisfied
bug-4.cpp: In substitution of ‘template<class auto:1>  requires  S<auto:1>
decltype(auto) f(auto:1) [with auto:1 = s<1>]’:
bug-4.cpp:15:53:   required from here
bug-4.cpp:7:9:   required for the satisfaction of ‘S<auto:1>’ [with auto:1 =
s<1>]
bug-4.cpp:7:13:   in requirements with ‘T t’ [with T = s<1>]
bug-4.cpp:9:5: note: ‘t.n’ does not satisfy return-type-requirement, because
    9 |   { t.n } -> std::same_as <const std::size_t>;
      |   ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bug-4.cpp:9:5: error: deduced expression type does not satisfy placeholder
constraints
bug-4.cpp:9:5: note: constraints not satisfied
In file included from bug-4.cpp:1:
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:15:  
required for the satisfaction of ‘__same_as<_Tp, _Up>’ [with _Tp = const long
unsigned int&; _Up = const long unsigned int]
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:62:13:  
required for the satisfaction of ‘same_as<const long unsigned int&, const long
unsigned int>’
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:32: note:
the expression ‘is_same_v<_Tp, _Up> [with _Tp = const long unsigned int&; _Up =
const long unsigned int]’ evaluated to ‘false’
   57 |       concept __same_as = std::is_same_v<_Tp, _Up>;
      |                           ~~~~~^~~~~~~~~~~~~~~~~~~
bug-4.cpp:15:21: error: template argument 1 is invalid
   15 | static_assert (std::is_same_v <decltype (f (s <1> {})), std::size_t>);
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bug-4.cpp:16:16: error: static assertion failed
   16 | static_assert (S <s <1>>);
      |                ^~~~~~~~~
bug-4.cpp:16:16: note: constraints not satisfied
bug-4.cpp:7:9:   required by the constraints of ‘template<class T> concept S’
bug-4.cpp:7:13:   in requirements with ‘T t’ [with T = s<1>]
bug-4.cpp:9:5: note: ‘t.n’ does not satisfy return-type-requirement, because
    9 |   { t.n } -> std::same_as <const std::size_t>;
      |   ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bug-4.cpp:9:5: error: deduced expression type does not satisfy placeholder
constraints
bug-4.cpp:9:5: note: constraints not satisfied
In file included from bug-4.cpp:1:
/home/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:15:   required for
the satisfaction of ‘__same_as<_Tp, _Up>’ [with _Tp = const long unsigned int&;
_Up = const long unsigned int]
/home/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:62:13:   required for
the satisfaction of ‘same_as<const long unsigned int&, const long unsigned
int>’
/home/dgorokho/gcc-trunk/trunk/dist/include/c++/11.0.0/concepts:57:32: note:
the expression ‘is_same_v<_Tp, _Up> [with _Tp = const long unsigned int&; _Up =
const long unsigned int]’ evaluated to ‘false’
   57 |       concept __same_as = std::is_same_v<_Tp, _Up>;
      |                           ~~~~~^~~~~~~~~~~~~~~~~~~

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/97059] C++20: compound requirement uses inconsistent return type (adds ref)
  2020-09-15 21:15 [Bug c++/97059] New: C++20: compound requirement uses inconsistent return type (adds ref) dimitri.gorokhovik at free dot fr
@ 2020-09-24 20:13 ` dimitri.gorokhovik at free dot fr
  2020-09-24 20:20 ` dimitri.gorokhovik at free dot fr
  2020-12-03 18:51 ` jason at gcc dot gnu.org
  2 siblings, 0 replies; 4+ messages in thread
From: dimitri.gorokhovik at free dot fr @ 2020-09-24 20:13 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97059

--- Comment #1 from Dimitri Gorokhovik <dimitri.gorokhovik at free dot fr> ---
I was able to reduce same code (attached file bug-6.cpp).

-- when compiled correctly, running it produces the following (expected)
output:

cube: ({ 0, 0, 0 }, { 1, 1, 1 }) 
cube: ({ 0, 0, 1 }, { 1, 1, 2 }) 
cube: ({ 0, 0, 2 }, { 1, 1, 3 }) 
cube: ({ 0, 1, 0 }, { 1, 2, 1 }) 
cube: ({ 0, 1, 1 }, { 1, 2, 2 }) 
cube: ({ 0, 1, 2 }, { 1, 2, 3 }) 
cube: ({ 0, 2, 0 }, { 1, 3, 1 }) 
cube: ({ 0, 2, 1 }, { 1, 3, 2 }) 
cube: ({ 0, 2, 2 }, { 1, 3, 3 }) 
cube: ({ 1, 0, 0 }, { 2, 1, 1 }) 
cube: ({ 1, 0, 1 }, { 2, 1, 2 }) 
cube: ({ 1, 0, 2 }, { 2, 1, 3 }) 
cube: ({ 1, 1, 0 }, { 2, 2, 1 }) 
cube: ({ 1, 1, 1 }, { 2, 2, 2 }) 
cube: ({ 1, 1, 2 }, { 2, 2, 3 }) 
cube: ({ 1, 2, 0 }, { 2, 3, 1 }) 
cube: ({ 1, 2, 1 }, { 2, 3, 2 }) 
cube: ({ 1, 2, 2 }, { 2, 3, 3 }) 
cube: ({ 2, 0, 0 }, { 3, 1, 1 }) 
cube: ({ 2, 0, 1 }, { 3, 1, 2 }) 
cube: ({ 2, 0, 2 }, { 3, 1, 3 }) 
cube: ({ 2, 1, 0 }, { 3, 2, 1 }) 
cube: ({ 2, 1, 1 }, { 3, 2, 2 }) 
cube: ({ 2, 1, 2 }, { 3, 2, 3 }) 
cube: ({ 2, 2, 0 }, { 3, 3, 1 }) 
cube: ({ 2, 2, 1 }, { 3, 3, 2 }) 
cube: ({ 2, 2, 2 }, { 3, 3, 3 }) 
count = 27

-- when compiled incorrectly, it prints out:

count = 0

Tested with build g++ (GCC) 11.0.0 20200924 (experimental).


In order to compile and run:

g++ -std=c++17 -O3 -o bug-6 bug-6.cpp && ./bug-6

This builds for implicit '-m64' (x86_64) and produces invalid output. 

To get valid output, compile with either of the following:
-m32
-O0 (instead of -O3)
-fno-tree-sra
one of -DFIX_0 to -DFIX_4 


>From my limited understanding of tree dumps, here is what roughly happens:

-- the routine 'begin()', line 183, returns 'struct iterator' by value. The
latter has the size of 14 bytes so returned "in registers". Forcing it to be
returned via memory ==> issue goes away. (Methods to force: make bigger than 16
bytes, make volatile, use -m32). Note also that, when the routine is evaluated
as constexpr (in static_assert), the issue is not reproduced.

-- all called routines are inlined inside one call, to 'count_them'. Prevent
the inlining of the routine 'can_be_incremented ()' ==>  issue goes away.
(Methods to prevent: define FIX_1.)

-- SRA replaces several fields of the 'struct iterator' (line 150), notably,
'idx_' (line 153). Disable SRA ==> issue goes away (-fno-tree-sra or use -O0). 

This replacement by tree-SRA somehow doesn't propagate the writes to idx_, from
the replacement vars to the original part of the structure which lives "in the
return registers".  When the return value lives in memory, the writes are
propagated correctly.

The compiler then eliminates the loop in 'can_be_incremented' and evaluates the
call to that routine by 'false' (line 163). Forcibly keeping the loop (-DFIX_2)
or replacing it by non-loop code (-DFIX_0) ==> issue goes away.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/97059] C++20: compound requirement uses inconsistent return type (adds ref)
  2020-09-15 21:15 [Bug c++/97059] New: C++20: compound requirement uses inconsistent return type (adds ref) dimitri.gorokhovik at free dot fr
  2020-09-24 20:13 ` [Bug c++/97059] " dimitri.gorokhovik at free dot fr
@ 2020-09-24 20:20 ` dimitri.gorokhovik at free dot fr
  2020-12-03 18:51 ` jason at gcc dot gnu.org
  2 siblings, 0 replies; 4+ messages in thread
From: dimitri.gorokhovik at free dot fr @ 2020-09-24 20:20 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97059

--- Comment #2 from Dimitri Gorokhovik <dimitri.gorokhovik at free dot fr> ---
(In reply to Dimitri Gorokhovik from comment #1)
> I was able to reduce same code (attached file bug-6.cpp).

Please disregard the comment #1 -- posted to wrong bug.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Bug c++/97059] C++20: compound requirement uses inconsistent return type (adds ref)
  2020-09-15 21:15 [Bug c++/97059] New: C++20: compound requirement uses inconsistent return type (adds ref) dimitri.gorokhovik at free dot fr
  2020-09-24 20:13 ` [Bug c++/97059] " dimitri.gorokhovik at free dot fr
  2020-09-24 20:20 ` dimitri.gorokhovik at free dot fr
@ 2020-12-03 18:51 ` jason at gcc dot gnu.org
  2 siblings, 0 replies; 4+ messages in thread
From: jason at gcc dot gnu.org @ 2020-12-03 18:51 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97059

Jason Merrill <jason at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org
         Resolution|---                         |INVALID
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #3 from Jason Merrill <jason at gcc dot gnu.org> ---
(In reply to Dimitri Gorokhovik from comment #0)
> template <typename T>
> concept S = requires (T t)
> {
>   { t.n } -> std::same_as <const std::size_t
> #if NOBUG
> &
> #endif
> >;
>   requires std::is_same_v <decltype (t.n), const std::size_t>;
> };
> 
> Compilation succeeds when NOBUG is defined, i.e., the compound requirement
> '{ t.n } ->' produces the return type as 'const std::size_t &' instead of
> 'const std::size_t'. Which is inconsistent elsewhere (see the source code
> above).

For the second 'requires' to be equivalent to the return-type-requirement, you
need another set of parentheses around "t.n".

7.5.7.3: "The immediately-declared constraint (13.2) of the type-constraint for
decltype((E)) shall be satisfied."

It's the extra parentheses that result in the reference type rather than
non-reference.  GCC is correct here.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-12-03 18:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-15 21:15 [Bug c++/97059] New: C++20: compound requirement uses inconsistent return type (adds ref) dimitri.gorokhovik at free dot fr
2020-09-24 20:13 ` [Bug c++/97059] " dimitri.gorokhovik at free dot fr
2020-09-24 20:20 ` dimitri.gorokhovik at free dot fr
2020-12-03 18:51 ` jason at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).