1*a393e68bSGeorge Karpenkov // RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=debug.DumpCFG -std=c++14 -analyzer-config eagerly-assume=false %s > %t 2>&1 26a5cd5e1SArtem Dergachev // RUN: FileCheck --input-file=%t %s 3*a393e68bSGeorge Karpenkov // RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=core,debug.ExprInspection -std=c++14 -verify -analyzer-config eagerly-assume=false %s 46a5cd5e1SArtem Dergachev 56a5cd5e1SArtem Dergachev void clang_analyzer_eval(bool); 66a5cd5e1SArtem Dergachev 76a5cd5e1SArtem Dergachev int global; 86a5cd5e1SArtem Dergachev 96a5cd5e1SArtem Dergachev namespace variant_0 { 106a5cd5e1SArtem Dergachev // This variant of the code works correctly. Function foo() is not a template 116a5cd5e1SArtem Dergachev // function. Note that there are two destructors within foo(). 126a5cd5e1SArtem Dergachev 136a5cd5e1SArtem Dergachev class A { 146a5cd5e1SArtem Dergachev public: 156a5cd5e1SArtem Dergachev ~A() { ++global; } 166a5cd5e1SArtem Dergachev }; 176a5cd5e1SArtem Dergachev 186a5cd5e1SArtem Dergachev class B { 196a5cd5e1SArtem Dergachev A a; 206a5cd5e1SArtem Dergachev }; 216a5cd5e1SArtem Dergachev 226a5cd5e1SArtem Dergachev // CHECK: void foo(int) 236a5cd5e1SArtem Dergachev // CHECK: [B1] 246a5cd5e1SArtem Dergachev // CHECK-NEXT: 1: (CXXConstructExpr, [B1.2], class variant_0::B) 256a5cd5e1SArtem Dergachev // CHECK-NEXT: 2: variant_0::B i; 266a5cd5e1SArtem Dergachev // CHECK-NEXT: 3: operator= 276a5cd5e1SArtem Dergachev // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, class variant_0::B &(*)(class variant_0::B &&) noexcept) 286a5cd5e1SArtem Dergachev // CHECK-NEXT: 5: i 296a5cd5e1SArtem Dergachev // CHECK-NEXT: 6: {} (CXXConstructExpr, [B1.7], [B1.8], class variant_0::B) 306a5cd5e1SArtem Dergachev // CHECK-NEXT: 7: [B1.6] (BindTemporary) 316a5cd5e1SArtem Dergachev // CHECK-NEXT: 8: [B1.7] 326a5cd5e1SArtem Dergachev // CHECK-NEXT: 9: [B1.5] = [B1.8] (OperatorCall) 336a5cd5e1SArtem Dergachev // CHECK-NEXT: 10: ~variant_0::B() (Temporary object destructor) 346a5cd5e1SArtem Dergachev // CHECK-NEXT: 11: [B1.2].~B() (Implicit destructor) 356a5cd5e1SArtem Dergachev void foo(int) { 366a5cd5e1SArtem Dergachev B i; 376a5cd5e1SArtem Dergachev i = {}; 386a5cd5e1SArtem Dergachev } 396a5cd5e1SArtem Dergachev 406a5cd5e1SArtem Dergachev void bar() { 416a5cd5e1SArtem Dergachev global = 0; 426a5cd5e1SArtem Dergachev foo(1); 436a5cd5e1SArtem Dergachev clang_analyzer_eval(global == 2); // expected-warning{{TRUE}} 446a5cd5e1SArtem Dergachev } 456a5cd5e1SArtem Dergachev 466a5cd5e1SArtem Dergachev } // end namespace variant_0 476a5cd5e1SArtem Dergachev 486a5cd5e1SArtem Dergachev namespace variant_1 { 496a5cd5e1SArtem Dergachev // Suddenly, if we turn foo() into a template, we are missing a 506a5cd5e1SArtem Dergachev // CXXBindTemporaryExpr in the AST, and therefore we're missing a 516a5cd5e1SArtem Dergachev // temporary destructor in the CFG. 526a5cd5e1SArtem Dergachev 536a5cd5e1SArtem Dergachev class A { 546a5cd5e1SArtem Dergachev public: 556a5cd5e1SArtem Dergachev ~A() { ++global; } 566a5cd5e1SArtem Dergachev }; 576a5cd5e1SArtem Dergachev 586a5cd5e1SArtem Dergachev class B { 596a5cd5e1SArtem Dergachev A a; 606a5cd5e1SArtem Dergachev }; 616a5cd5e1SArtem Dergachev 626a5cd5e1SArtem Dergachev // FIXME: Find the construction context for {} and enforce the temporary 636a5cd5e1SArtem Dergachev // destructor. 646a5cd5e1SArtem Dergachev // CHECK: template<> void foo<int>(int) 656a5cd5e1SArtem Dergachev // CHECK: [B1] 666a5cd5e1SArtem Dergachev // CHECK-NEXT: 1: (CXXConstructExpr, [B1.2], class variant_1::B) 676a5cd5e1SArtem Dergachev // CHECK-NEXT: 2: variant_1::B i; 686a5cd5e1SArtem Dergachev // CHECK-NEXT: 3: operator= 696a5cd5e1SArtem Dergachev // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, class variant_1::B &(*)(class variant_1::B &&) noexcept) 706a5cd5e1SArtem Dergachev // CHECK-NEXT: 5: i 716a5cd5e1SArtem Dergachev // CHECK-NEXT: 6: {} (CXXConstructExpr, class variant_1::B) 726a5cd5e1SArtem Dergachev // CHECK-NEXT: 7: [B1.6] 736a5cd5e1SArtem Dergachev // CHECK-NEXT: 8: [B1.5] = [B1.7] (OperatorCall) 746a5cd5e1SArtem Dergachev // CHECK-NEXT: 9: [B1.2].~B() (Implicit destructor) 756a5cd5e1SArtem Dergachev template <typename T> void foo(T) { 766a5cd5e1SArtem Dergachev B i; 776a5cd5e1SArtem Dergachev i = {}; 786a5cd5e1SArtem Dergachev } 796a5cd5e1SArtem Dergachev 806a5cd5e1SArtem Dergachev void bar() { 816a5cd5e1SArtem Dergachev global = 0; 826a5cd5e1SArtem Dergachev foo(1); 836a5cd5e1SArtem Dergachev // FIXME: Should be TRUE, i.e. we should call (and inline) two destructors. 846a5cd5e1SArtem Dergachev clang_analyzer_eval(global == 2); // expected-warning{{UNKNOWN}} 856a5cd5e1SArtem Dergachev } 866a5cd5e1SArtem Dergachev 876a5cd5e1SArtem Dergachev } // end namespace variant_1 886a5cd5e1SArtem Dergachev 896a5cd5e1SArtem Dergachev namespace variant_2 { 906a5cd5e1SArtem Dergachev // Making field 'a' in class 'B' public turns the class into an aggregate. 916a5cd5e1SArtem Dergachev // In this case there is no constructor at {} - only an aggregate 926a5cd5e1SArtem Dergachev // initialization. Aggregate initialization is unsupported for now. 936a5cd5e1SArtem Dergachev 946a5cd5e1SArtem Dergachev class A { 956a5cd5e1SArtem Dergachev public: 966a5cd5e1SArtem Dergachev ~A() { ++global; } 976a5cd5e1SArtem Dergachev }; 986a5cd5e1SArtem Dergachev 996a5cd5e1SArtem Dergachev class B { 1006a5cd5e1SArtem Dergachev public: 1016a5cd5e1SArtem Dergachev A a; 1026a5cd5e1SArtem Dergachev }; 1036a5cd5e1SArtem Dergachev 1046a5cd5e1SArtem Dergachev // CHECK: template<> void foo<int>(int) 1056a5cd5e1SArtem Dergachev // CHECK: [B1] 1066a5cd5e1SArtem Dergachev // CHECK-NEXT: 1: (CXXConstructExpr, [B1.2], class variant_2::B) 1076a5cd5e1SArtem Dergachev // CHECK-NEXT: 2: variant_2::B i; 1086a5cd5e1SArtem Dergachev // CHECK-NEXT: 3: operator= 1096a5cd5e1SArtem Dergachev // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, FunctionToPointerDecay, class variant_2::B &(*)(class variant_2::B &&) noexcept) 1106a5cd5e1SArtem Dergachev // CHECK-NEXT: 5: i 1116a5cd5e1SArtem Dergachev // CHECK-NEXT: 6: {} 1126a5cd5e1SArtem Dergachev // CHECK-NEXT: 7: {} 1136a5cd5e1SArtem Dergachev // CHECK-NEXT: 8: [B1.7] (BindTemporary) 1146a5cd5e1SArtem Dergachev // CHECK-NEXT: 9: [B1.8] 1156a5cd5e1SArtem Dergachev // CHECK-NEXT: 10: [B1.5] = [B1.9] (OperatorCall) 1166a5cd5e1SArtem Dergachev // CHECK-NEXT: 11: ~variant_2::B() (Temporary object destructor) 1176a5cd5e1SArtem Dergachev // CHECK-NEXT: 12: [B1.2].~B() (Implicit destructor) 1186a5cd5e1SArtem Dergachev template <typename T> void foo(T) { 1196a5cd5e1SArtem Dergachev B i; 1206a5cd5e1SArtem Dergachev i = {}; 1216a5cd5e1SArtem Dergachev } 1226a5cd5e1SArtem Dergachev 1236a5cd5e1SArtem Dergachev void bar() { 1246a5cd5e1SArtem Dergachev global = 0; 1256a5cd5e1SArtem Dergachev foo(1); 1266a5cd5e1SArtem Dergachev // FIXME: Should be TRUE, i.e. we should call (and inline) two destructors. 1276a5cd5e1SArtem Dergachev clang_analyzer_eval(global == 2); // expected-warning{{UNKNOWN}} 1286a5cd5e1SArtem Dergachev } 1296a5cd5e1SArtem Dergachev 1306a5cd5e1SArtem Dergachev } // end namespace variant_2 131