From: Artem Dergachev Date: Mon, 12 Feb 2018 22:36:36 +0000 (+0000) Subject: [CFG] Provide construction contexts for return value constructors. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a9a4c57c2a62f6278080a8f9927c268d33ea68b0;p=clang [CFG] Provide construction contexts for return value constructors. When the current function returns a C++ object by value, CFG elements for constructors that construct the return values can now be queried to discover that they're indeed participating in construction of the respective return value at the respective return statement. Differential Revision: https://reviews.llvm.org/D42875 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@324952 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 934abb063e..cec5a652b9 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -2575,6 +2575,8 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R); + EnterConstructionContextIfNecessary(R, R->getRetValue()); + // If the one of the destructors does not return, we already have the Exit // block as a successor. if (!Block->hasNoReturnElement()) diff --git a/test/Analysis/cfg-rich-constructors.cpp b/test/Analysis/cfg-rich-constructors.cpp index 012d382a75..46125f729f 100644 --- a/test/Analysis/cfg-rich-constructors.cpp +++ b/test/Analysis/cfg-rich-constructors.cpp @@ -5,6 +5,7 @@ class C { public: C(); C(C *); + C(int, int); static C get(); }; @@ -224,3 +225,94 @@ public: }; } // end namespace ctor_initializers + +namespace return_stmt { + +// CHECK: C returnVariable() +// CHECK: 1: (CXXConstructExpr, [B1.2], class C) +// CHECK-NEXT: 2: C c; +// CHECK-NEXT: 3: c +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, class C) +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) +// CHECK-NEXT: 6: return [B1.5]; +C returnVariable() { + C c; + return c; +} + +// CHECK: C returnEmptyBraces() +// CHECK: 1: {} (CXXConstructExpr, [B1.2], class C) +// CHECK-NEXT: 2: return [B1.1]; +C returnEmptyBraces() { + return {}; +} + +// CHECK: C returnBracesWithOperatorNew() +// CHECK: 1: CFGNewAllocator(C *) +// CHECK-NEXT: 2: (CXXConstructExpr, [B1.3], class C) +// CHECK-NEXT: 3: new C([B1.2]) +// CHECK-NEXT: 4: {[B1.3]} (CXXConstructExpr, [B1.5], class C) +// CHECK-NEXT: 5: return [B1.4]; +C returnBracesWithOperatorNew() { + return {new C()}; +} + +// CHECK: C returnBracesWithMultipleItems() +// CHECK: 1: 123 +// CHECK-NEXT: 2: 456 +// CHECK-NEXT: 3: {[B1.1], [B1.2]} (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: return [B1.3]; +C returnBracesWithMultipleItems() { + return {123, 456}; +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnTemporary() +// CHECK: 1: C() (CXXConstructExpr, class C) +// CHECK-NEXT: 2: [B1.1] +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.4], class C) +// CHECK-NEXT: 4: return [B1.3]; +C returnTemporary() { + return C(); +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnTemporaryWithArgument() +// CHECK: 1: nullptr +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *) +// CHECK-NEXT: 3: [B1.2] (CXXConstructExpr, class C) +// CHECK-NEXT: 4: C([B1.3]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 5: [B1.4] +// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.7], class C) +// CHECK-NEXT: 7: return [B1.6]; +C returnTemporaryWithArgument() { + return C(nullptr); +} + +// CHECK: C returnTemporaryConstructedByFunction() +// CHECK: 1: C::get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, [B1.6], class C) +// CHECK-NEXT: 6: return [B1.5]; +C returnTemporaryConstructedByFunction() { + return C::get(); +} + +// TODO: Should find construction targets for the first constructor as well. +// CHECK: C returnChainOfCopies() +// CHECK: 1: C::get +// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class C (*)(void)) +// CHECK-NEXT: 3: [B1.2]() +// CHECK-NEXT: 4: [B1.3] +// CHECK-NEXT: 5: [B1.4] (CXXConstructExpr, class C) +// CHECK-NEXT: 6: C([B1.5]) (CXXFunctionalCastExpr, ConstructorConversion, class C) +// CHECK-NEXT: 7: [B1.6] +// CHECK-NEXT: 8: [B1.7] (CXXConstructExpr, [B1.9], class C) +// CHECK-NEXT: 9: return [B1.8]; +C returnChainOfCopies() { + return C(C::get()); +} + +} // end namespace return_stmt diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp index f6c84f505d..1ddf877861 100644 --- a/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -220,7 +220,8 @@ int testConsistencyNestedNormalReturn(bool value) { // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] -// CHECK: 5: [B1.4] (CXXConstructExpr, class A) +// WARNINGS: 5: [B1.4] (CXXConstructExpr, class A) +// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], class A) // CHECK: 6: ~A() (Temporary object destructor) // CHECK: 7: return [B1.5]; // CHECK: Preds (1): B2 @@ -278,7 +279,8 @@ int testConsistencyNestedNormalReturn(bool value) { // CHECK: 2: [B1.1] (BindTemporary) // CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A) // CHECK: 4: [B1.3] -// CHECK: 5: [B1.4] (CXXConstructExpr, class A) +// WARNINGS: 5: [B1.4] (CXXConstructExpr, class A) +// ANALYZER: 5: [B1.4] (CXXConstructExpr, [B1.7], class A) // CHECK: 6: ~A() (Temporary object destructor) // CHECK: 7: return [B1.5]; // CHECK: Preds (1): B2