NoQ created this revision. NoQ added reviewers: rsmith, dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet. Herald added subscribers: cfe-commits, rnkovacs.
This one's new, the analyzer didn't enjoy this before. This patch adds construction context for `ReturnStmt`, which means that we'd be able to properly return objects from functions by value. This is the CFG part of the work, the Analyzer-side improvement to make use of it will be in the next patch. Repository: rC Clang https://reviews.llvm.org/D42875 Files: lib/Analysis/CFG.cpp test/Analysis/cfg-rich-constructors.cpp test/Analysis/temp-obj-dtors-cfg-output.cpp
Index: test/Analysis/temp-obj-dtors-cfg-output.cpp =================================================================== --- test/Analysis/temp-obj-dtors-cfg-output.cpp +++ test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -220,7 +220,8 @@ // 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 @@ // 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 Index: test/Analysis/cfg-rich-constructors.cpp =================================================================== --- test/Analysis/cfg-rich-constructors.cpp +++ test/Analysis/cfg-rich-constructors.cpp @@ -5,6 +5,7 @@ public: C(); C(C *); + C(int, int); static C get(); }; @@ -224,3 +225,82 @@ }; } // end namespace ctor_initializers + +namespace return_stmt { + +// 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 Index: lib/Analysis/CFG.cpp =================================================================== --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -2576,6 +2576,8 @@ 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())
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits