aboutsummaryrefslogtreecommitdiff
path: root/test/SemaCXX/cxx1z-copy-omission.cpp
blob: e2b8fd7961740915db8bbb3ee52395962d022e66 (plain) (blame)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// RUN: %clang_cc1 -std=c++1z -verify %s

struct Noncopyable {
  Noncopyable();
  Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}}
  virtual ~Noncopyable();
};
struct Derived : Noncopyable {};
struct NoncopyableAggr {
  Noncopyable nc;
};
struct Indestructible {
  Indestructible();
  ~Indestructible() = delete; // expected-note 1+{{deleted}}
};
struct Incomplete; // expected-note 1+{{declar}}

Noncopyable make(int kind = 0) {
  switch (kind) {
  case 0: return {};
  case 1: return Noncopyable();
  case 2: return Noncopyable{};
  case 3: return make();
  }
  __builtin_unreachable();
}

Indestructible make_indestructible();
Incomplete make_incomplete(); // expected-note 1+{{here}}

void take(Noncopyable nc) {}

Noncopyable nrvo() {
  Noncopyable nrvo;
  return nrvo; // expected-error {{deleted constructor}}
}

Noncopyable nc1 = make();
Noncopyable nc2 = Noncopyable();
Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}

NoncopyableAggr nca1 = NoncopyableAggr{};
NoncopyableAggr nca2 = NoncopyableAggr{{}};
NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};

void test_expressions(bool b) {
  auto lambda = [a = make()] {};

  take({});
  take(Noncopyable());
  take(Noncopyable{});
  take(make());

  Noncopyable &&dc1 = dynamic_cast<Noncopyable&&>(Noncopyable());
  Noncopyable &&dc2 = dynamic_cast<Noncopyable&&>(nc1);
  Noncopyable &&dc3 = dynamic_cast<Noncopyable&&>(Derived());

  Noncopyable sc1 = static_cast<Noncopyable>(Noncopyable());
  Noncopyable sc2 = static_cast<Noncopyable>(nc1); // expected-error {{deleted}}
  Noncopyable sc3 = static_cast<Noncopyable&&>(Noncopyable()); // expected-error {{deleted}}
  Noncopyable sc4 = static_cast<Noncopyable>(static_cast<Noncopyable&&>(Noncopyable())); // expected-error {{deleted}}

  Noncopyable cc1 = (Noncopyable)Noncopyable();
  Noncopyable cc2 = (Noncopyable)Derived(); // expected-error {{deleted}}

  Noncopyable fc1 = Noncopyable(Noncopyable());
  Noncopyable fc2 = Noncopyable(Derived()); // expected-error {{deleted}}

  // We must check for a complete type for every materialized temporary. (Note
  // that in the special case of the top level of a decltype, no temporary is
  // materialized.)
  make_incomplete(); // expected-error {{incomplete}}
  make_incomplete().a; // expected-error {{incomplete}}
  make_incomplete().*(int Incomplete::*)nullptr; // expected-error {{incomplete}}
  dynamic_cast<Incomplete&&>(make_incomplete()); // expected-error {{incomplete}}
  const_cast<Incomplete&&>(make_incomplete()); // expected-error {{incomplete}}

  sizeof(Indestructible{}); // expected-error {{deleted}}
  sizeof(make_indestructible()); // expected-error {{deleted}}
  sizeof(make_incomplete()); // expected-error {{incomplete}}
  typeid(Indestructible{}); // expected-error {{deleted}}
  typeid(make_indestructible()); // expected-error {{deleted}}
  typeid(make_incomplete()); // expected-error {{incomplete}}

  // FIXME: The first two cases here are now also valid in C++17 onwards.
  using I = decltype(Indestructible()); // expected-error {{deleted}}
  using I = decltype(Indestructible{}); // expected-error {{deleted}}
  using I = decltype(make_indestructible());
  using J = decltype(make_incomplete());

  Noncopyable cond1 = b ? Noncopyable() : make();
  Noncopyable cond2 = b ? Noncopyable() : Derived(); // expected-error {{incompatible}}
  Noncopyable cond3 = b ? Derived() : Noncopyable(); // expected-error {{incompatible}}
  Noncopyable cond4 = b ? Noncopyable() : nc1; // expected-error {{deleted}}
  Noncopyable cond5 = b ? nc1 : Noncopyable(); // expected-error {{deleted}}
  // Could convert both to an xvalue of type Noncopyable here, but we're not
  // permitted to consider that.
  Noncopyable &&cond6 = b ? Noncopyable() : Derived(); // expected-error {{incompatible}}
  Noncopyable &&cond7 = b ? Derived() : Noncopyable(); // expected-error {{incompatible}}
  // Could convert both to a const lvalue of type Noncopyable here, but we're
  // not permitted to consider that, either.
  const Noncopyable cnc;
  const Noncopyable &cond8 = b ? cnc : Derived(); // expected-error {{incompatible}}
  const Noncopyable &cond9 = b ? Derived() : cnc; // expected-error {{incompatible}}

  extern const volatile Noncopyable make_cv();
  Noncopyable cv_difference1 = make_cv();
  const volatile Noncopyable cv_difference2 = make();
}

template<typename T> struct ConversionFunction { operator T(); };
Noncopyable cf1 = ConversionFunction<Noncopyable>();
Noncopyable cf2 = ConversionFunction<Noncopyable&&>(); // expected-error {{deleted}}
Noncopyable cf3 = ConversionFunction<const volatile Noncopyable>();
const volatile Noncopyable cf4 = ConversionFunction<Noncopyable>();
Noncopyable cf5 = ConversionFunction<Derived>(); // expected-error {{deleted}}

struct AsMember {
  Noncopyable member;
  AsMember() : member(make()) {}
};
// FIXME: DR (no number yet): we still get a copy for base or delegating construction.
struct AsBase : Noncopyable {
  AsBase() : Noncopyable(make()) {} // expected-error {{deleted}}
};
struct AsDelegating final {
  AsDelegating(const AsDelegating &) = delete; // expected-note {{deleted}}
  static AsDelegating make(int);

  // The base constructor version of this is problematic; the complete object
  // version would be OK. Perhaps we could allow copy omission here for final
  // classes?
  AsDelegating(int n) : AsDelegating(make(n)) {} // expected-error {{deleted}}
};