brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.5 KiB · 044e0b7 Raw
318 lines · cpp
1// RUN: rm -f %t.14 %t.2a2// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++14 -DCXX2A=0 -fblocks -Wall -Wno-unused -Werror %s > %t.14 2>&13// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -std=c++2a -DCXX2A=1 -fblocks -Wall -Wno-unused -Werror %s > %t.2a 2>&14// RUN: FileCheck --input-file=%t.14 -check-prefixes=CHECK,CXX14 -implicit-check-not=destructor %s5// RUN: FileCheck --input-file=%t.2a -check-prefixes=CHECK,CXX2A -implicit-check-not=destructor %s6 7int puts(const char *);8 9struct Foo {10  Foo() = delete;11#if CXX2A12  // Guarantee that the elided examples are actually elided by deleting the13  // copy constructor.14  Foo(const Foo &) = delete;15#else16  // No elision support, so we need a copy constructor.17  Foo(const Foo &);18#endif19  ~Foo();20};21 22struct TwoFoos {23  Foo foo1, foo2;24  ~TwoFoos();25};26 27Foo get_foo();28 29struct Bar {30  Bar();31  Bar(const Bar &);32  ~Bar();33  Bar &operator=(const Bar &);34};35 36Bar get_bar();37 38struct TwoBars {39  Bar foo1, foo2;40  ~TwoBars();41};42 43// Start of tests:44 45void elided_assign() {46  Foo x = get_foo();47}48// CHECK: void elided_assign()49// CXX14: (CXXConstructExpr{{.*}}, Foo)50// CXX14: ~Foo() (Temporary object destructor)51// CHECK: ~Foo() (Implicit destructor)52 53void nonelided_assign() {54  Bar x = (const Bar &)get_bar();55}56// CHECK: void nonelided_assign()57// CHECK: (CXXConstructExpr{{.*}}, Bar)58// CHECK: ~Bar() (Temporary object destructor)59// CHECK: ~Bar() (Implicit destructor)60 61void elided_paren_init() {62  Foo x(get_foo());63}64// CHECK: void elided_paren_init()65// CXX14: (CXXConstructExpr{{.*}}, Foo)66// CXX14: ~Foo() (Temporary object destructor)67// CHECK: ~Foo() (Implicit destructor)68 69void nonelided_paren_init() {70  Bar x((const Bar &)get_bar());71}72// CHECK: void nonelided_paren_init()73// CHECK: (CXXConstructExpr{{.*}}, Bar)74// CHECK: ~Bar() (Temporary object destructor)75// CHECK: ~Bar() (Implicit destructor)76 77void elided_brace_init() {78  Foo x{get_foo()};79}80// CHECK: void elided_brace_init()81// CXX14: (CXXConstructExpr{{.*}}, Foo)82// CXX14: ~Foo() (Temporary object destructor)83// CHECK: ~Foo() (Implicit destructor)84 85void nonelided_brace_init() {86  Bar x{(const Bar &)get_bar()};87}88// CHECK: void nonelided_brace_init()89// CHECK: (CXXConstructExpr{{.*}}, Bar)90// CHECK: ~Bar() (Temporary object destructor)91// CHECK: ~Bar() (Implicit destructor)92 93void elided_lambda_capture_init() {94  // The copy from get_foo() into the lambda should be elided.  Should call95  // the lambda's destructor, but not ~Foo() separately.96  // (This syntax is C++14 'generalized lambda captures'.)97  auto z = [x=get_foo()]() {};98}99// CHECK: void elided_lambda_capture_init()100// CXX14: (CXXConstructExpr{{.*}}, Foo)101// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)102// CXX14: ~Foo() (Temporary object destructor)103// CHECK: ~(lambda at {{.*}})() (Implicit destructor)104 105void nonelided_lambda_capture_init() {106  // Should call the lambda's destructor as well as ~Bar() for the temporary.107  auto z = [x((const Bar &)get_bar())]() {};108}109// CHECK: void nonelided_lambda_capture_init()110// CHECK: (CXXConstructExpr{{.*}}, Bar)111// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)112// CHECK: ~Bar() (Temporary object destructor)113// CHECK: ~(lambda at {{.*}})() (Implicit destructor)114 115Foo elided_return_stmt_expr() {116  // Two copies, both elided in C++17.117  return ({ get_foo(); });118}119// CHECK: Foo elided_return_stmt_expr()120// CXX14: (CXXConstructExpr{{.*}}, Foo)121// CXX14: ~Foo() (Temporary object destructor)122// CXX14: (CXXConstructExpr{{.*}}, Foo)123// CXX14: ~Foo() (Temporary object destructor)124 125void elided_stmt_expr() {126  // One copy, elided in C++17.127  ({ get_foo(); });128}129// CHECK: void elided_stmt_expr()130// CXX14: (CXXConstructExpr{{.*}}, Foo)131// CXX14: ~Foo() (Temporary object destructor)132// CHECK: ~Foo() (Temporary object destructor)133 134 135void elided_stmt_expr_multiple_stmts() {136  // Make sure that only the value returned out of a statement expression is137  // elided.138  ({ get_bar(); get_foo(); });139}140// CHECK: void elided_stmt_expr_multiple_stmts()141// CHECK: ~Bar() (Temporary object destructor)142// CXX14: (CXXConstructExpr{{.*}}, Foo)143// CXX14: ~Foo() (Temporary object destructor)144// CHECK: ~Foo() (Temporary object destructor)145 146 147void unelided_stmt_expr() {148  ({ (const Bar &)get_bar(); });149}150// CHECK: void unelided_stmt_expr()151// CHECK: (CXXConstructExpr{{.*}}, Bar)152// CHECK: ~Bar() (Temporary object destructor)153// CHECK: ~Bar() (Temporary object destructor)154 155void elided_aggregate_init() {156  TwoFoos x{get_foo(), get_foo()};157}158// CHECK: void elided_aggregate_init()159// CXX14: (CXXConstructExpr{{.*}}, Foo)160// CXX14: (CXXConstructExpr{{.*}}, Foo)161// CXX14: ~Foo() (Temporary object destructor)162// CXX14: ~Foo() (Temporary object destructor)163// CHECK: ~TwoFoos() (Implicit destructor)164 165void nonelided_aggregate_init() {166  TwoBars x{(const Bar &)get_bar(), (const Bar &)get_bar()};167}168// CHECK: void nonelided_aggregate_init()169// CHECK: (CXXConstructExpr{{.*}}, Bar)170// CHECK: (CXXConstructExpr{{.*}}, Bar)171// CHECK: ~Bar() (Temporary object destructor)172// CHECK: ~Bar() (Temporary object destructor)173// CHECK: ~TwoBars() (Implicit destructor)174 175TwoFoos return_aggregate_init() {176  return TwoFoos{get_foo(), get_foo()};177}178// CHECK: TwoFoos return_aggregate_init()179// CXX14: (CXXConstructExpr{{.*}}, Foo)180// CXX14: (CXXConstructExpr{{.*}}, Foo)181// CXX14: ~TwoFoos() (Temporary object destructor)182// CXX14: ~Foo() (Temporary object destructor)183// CXX14: ~Foo() (Temporary object destructor)184 185void lifetime_extended() {186  const Foo &x = (get_foo(), get_foo());187  puts("one destroyed before, one destroyed after");188}189// CHECK: void lifetime_extended()190// CHECK: ~Foo() (Temporary object destructor)191// CHECK: one destroyed before, one destroyed after192// CHECK: ~Foo() (Implicit destructor)193 194void not_lifetime_extended() {195  Foo x = (get_foo(), get_foo());196  puts("one destroyed before, one destroyed after");197}198// CHECK: void not_lifetime_extended()199// CXX14: (CXXConstructExpr{{.*}}, Foo)200// CHECK: ~Foo() (Temporary object destructor)201// CXX14: ~Foo() (Temporary object destructor)202// CHECK: one destroyed before, one destroyed after203// CHECK: ~Foo() (Implicit destructor)204 205void compound_literal() {206  (void)(Bar[]){{}, {}};207}208// CHECK: void compound_literal()209// CHECK: (CXXConstructExpr, Bar)210// CHECK: (CXXConstructExpr, Bar)211// CHECK: ~Bar[2]() (Temporary object destructor)212 213Foo elided_return() {214  return get_foo();215}216// CHECK: Foo elided_return()217// CXX14: (CXXConstructExpr{{.*}}, Foo)218// CXX14: ~Foo() (Temporary object destructor)219 220auto elided_return_lambda() {221  return [x=get_foo()]() {};222}223// CHECK: (lambda at {{.*}}) elided_return_lambda()224// CXX14: (CXXConstructExpr{{.*}}, class (lambda at {{.*}}))225// CXX14: ~(lambda at {{.*}})() (Temporary object destructor)226// CXX14: ~Foo() (Temporary object destructor)227 228void const_auto_obj() {229  const Bar bar;230}231// CHECK: void const_auto_obj()232// CHECK: .~Bar() (Implicit destructor)233 234void has_default_arg(Foo foo = get_foo());235void test_default_arg() {236  // FIXME: This emits a destructor but no constructor.  Search CFG.cpp for237  // 'PR13385' for details.238  has_default_arg();239}240// CHECK: void test_default_arg()241// CXX14: ~Foo() (Temporary object destructor)242// CHECK: ~Foo() (Temporary object destructor)243 244struct DefaultArgInCtor {245    DefaultArgInCtor(Foo foo = get_foo());246    ~DefaultArgInCtor();247};248 249void default_ctor_with_default_arg() {250  // FIXME: Default arguments are mishandled in two ways:251  // - The constructor is not emitted at all (not specific to arrays; see fixme252  //   in CFG.cpp that mentions PR13385).253  // - The destructor is emitted once, even though the default argument will be254  //   constructed and destructed once per array element.255  // Ideally, the CFG would expand array constructions into a loop that256  // constructs each array element, allowing default argument257  // constructor/destructor calls to be correctly placed inside the loop.258  DefaultArgInCtor qux[3];259}260// CHECK: void default_ctor_with_default_arg()261// CHECK: CXXConstructExpr, {{.*}}, DefaultArgInCtor[3]262// CXX14: ~Foo() (Temporary object destructor)263// CHECK: ~Foo() (Temporary object destructor)264// CHECK: .~DefaultArgInCtor[3]() (Implicit destructor)265 266void new_default_ctor_with_default_arg(long count) {267  // Same problems as above.268  new DefaultArgInCtor[count];269}270// CHECK: void new_default_ctor_with_default_arg(long count)271// CHECK: CXXConstructExpr, {{.*}}, DefaultArgInCtor[]272// CXX14: ~Foo() (Temporary object destructor)273// CHECK: ~Foo() (Temporary object destructor)274 275#if CXX2A276// Boilerplate needed to test co_return:277 278namespace std {279template <typename Promise>280struct coroutine_handle {281  static coroutine_handle from_address(void *) noexcept;282};283} // namespace std284 285struct TestPromise {286  TestPromise initial_suspend();287  TestPromise final_suspend() noexcept;288  bool await_ready() noexcept;289  void await_suspend(const std::coroutine_handle<TestPromise> &) noexcept;290  void await_resume() noexcept;291  Foo return_value(const Bar &);292  Bar get_return_object();293  void unhandled_exception();294};295 296namespace std {297template <typename Ret, typename... Args>298struct coroutine_traits;299template <>300struct coroutine_traits<Bar> {301  using promise_type = TestPromise;302};303} // namespace std304 305Bar coreturn() {306  co_return get_bar();307  // This expands to something like:308  //     promise.return_value(get_bar());309  // get_bar() is passed by reference to return_value() and is then destroyed;310  // there is no equivalent of RVO.  TestPromise::return_value also returns a311  // Foo, which should be immediately destroyed.312  // FIXME: The generated CFG completely ignores get_return_object().313}314// CXX2A: Bar coreturn()315// CXX2A: ~Foo() (Temporary object destructor)316// CXX2A: ~Bar() (Temporary object destructor)317#endif318