aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.dg/cpp23/elision1.C
blob: f44fd2a061cb82648d54498e6b6c3e5c59edda91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// PR c++/101165 - P2266R1 - Simpler implicit move
// { dg-do compile { target c++23 } }
// Tests from P2266R1.

namespace std {
  template<typename _Tp>
    struct remove_reference
    { typedef _Tp   type; };

  template<typename _Tp>
    struct remove_reference<_Tp&>
    { typedef _Tp   type; };

  template<typename _Tp>
    struct remove_reference<_Tp&&>
    { typedef _Tp   type; };

  template<typename _Tp>
    constexpr typename std::remove_reference<_Tp>::type&&
    move(_Tp&& __t) noexcept
    { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
}

template<typename T, typename U>
struct same_type { static const bool value = false; };

template<typename T>
struct same_type<T, T> { static const bool value = true; };

struct Widget {
    Widget(Widget&&);
};

struct RRefTaker {
    RRefTaker(Widget&&);
};

struct Mutt {
    operator int*() &&;
};

struct Jeff {
    operator int&() &&;
};

struct Ella {
    operator int() &&;
};

Widget one(Widget w) {
    return w;  // OK since C++11
}

RRefTaker two(Widget w) {
    return w;  // OK since C++11 + CWG1579
}

RRefTaker three(Widget&& w) {
    return w;  // OK since C++20 because P0527
}

// Tests that implicit move applies even to functions that return references.
Widget&& four(Widget&& w) {
    return w;  // OK since C++23
}

// ... or pointers.
int* five(Mutt x) {
    return x;  // OK since C++20 because P1155
}

int& six(Jeff x) {
    return x;
}

int test_ella(Ella e) {
  return e;
}

template<class T>
T&& seven(T&& x) { return x; }

void test_seven(Widget w) {
    Widget& r = seven(w);
    Widget&& rr = seven(std::move(w));
}

Widget val();
Widget& lref();
Widget&& rref();

decltype(auto) eight() {
    decltype(auto) x = val();  // OK, x is Widget
    return x;  // OK, return type is Widget, we get copy elision
}

decltype(auto) nine() {
    decltype(auto) x = lref();  // OK, x is Widget&
    return x;  // OK, return type is Widget&
}

decltype(auto) ten() {
  decltype(auto) x = rref();  // OK, x is Widget&&
  // This was an error: return type is Widget&&, cannot bind to x.
  // But in C++23, x is treated as an rvalue.
  return x;
}

// Now returns Widget&&, not Widget&.
// This is from $ 3.2.1. Interaction with decltype and decltype(auto).
decltype(auto) eleven(Widget&& x) {
    return (x);
}
static_assert(same_type<decltype(eleven), Widget&& (Widget&&)>::value);