reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
// RUN: rm -f %t.14 %t.2a
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++14 -DCXX2A=0 -fblocks -Wall -Wno-unused -Werror %s > %t.14 2>&1
// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++2a -DCXX2A=1 -fblocks -Wall -Wno-unused -Werror %s > %t.2a 2>&1
// RUN: FileCheck --input-file=%t.14 -check-prefixes=CHECK,CXX14 -implicit-check-not=destructor %s
// RUN: FileCheck --input-file=%t.2a -check-prefixes=CHECK,CXX2A -implicit-check-not=destructor %s

int puts(const char *);

struct Foo {
  Foo() = delete;
#if CXX2A
  // Guarantee that the elided examples are actually elided by deleting the
  // copy constructor.
  Foo(const Foo &) = delete;
#else
  // No elision support, so we need a copy constructor.
  Foo(const Foo &);
#endif
  ~Foo();
};

struct TwoFoos {
  Foo foo1, foo2;
  ~TwoFoos();
};

Foo get_foo();

struct Bar {
  Bar();
  Bar(const Bar &);
  ~Bar();
  Bar &operator=(const Bar &);
};

Bar get_bar();

struct TwoBars {
  Bar foo1, foo2;
  ~TwoBars();
};

// Start of tests:

void elided_assign() {
  Foo x = get_foo();
}
// CHECK: void elided_assign()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Implicit destructor)

void nonelided_assign() {
  Bar x = (const Bar &)get_bar();
}
// CHECK: void nonelided_assign()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~Bar() (Implicit destructor)

void elided_paren_init() {
  Foo x(get_foo());
}
// CHECK: void elided_paren_init()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Implicit destructor)

void nonelided_paren_init() {
  Bar x((const Bar &)get_bar());
}
// CHECK: void nonelided_paren_init()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~Bar() (Implicit destructor)

void elided_brace_init() {
  Foo x{get_foo()};
}
// CHECK: void elided_brace_init()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Implicit destructor)

void nonelided_brace_init() {
  Bar x{(const Bar &)get_bar()};
}
// CHECK: void nonelided_brace_init()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~Bar() (Implicit destructor)

void elided_lambda_capture_init() {
  // The copy from get_foo() into the lambda should be elided.  Should call
  // the lambda's destructor, but not ~Foo() separately.
  // (This syntax is C++14 'generalized lambda captures'.)
  auto z = [x=get_foo()]() {};
}
// CHECK: void elided_lambda_capture_init()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~(lambda at {{.*}})() (Implicit destructor)

void nonelided_lambda_capture_init() {
  // Should call the lambda's destructor as well as ~Bar() for the temporary.
  auto z = [x((const Bar &)get_bar())]() {};
}
// CHECK: void nonelided_lambda_capture_init()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~(lambda at {{.*}})() (Implicit destructor)

Foo elided_return_stmt_expr() {
  // Two copies, both elided in C++17.
  return ({ get_foo(); });
}
// CHECK: Foo elided_return_stmt_expr()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)

void elided_stmt_expr() {
  // One copy, elided in C++17.
  ({ get_foo(); });
}
// CHECK: void elided_stmt_expr()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Temporary object destructor)


void elided_stmt_expr_multiple_stmts() {
  // Make sure that only the value returned out of a statement expression is
  // elided.
  ({ get_bar(); get_foo(); });
}
// CHECK: void elided_stmt_expr_multiple_stmts()
// CHECK: ~Bar() (Temporary object destructor)
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Temporary object destructor)


void unelided_stmt_expr() {
  ({ (const Bar &)get_bar(); });
}
// CHECK: void unelided_stmt_expr()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~Bar() (Temporary object destructor)

void elided_aggregate_init() {
  TwoFoos x{get_foo(), get_foo()};
}
// CHECK: void elided_aggregate_init()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~TwoFoos() (Implicit destructor)

void nonelided_aggregate_init() {
  TwoBars x{(const Bar &)get_bar(), (const Bar &)get_bar()};
}
// CHECK: void nonelided_aggregate_init()
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: (CXXConstructExpr{{.*}}, struct Bar)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~Bar() (Temporary object destructor)
// CHECK: ~TwoBars() (Implicit destructor)

TwoFoos return_aggregate_init() {
  return TwoFoos{get_foo(), get_foo()};
}
// CHECK: TwoFoos return_aggregate_init()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~TwoFoos() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)

void lifetime_extended() {
  const Foo &x = (get_foo(), get_foo());
  puts("one destroyed before, one destroyed after");
}
// CHECK: void lifetime_extended()
// CHECK: ~Foo() (Temporary object destructor)
// CHECK: one destroyed before, one destroyed after
// CHECK: ~Foo() (Implicit destructor)

void not_lifetime_extended() {
  Foo x = (get_foo(), get_foo());
  puts("one destroyed before, one destroyed after");
}
// CHECK: void not_lifetime_extended()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CHECK: ~Foo() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: one destroyed before, one destroyed after
// CHECK: ~Foo() (Implicit destructor)

void compound_literal() {
  (void)(Bar[]){{}, {}};
}
// CHECK: void compound_literal()
// CHECK: (CXXConstructExpr, struct Bar)
// CHECK: (CXXConstructExpr, struct Bar)
// CHECK: ~Bar [2]() (Temporary object destructor)

Foo elided_return() {
  return get_foo();
}
// CHECK: Foo elided_return()
// CXX14: (CXXConstructExpr{{.*}}, struct Foo)
// CXX14: ~Foo() (Temporary object destructor)

auto elided_return_lambda() {
  return [x=get_foo()]() {};
}
// CHECK: (lambda at {{.*}}) elided_return_lambda()
// CXX14: (CXXConstructExpr{{.*}}, class (lambda at {{.*}}))
// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)
// CXX14: ~Foo() (Temporary object destructor)

void const_auto_obj() {
  const Bar bar;
}
// CHECK: void const_auto_obj()
// CHECK: .~Bar() (Implicit destructor)

void has_default_arg(Foo foo = get_foo());
void test_default_arg() {
  // FIXME: This emits a destructor but no constructor.  Search CFG.cpp for
  // 'PR13385' for details.
  has_default_arg();
}
// CHECK: void test_default_arg()
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Temporary object destructor)

struct DefaultArgInCtor {
    DefaultArgInCtor(Foo foo = get_foo());
    ~DefaultArgInCtor();
};

void default_ctor_with_default_arg() {
  // FIXME: Default arguments are mishandled in two ways:
  // - The constructor is not emitted at all (not specific to arrays; see fixme
  //   in CFG.cpp that mentions PR13385).
  // - The destructor is emitted once, even though the default argument will be
  //   constructed and destructed once per array element.
  // Ideally, the CFG would expand array constructions into a loop that
  // constructs each array element, allowing default argument
  // constructor/destructor calls to be correctly placed inside the loop.
  DefaultArgInCtor qux[3];
}
// CHECK: void default_ctor_with_default_arg()
// CHECK: CXXConstructExpr, {{.*}}, struct DefaultArgInCtor [3]
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Temporary object destructor)
// CHECK: .~DefaultArgInCtor [3]() (Implicit destructor)

void new_default_ctor_with_default_arg(long count) {
  // Same problems as above.
  new DefaultArgInCtor[count];
}
// CHECK: void new_default_ctor_with_default_arg(long count)
// CHECK: CXXConstructExpr, {{.*}}, struct DefaultArgInCtor []
// CXX14: ~Foo() (Temporary object destructor)
// CHECK: ~Foo() (Temporary object destructor)

#if CXX2A
// Boilerplate needed to test co_return:

namespace std::experimental {
  template <typename Promise>
  struct coroutine_handle {
    static coroutine_handle from_address(void *);
  };
}

struct TestPromise {
  TestPromise initial_suspend();
  TestPromise final_suspend();
  bool await_ready();
  void await_suspend(const std::experimental::coroutine_handle<TestPromise> &);
  void await_resume();
  Foo return_value(const Bar &);
  Bar get_return_object();
  void unhandled_exception();
};

namespace std::experimental {
  template <typename Ret, typename... Args>
  struct coroutine_traits;
  template <>
  struct coroutine_traits<Bar> {
      using promise_type = TestPromise;
  };
}

Bar coreturn() {
  co_return get_bar();
  // This expands to something like:
  //     promise.return_value(get_bar());
  // get_bar() is passed by reference to return_value() and is then destroyed;
  // there is no equivalent of RVO.  TestPromise::return_value also returns a
  // Foo, which should be immediately destroyed.
  // FIXME: The generated CFG completely ignores get_return_object().
}
// CXX2A: Bar coreturn()
// CXX2A: ~Foo() (Temporary object destructor)
// CXX2A: ~Bar() (Temporary object destructor)
#endif