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