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