Bug 77875 (cwg1288) - C++ core issue 1288
Summary: C++ core issue 1288
Status: NEW
Alias: cwg1288
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: rejects-valid
: 89857 100039 (view as bug list)
Depends on:
Blocks: c++-core-issues
  Show dependency treegraph
Reported: 2016-10-05 19:13 UTC by Aleksey Covacevice
Modified: 2021-12-14 05:26 UTC (History)
3 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-01 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Aleksey Covacevice 2016-10-05 19:13:03 UTC
GCC does not fully implement the resolution for core issue 1288 (http://wg21.link/cwg1288).

    int i; (int&){i};

GCC yields "invalid cast of an rvalue expression of type 'int' to type 'int&'".

More info and discussion:
Comment 1 Jonathan Wakely 2019-03-27 18:36:19 UTC
*** Bug 89857 has been marked as a duplicate of this bug. ***
Comment 2 Jonathan Wakely 2019-03-27 18:36:56 UTC
From PR 89857:

gcc doesn't compile the following well-formed program:

void foo () {
    using T = int&;
    int i{};

$ g++ -std=c++17 -c gcc_bug2.cpp 
gcc_bug2.cpp: In function ‘void foo()’:
gcc_bug2.cpp:4:8: error: invalid cast of an rvalue expression of type ‘int’ to type ‘T’ {aka ‘int&’}

Quoting from the standard draft:


Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.

According to the error, it looks like gcc skips this and tries to apply the next rule:

Otherwise, if T is a reference type, a prvalue of the type referenced by T is generated.
The prvalue initializes its result object by copy-list-initialization.
The prvalue is then used to direct-initialize the reference.
[ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type.
— end note ]

Note: The current behavior was originally a defect in the C++11 standard that was corrected in CWG1288.
Comment 3 Lénárd Szolnoki 2019-03-28 08:25:09 UTC
A more worrisome example presumably for this same bug, it's a miscompilation:

template <typename T>
decltype(auto) as_const(T& t) {
    using const_ref = const T&;
    return const_ref{t};

int main() {
    int i = 42;
    return as_const(i);

$ g++ -std=c++17 -O0 -fsanitize=undefined -Wall -pedantic main.cpp && ./a.out
main.cpp: In instantiation of 'decltype(auto) as_const(T&) [with T = int]':
main.cpp:9:22:   required from here
main.cpp:4:23: warning: returning reference to temporary [-Wreturn-local-addr]
     return const_ref{t};
main.cpp:4:23: runtime error: reference binding to null pointer of type 'const int'
main.cpp:9:22: runtime error: load of null pointer of type 'const int'
bash: line 7:   802 Segmentation fault      (core dumped) ./a.out

An UB is added where should be none.
Comment 4 Marek Polacek 2019-03-28 16:13:26 UTC
Doesn't this depend on the resolution of Core 1521 (still "drafting"), dealing with T{expr} where T is a reference type?  Which is what this PR is about:

f ()
  int i = 42;
  using T = int&;
  T t = T{i};
Comment 5 Jonathan Wakely 2019-03-28 16:24:40 UTC
Yes, probably, but it doesn't seem useful for T{i} to do anything except bind a reference of type T to i. Issue 1521 seems to be a problem with the wording, such that it doesn't apply to references, but I doubt it will be resolved by saying that T{i} does anything surprising. But maybe I'm missing something.
Comment 6 Andrew Pinski 2021-12-14 05:26:09 UTC
*** Bug 100039 has been marked as a duplicate of this bug. ***