]> granicus.if.org Git - clang/commitdiff
[CFG] [analyzer] pr41142: C++17: Skip transparent InitListExprs in constructors.
authorArtem Dergachev <artem.dergachev@gmail.com>
Thu, 21 Mar 2019 00:15:07 +0000 (00:15 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Thu, 21 Mar 2019 00:15:07 +0000 (00:15 +0000)
When searching for construction contexts, i.e. figuring out which statements
define the object that is constructed by each construct-expression, ignore
transparent init-list expressions because they don't add anything to the
context. This allows the Static Analyzer to model construction, destruction,
materialization, lifetime extension correctly in more cases. Also fixes
a crash caused by incorrectly evaluating initial values of variables
initialized with such expressions.

Differential Revision: https://reviews.llvm.org/D59573

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@356634 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFG.cpp
test/Analysis/cfg-rich-constructors.cpp
test/Analysis/initializer.cpp

index f6b829147b343ac4c950395e74a9bb6dcb3162ec..6ff72540afe65ad295337383e1a1e42c37108862 100644 (file)
@@ -1378,6 +1378,15 @@ void CFGBuilder::findConstructionContexts(
     findConstructionContexts(Layer, CO->getRHS());
     break;
   }
+  case Stmt::InitListExprClass: {
+    auto *ILE = cast<InitListExpr>(Child);
+    if (ILE->isTransparent()) {
+      findConstructionContexts(Layer, ILE->getInit(0));
+      break;
+    }
+    // TODO: Handle other cases. For now, fail to find construction contexts.
+    break;
+  }
   default:
     break;
   }
index 31c306bbfe9c5c411270b4e5f34228e1b9e42215..0125c9bf52325480dcdb1cb5dcc5f169ec22c98f 100644 (file)
@@ -1043,3 +1043,23 @@ void testCrashOnVariadicArgument() {
   C c(variadic(0 ? c : 0)); // no-crash
 }
 } // namespace variadic_function_arguments
+
+// CHECK: void testTransparentInitListExprs()
+// CHECK:        [B1]
+// CHECK-NEXT:     1: getC
+// CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class transparent_init_list_exprs::C (*)(void))
+// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.5])
+// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
+// CXX11-NEXT:     4: [B1.3]
+// CXX11-NEXT:     5: {[B1.4]} (CXXConstructExpr, [B1.6], class transparent_init_list_exprs::C)
+// CXX11-NEXT:     6: transparent_init_list_exprs::C c{getC()};
+// CXX17-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.5])
+// CXX17-NEXT:     4: {[B1.3]}
+// CXX17-NEXT:     5: transparent_init_list_exprs::C c{getC()};
+namespace transparent_init_list_exprs {
+class C {};
+C getC();
+void testTransparentInitListExprs() {
+  C c{getC()};
+}
+} // namespace transparent_init_list_exprs
index 0cb68c4a9780e0531f82187f0449b330ca68a708..5853f3aed565509c0f2ee40357748084c1a17bf3 100644 (file)
@@ -242,4 +242,22 @@ void foo() {
   B &&bcr = C({{}}); // no-crash
 #endif
 }
+} // namespace CXX17_aggregate_construction
+
+namespace CXX17_transparent_init_list_exprs {
+class A {};
+
+class B: private A {};
+
+B boo();
+void foo1() {
+  B b { boo() }; // no-crash
+}
+
+class C: virtual public A {};
+
+C coo();
+void foo2() {
+  C c { coo() }; // no-crash
 }
+} // namespace CXX17_transparent_init_list_exprs