[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 129985. m.ostapenko added a comment. Hi Devin, now I'm very sorry for a such long delay. Now I have a bunch of time to proceed development of this patch (if scope contexts are still needed, of course). Regarding to approach you suggested (reuse LocalScope infrastructure and use first VarDecl for ScopeBegin): it seems very reasonable for me, but perhaps I need more advisory here. I've implemented a draft patch to make sure I've understood you correctly (this is not a final version, the test case is completely inadequate for now). While testing, I've discovered several questions that I would like to discuss: 1. Do we need to have one-to-one mapping between ScopeBegins and corresponding ScopeEnds or is it OK to assume that ScopeEnd can terminate several nested scopes? 2. In the following example: class A { public: A() {} ~A() {} operator int() const { return 1; } }; bool UV; void test_for_implicit_scope() { for (A a; A b = a; ) if (UV) continue; A c; } it seems that lifetime of **b** ends when we branch out from the loop body (if entered, of course), but it seems that in current implementation we don't generate an implicit destructor for **b** just before **continue**. Is this a bug, or perhaps I'm missing something? # The approach with first VarDecl works not so well with the following test case: void test_goto() { A f; l0: A d; { A a; if (UV) goto l0; if (UV) goto l1; A b; } l1: A c; } in this approach we'll don't emit a ScopeBegin for **d** because the first VarDecl is **f**. However IMHO we still need to add ScopeBegin for **d** in order to handle d's scope end occurring when we jumping to //l0// via **if (UV) goto l0;**. I think this can be solved by adding ScopeBegin for **d** when backpatching blocks late in **buildCFG** routine (when we know all targets of all gotos). Does this approach look reasonable for you? Thanks. https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisDeclContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,909 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B3 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B1 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 7: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 10: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 11: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 12: (CXXConstructExpr, class A) +// CHECK: 13: A b; +// CHECK: 14: CFGScopeEnd(CompoundStmt) +// CHECK: 15: [B1.13].~A() (Implicit destructor) +// CHECK: 16: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: Pr
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
dcoughlin added a comment. Maxim, thanks for commandeering the patch. I apologize for the long delay reviewing! I really like the approach of retrying without scopes enabled when we hit a construct we can't handle yet. This will make is possible to turn the feature on by default (and get it running on large amounts of code) while still developing it incrementally! I'd like to suggest a change in the scope representation that will make it much easier to support all the corner cases and also re-use the existing logic for handling variable scopes. Right now the CFGScopeBegin and CFGScopeEnd elements use a statement (a loop or a CompoundStatement) to uniquely identify a scope. However, this is a problem because a `for` loop with an initializer may have two scopes that we really want to distinguish: for (int i = 0; i < 10; i++) int j = i; Here `i` and `j` really have different scopes, but with the current approach we won't be able tell them apart. My suggestion is to instead use the first VarDecl declared in a scope to uniquely identify it. This means, for example, that CFGScopeBegin's constructor will take a VarDecl instead of a statement. What's nice about this VarDecl approach is that the CFGBuilder already has a bunch of infrastructure to correctly track local scopes for variables (see the `LocalScope` class in CFG.cpp and the `addLocalScopeForStmt()` function.) Further, there are two functions, addLocalScopeAndDtors() and addAutomaticObjHandling() that are already called in all the places where a scope should end. This means you should only need to add logic to add an end of scope element in those two functions. What's more, future work to extend CFG construction to handle new C++ language features will also use these two functions -- so we will get support for those features for free. For an example of how to change those two functions, take a look at Matthias Gehre's commit in https://reviews.llvm.org/D15031. What you would need to do for CFGScopeEnd would be very similar to that patch. Using this approach should also make it possible to re-use the logic in that patch to eventually handle gotos. To handle CFGScopeBegin, you would only need to change CFGBuilder::VisitDeclSubExpr() to detect when the variable being visited is the first variable declared in its LocalScope. If so, you would append the CFGScopeBegin element. What's nice about this is that you won't have to handle all the different kinds of loops individually. What do you think? I'd be happy to have a Skype/Google hangouts talk about this if you want to have real-time discussion about it. Repository: rL LLVM https://reviews.llvm.org/D16403 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 112547. m.ostapenko added a comment. Ping^4 Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/PathDiagnostic.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1098 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 12: (CXXConstructExpr, class A) +// CHECK-NEXT: 13: A b; +// CHECK-NEXT: 14: [B1.13].~A() (Implicit destructor) +// CHECK-NEXT: 15: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 111322. m.ostapenko added a comment. Ping^3 Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/PathDiagnostic.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1098 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 12: (CXXConstructExpr, class A) +// CHECK-NEXT: 13: A b; +// CHECK-NEXT: 14: [B1.13].~A() (Implicit destructor) +// CHECK-NEXT: 15: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 110329. m.ostapenko added a comment. Rebased and ping. Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/PathDiagnostic.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1098 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 12: (CXXConstructExpr, class A) +// CHECK-NEXT: 13: A b; +// CHECK-NEXT: 14: [B1.13].~A() (Implicit destructor) +// CHECK-NEXT: 15: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 108644. m.ostapenko added a comment. Updated some comments. Could someone take a look please? Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1099 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: (CXXConstructExpr, class A) +// CHECK-NEXT: 12: A b; +// CHECK-NEXT: 13: [B1.12].~A() (Implicit destructor) +// CHECK-NEXT: 14: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 15: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructE
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 107894. m.ostapenko added a comment. Rebased and removed a bunch of stale changes. Also added a check for goto's: if we see GotoStmt and have cfg-scopes == true, make badCFG = true and retry without scopes enabled. This check will be removed once GotoStmt will become supported. Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1099 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: (CXXConstructExpr, class A) +// CHECK-NEXT: 12: A b; +// CHECK-NEXT: 13: [B1.12].~A() (Implicit destructor) +// CHECK-NEXT: 14: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 15: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko added a comment. In https://reviews.llvm.org/D16403#808104, @NoQ wrote: > I think the remaining switch-related code seems to be about C++17 switch > condition variables, i.e. `switch (int x = ...)`(?) Yeah, exactly. I can remove it from this patch if it looks confusing. Repository: rL LLVM https://reviews.llvm.org/D16403 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
NoQ added a comment. I think the remaining switch-related code seems to be about C++17 switch condition variables, i.e. `switch (int x = ...)`(?) Repository: rL LLVM https://reviews.llvm.org/D16403 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
szepet added a comment. Hello Maxim! Thanks for working on this! > Ugh, yeah, SwitchStmt is tricky (thank you for pointing to Duff's device > example!). I've tried to resolve several issues with switch revealed by this > testcase, but didn't succeed for now :(. So, it was decided to remove > SwitchStmt support in this patch. I think this is a great decision! It can build up incremental and the patch can be more easily reviewed. When do you plan to upload a patch wihtout casestmt support? (As far as I see there is switchstmt related code but maybe Im missing something.) Repository: rL LLVM https://reviews.llvm.org/D16403 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D16403: Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements
m.ostapenko updated this revision to Diff 106408. m.ostapenko retitled this revision from "Add scope information to CFG" to "Add scope information to CFG for If/While/For/Do/Compound/CXXRangeFor statements". m.ostapenko added a comment. Updating the diff. I've dropped SwitchStmt support, let's implement in separately as well as GotoStmt. Repository: rL LLVM https://reviews.llvm.org/D16403 Files: include/clang/Analysis/AnalysisContext.h include/clang/Analysis/CFG.h include/clang/StaticAnalyzer/Core/AnalyzerOptions.h lib/Analysis/AnalysisDeclContext.cpp lib/Analysis/CFG.cpp lib/StaticAnalyzer/Core/AnalysisManager.cpp lib/StaticAnalyzer/Core/AnalyzerOptions.cpp test/Analysis/analyzer-config.c test/Analysis/analyzer-config.cpp test/Analysis/scopes-cfg-output.cpp Index: test/Analysis/scopes-cfg-output.cpp === --- /dev/null +++ test/Analysis/scopes-cfg-output.cpp @@ -0,0 +1,1030 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-scopes=true %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +class A { +public: +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + A() {} + +// CHECK: [B1 (ENTRY)] +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + ~A() {} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: 1 +// CHECK-NEXT: 3: return [B1.2]; +// CHECK-NEXT: 4: CFGScopeEnd(ReturnStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } +}; + +int getX(); +extern const bool UV; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: a +// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 6: const A &b = a; +// CHECK-NEXT: 7: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 8: [B1.7] (BindTemporary) +// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 10: [B1.9] +// CHECK-NEXT: 11: const A &c = A(); +// CHECK-NEXT: 12: [B1.11].~A() (Implicit destructor) +// CHECK-NEXT: 13: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 14: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_const_ref() { + A a; + const A& b = a; + const A& c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 3: A a[2]; +// CHECK-NEXT: 4: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 5: A b[0]; +// CHECK-NEXT: 6: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 7: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A a; +// CHECK-NEXT: 4: CFGScopeBegin(CompoundStmt) +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A c; +// CHECK-NEXT: 7: (CXXConstructExpr, class A) +// CHECK-NEXT: 8: A d; +// CHECK-NEXT: 9: [B1.8].~A() (Implicit destructor) +// CHECK-NEXT: 10: [B1.6].~A() (Implicit destructor) +// CHECK-NEXT: 11: (CXXConstructExpr, class A) +// CHECK-NEXT: 12: A b; +// CHECK-NEXT: 13: [B1.12].~A() (Implicit destructor) +// CHECK-NEXT: 14: [B1.3].~A() (Implicit destructor) +// CHECK-NEXT: 15: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: 16: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +void test_scope() { + A a; + { A c; +A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 5: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 6: CFGScopeEnd(CompoundStmt) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: CFGScopeBegin(IfStmt) +// CHECK-NEXT: 2: return; +// CHECK-NEXT: 3: [B3.5].~A() (Implicit destructor) +// CHECK-NEXT: 4: [B3.3].~A() (Implicit destructor) +// CHECK-NEXT: 5: CFGScopeEnd(ReturnStmt) +// C