r327096 - [CFG] [analyzer] Add construction context for implicit constructor conversions.
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 8 17:39:59 PST 2018
Author: dergachev
Date: Thu Mar 8 17:39:59 2018
New Revision: 327096
URL: http://llvm.org/viewvc/llvm-project?rev=327096&view=rev
Log:
[CFG] [analyzer] Add construction context for implicit constructor conversions.
Implicit constructor conversions such as A a = B() are represented by
surrounding the constructor for B() with an ImplicitCastExpr of
CK_ConstructorConversion kind, similarly to how explicit constructor conversions
are surrounded by a CXXFunctionalCastExpr. Support this syntax pattern when
extracting the construction context for the implicit constructor that
performs the conversion.
Differential Revision: https://reviews.llvm.org/D44051
Modified:
cfe/trunk/lib/Analysis/CFG.cpp
cfe/trunk/lib/Analysis/ConstructionContext.cpp
cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
cfe/trunk/test/Analysis/temporaries.cpp
Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=327096&r1=327095&r2=327096&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Thu Mar 8 17:39:59 2018
@@ -1202,8 +1202,13 @@ void CFGBuilder::findConstructionContext
case Stmt::ImplicitCastExprClass: {
auto *Cast = cast<ImplicitCastExpr>(Child);
// TODO: We need to support CK_ConstructorConversion, maybe other kinds?
- if (Cast->getCastKind() == CK_NoOp)
+ switch (Cast->getCastKind()) {
+ case CK_NoOp:
+ case CK_ConstructorConversion:
findConstructionContexts(Layer, Cast->getSubExpr());
+ default:
+ break;
+ }
break;
}
case Stmt::CXXBindTemporaryExprClass: {
Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=327096&r1=327095&r2=327096&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original)
+++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Thu Mar 8 17:39:59 2018
@@ -70,8 +70,11 @@ const ConstructionContext *ConstructionC
C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
return new (CC) TemporaryObjectConstructionContext(BTE, MTE);
} else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
+ // If the object requires destruction and is not lifetime-extended,
+ // then it must have a BTE within its MTE.
assert(MTE->getType().getCanonicalType()
- ->getAsCXXRecordDecl()->hasTrivialDestructor());
+ ->getAsCXXRecordDecl()->hasTrivialDestructor() ||
+ MTE->getStorageDuration() != SD_FullExpression);
assert(TopLayer->isLast());
auto *CC =
C.getAllocator().Allocate<TemporaryObjectConstructionContext>();
Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=327096&r1=327095&r2=327096&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
+++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Thu Mar 8 17:39:59 2018
@@ -498,20 +498,70 @@ public:
~B() {}
};
-// FIXME: Find construction context for the implicit constructor conversion.
+// CHECK: void implicitConstructionConversionFromTemporary()
+// CHECK: 1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A)
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CHECK-NEXT: 3: [B1.2]
+// CHECK-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class implicit_constructor_conversion::B)
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CHECK-NEXT: 6: [B1.5] (BindTemporary)
+// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
+// CHECK-NEXT: 8: [B1.7]
+// CHECK-NEXT: 9: [B1.8] (CXXConstructExpr, [B1.10], class implicit_constructor_conversion::B)
+// CHECK-NEXT: 10: implicit_constructor_conversion::B b = implicit_constructor_conversion::A();
+// CHECK-NEXT: 11: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CHECK-NEXT: 12: [B1.10].~B() (Implicit destructor)
+void implicitConstructionConversionFromTemporary() {
+ B b = A();
+}
+
// CHECK: void implicitConstructionConversionFromFunctionValue()
// CHECK: 1: get
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conversion::A (*)(void))
+// CHECK-NEXT: 3: [B1.2]()
+// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CHECK-NEXT: 5: [B1.4]
+// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class implicit_constructor_conversion::B)
+// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CHECK-NEXT: 8: [B1.7] (BindTemporary)
+// CHECK-NEXT: 9: [B1.8] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
+// CHECK-NEXT: 10: [B1.9]
+// CHECK-NEXT: 11: [B1.10] (CXXConstructExpr, [B1.12], class implicit_constructor_conversion::B)
+// CHECK-NEXT: 12: implicit_constructor_conversion::B b = get();
+// CHECK-NEXT: 13: ~implicit_constructor_conversion::B() (Temporary object destructor)
+// CHECK-NEXT: 14: [B1.12].~B() (Implicit destructor)
+void implicitConstructionConversionFromFunctionValue() {
+ B b = get();
+}
+
+// CHECK: void implicitConstructionConversionFromTemporaryWithLifetimeExtension()
+// CHECK: 1: implicit_constructor_conversion::A() (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A)
+// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
+// CHECK-NEXT: 3: [B1.2]
+// CHECK-NEXT: 4: [B1.3] (CXXConstructExpr, [B1.7], class implicit_constructor_conversion::B)
+// CHECK-NEXT: 5: [B1.4] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_conversion::B)
+// CHECK-NEXT: 6: [B1.5] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
+// CHECK-NEXT: 7: [B1.6]
+// CHECK-NEXT: 8: const implicit_constructor_conversion::B &b = implicit_constructor_conversion::A();
+// CHECK-NEXT: 9: [B1.8].~B() (Implicit destructor)
+void implicitConstructionConversionFromTemporaryWithLifetimeExtension() {
+ const B &b = A();
+}
+
+// FIXME: Find construction context for the implicit constructor conversion.
+// CHECK: void implicitConstructionConversionFromFunctionValueWithLifetimeExtension()
+// CHECK: 1: get
// CHECK-NEXT: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class implicit_constructor_conver
// CHECK-NEXT: 3: [B1.2]()
// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::A)
// CHECK-NEXT: 5: [B1.4]
-// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, class implicit_constructor_conversion::B)
+// CHECK-NEXT: 6: [B1.5] (CXXConstructExpr, [B1.9], class implicit_constructor_conversion::B)
// CHECK-NEXT: 7: [B1.6] (ImplicitCastExpr, ConstructorConversion, class implicit_constructor_convers
// CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class implicit_constructor_conversion::B)
// CHECK-NEXT: 9: [B1.8]
// CHECK-NEXT: 10: const implicit_constructor_conversion::B &b = get();
// CHECK-NEXT: 11: [B1.10].~B() (Implicit destructor)
-void implicitConstructionConversionFromFunctionValue() {
+void implicitConstructionConversionFromFunctionValueWithLifetimeExtension() {
const B &b = get(); // no-crash
}
Modified: cfe/trunk/test/Analysis/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temporaries.cpp?rev=327096&r1=327095&r2=327096&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/temporaries.cpp (original)
+++ cfe/trunk/test/Analysis/temporaries.cpp Thu Mar 8 17:39:59 2018
@@ -940,3 +940,48 @@ void test() {
}
} // namespace temporary_list_crash
#endif // C++11
+
+namespace implicit_constructor_conversion {
+struct S {
+ int x;
+ S(int x) : x(x) {}
+ ~S() {}
+};
+
+class C {
+ int x;
+
+public:
+ C(const S &s) : x(s.x) {}
+ ~C() {}
+ int getX() const { return x; }
+};
+
+void test() {
+ const C &c1 = S(10);
+ clang_analyzer_eval(c1.getX() == 10);
+#ifdef TEMPORARY_DTORS
+ // expected-warning at -2{{TRUE}}
+#else
+ // expected-warning at -4{{UNKNOWN}}
+#endif
+
+ S s = 20;
+ clang_analyzer_eval(s.x == 20);
+#ifdef TEMPORARY_DTORS
+ // expected-warning at -2{{TRUE}}
+#else
+ // expected-warning at -4{{UNKNOWN}}
+#endif
+
+ C c2 = s;
+ clang_analyzer_eval(c2.getX() == 20);
+#ifdef TEMPORARY_DTORS
+ // expected-warning at -2{{TRUE}}
+#else
+ // expected-warning at -4{{UNKNOWN}}
+#endif
+}
+} // end namespace implicit_constructor_conversion
+
+
More information about the cfe-commits
mailing list