From aa40315c69fb667c070293ea94f6caaf4a0a6ec6 Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Thu, 21 Mar 2019 00:15:07 +0000 Subject: [PATCH] [CFG] [analyzer] pr41142: C++17: Skip transparent InitListExprs in constructors. 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 llvm-svn: 356634 --- clang/lib/Analysis/CFG.cpp | 9 +++++++++ clang/test/Analysis/cfg-rich-constructors.cpp | 20 ++++++++++++++++++++ clang/test/Analysis/initializer.cpp | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index f6b8291..6ff7254 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -1378,6 +1378,15 @@ void CFGBuilder::findConstructionContexts( findConstructionContexts(Layer, CO->getRHS()); break; } + case Stmt::InitListExprClass: { + auto *ILE = cast(Child); + if (ILE->isTransparent()) { + findConstructionContexts(Layer, ILE->getInit(0)); + break; + } + // TODO: Handle other cases. For now, fail to find construction contexts. + break; + } default: break; } diff --git a/clang/test/Analysis/cfg-rich-constructors.cpp b/clang/test/Analysis/cfg-rich-constructors.cpp index 31c306b..0125c9b 100644 --- a/clang/test/Analysis/cfg-rich-constructors.cpp +++ b/clang/test/Analysis/cfg-rich-constructors.cpp @@ -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 diff --git a/clang/test/Analysis/initializer.cpp b/clang/test/Analysis/initializer.cpp index 0cb68c4..5853f3a 100644 --- a/clang/test/Analysis/initializer.cpp +++ b/clang/test/Analysis/initializer.cpp @@ -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 -- 2.7.4