martong updated this revision to Diff 425782.
martong added a comment.

- Add an option to config the inlining mode during the first phase
- Change the `ctu-main.c[pp]` tests to have a RUN line with this new config 
option that mimics the old ctu implementation's behavor.
- Change the on-demand-parsing tests back as they were in the baseline. Those 
files are sheer copies of the `ctu-main` files, actually, the on demand testing 
should be done in the `ctu-main` test files as well (added a fixme for that).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D123773/new/

https://reviews.llvm.org/D123773

Files:
  clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
  clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
  clang/test/Analysis/Inputs/ctu-onego-small-other.cpp
  
clang/test/Analysis/Inputs/ctu-onego-small-other.cpp.externalDefMap.ast-dump.txt
  clang/test/Analysis/analyzer-config.c
  clang/test/Analysis/ctu-main.c
  clang/test/Analysis/ctu-main.cpp
  clang/test/Analysis/ctu-on-demand-parsing.c
  clang/test/Analysis/ctu-on-demand-parsing.cpp
  clang/test/Analysis/ctu-onego-indirect.cpp
  clang/test/Analysis/ctu-onego-small.cpp
  clang/test/Analysis/ctu-onego-toplevel.cpp

Index: clang/test/Analysis/ctu-onego-toplevel.cpp
===================================================================
--- clang/test/Analysis/ctu-onego-toplevel.cpp
+++ clang/test/Analysis/ctu-onego-toplevel.cpp
@@ -9,6 +9,7 @@
 // RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
 // RUN:   -verify=ctu %s
 
 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
@@ -16,6 +17,7 @@
 // RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
 // RUN:   -analyzer-config display-ctu-progress=true \
 // RUN:   -analyzer-display-progress \
 // RUN:   -verify=ctu %s 2>&1 | FileCheck %s
Index: clang/test/Analysis/ctu-onego-small.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/ctu-onego-small.cpp
@@ -0,0 +1,51 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir -p %t/ctudir
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
+// RUN:   -emit-pch -o %t/ctudir/ctu-onego-small-other.cpp.ast %S/Inputs/ctu-onego-small-other.cpp
+// RUN: cp %S/Inputs/ctu-onego-small-other.cpp.externalDefMap.ast-dump.txt %t/ctudir/externalDefMap.txt
+
+// Small function defined in another TU.
+int bar();
+
+// Here we limit the ctu analysis to the first phase only (via the
+// ctu-max-nodes config options). And we check whether the small foreign
+// function `bar` is inlined.
+
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config display-ctu-progress=true \
+// RUN:   -analyzer-display-progress \
+// RUN:   -analyzer-config ctu-max-nodes-mul=0 \
+// RUN:   -analyzer-config ctu-max-nodes-min=0 2>&1 %s | FileCheck %s
+// CHECK: ANALYZE (Path,  Inline_Regular): {{.*}} baruser(int){{.*}}CTU loaded AST file
+
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config ctu-max-nodes-mul=0 \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
+// RUN:   -analyzer-config ctu-max-nodes-min=0 -verify=inline-none %s
+
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config ctu-max-nodes-mul=0 \
+// RUN:   -analyzer-config ctu-phase1-inlining=small \
+// RUN:   -analyzer-config ctu-max-nodes-min=0 -verify=inline-small %s
+
+
+void clang_analyzer_eval(int);
+
+void baruser(int x) {
+  int y = bar();
+  // inline-none-warning@+2{{UNKNOWN}}
+  // inline-small-warning@+1{{TRUE}}
+  clang_analyzer_eval(y == 0);
+}
Index: clang/test/Analysis/ctu-onego-indirect.cpp
===================================================================
--- clang/test/Analysis/ctu-onego-indirect.cpp
+++ clang/test/Analysis/ctu-onego-indirect.cpp
@@ -18,6 +18,7 @@
 // RUN:   -analyzer-config ctu-dir=%t/ctudir \
 // RUN:   -analyzer-display-progress \
 // RUN:   -analyzer-inlining-mode=all \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
 // RUN:   -analyzer-config ctu-max-nodes-mul=100 \
 // RUN:   -analyzer-config ctu-max-nodes-min=1000 2>&1 %s | FileCheck %s
 // CHECK: ANALYZE (Path,  Inline_Regular):{{.*}}adirectbaruser(int)
@@ -30,6 +31,7 @@
 // RUN:   -analyzer-config ctu-dir=%t/ctudir \
 // RUN:   -analyzer-display-progress \
 // RUN:   -analyzer-inlining-mode=all \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
 // RUN:   -verify %s \
 // RUN:   -analyzer-config ctu-max-nodes-mul=100 \
 // RUN:   -analyzer-config ctu-max-nodes-min=1000
Index: clang/test/Analysis/ctu-on-demand-parsing.cpp
===================================================================
--- clang/test/Analysis/ctu-on-demand-parsing.cpp
+++ clang/test/Analysis/ctu-on-demand-parsing.cpp
@@ -15,10 +15,10 @@
 //
 // RUN: cd "%t" && %clang_analyze_cc1 \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
-// RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=. \
 // RUN:   -analyzer-config ctu-invocation-list=invocations.yaml \
+// RUN:   -analyzer-config ctu-phase1-inlining=all \
 // RUN:   -verify ctu-on-demand-parsing.cpp
 // RUN: cd "%t" && %clang_analyze_cc1 \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
@@ -29,6 +29,10 @@
 //
 // CHECK: CTU loaded AST file: {{.*}}ctu-other.cpp
 // CHECK: CTU loaded AST file: {{.*}}ctu-chain.cpp
+
+// FIXME On-demand ctu should be tested in the very same file that we have for
+// the PCH version, but with a different a different verify prefix (e.g.
+// -verfiy=on-demanc-ctu)
 //
 // FIXME: Path handling should work on all platforms.
 // REQUIRES: system-linux
@@ -83,46 +87,30 @@
 void test_virtual_functions(mycls *obj) {
   // The dynamic type is known.
   clang_analyzer_eval(mycls().fvcl(1) == 8);   // expected-warning{{TRUE}}
-                                               // expected-warning@-1{{UNKNOWN}} stu
   clang_analyzer_eval(derived().fvcl(1) == 9); // expected-warning{{TRUE}}
-                                               // expected-warning@-1{{UNKNOWN}} stu
   // We cannot decide about the dynamic type.
-  clang_analyzer_eval(obj->fvcl(1) == 8);      // expected-warning{{TRUE}} ctu
-                                               // expected-warning@-1{{UNKNOWN}} ctu, stu
+  clang_analyzer_eval(obj->fvcl(1) == 8); // expected-warning{{FALSE}} expected-warning{{TRUE}}
+  clang_analyzer_eval(obj->fvcl(1) == 9); // expected-warning{{FALSE}} expected-warning{{TRUE}}
 }
 
 int main() {
-  clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(f(5) == 3); // expected-warning{{FALSE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(g(4) == 6); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(h(2) == 8); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-
-  clang_analyzer_eval(myns::fns(2) == 9);                   // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(myns::embed_ns::fens(2) == -1);       // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls().fcl(1) == 6);                 // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls::fscl(1) == 7);                 // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(myns::embed_cls().fecl(1) == -6);     // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls::embed_cls2().fecl2(0) == -11); // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-
-  clang_analyzer_eval(chns::chf1(4) == 12); // expected-warning{{TRUE}} ctu
-                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(fun_using_anon_struct(8) == 8); // expected-warning{{TRUE}} ctu
-                                                      // expected-warning@-1{{UNKNOWN}} stu
+  clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}}
+  clang_analyzer_eval(f(5) == 3); // expected-warning{{FALSE}}
+  clang_analyzer_eval(g(4) == 6); // expected-warning{{TRUE}}
+  clang_analyzer_eval(h(2) == 8); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(myns::fns(2) == 9);                   // expected-warning{{TRUE}}
+  clang_analyzer_eval(myns::embed_ns::fens(2) == -1);       // expected-warning{{TRUE}}
+  clang_analyzer_eval(mycls().fcl(1) == 6);                 // expected-warning{{TRUE}}
+  clang_analyzer_eval(mycls::fscl(1) == 7);                 // expected-warning{{TRUE}}
+  clang_analyzer_eval(myns::embed_cls().fecl(1) == -6);     // expected-warning{{TRUE}}
+  clang_analyzer_eval(mycls::embed_cls2().fecl2(0) == -11); // expected-warning{{TRUE}}
+
+  clang_analyzer_eval(chns::chf1(4) == 12);           // expected-warning{{TRUE}}
+  clang_analyzer_eval(fun_using_anon_struct(8) == 8); // expected-warning{{TRUE}}
 
   clang_analyzer_eval(other_macro_diag(1) == 1); // expected-warning{{TRUE}}
-                                                 // expected-warning@-1{{UNKNOWN}} stu
   // expected-warning@Inputs/ctu-other.cpp:93{{REACHABLE}}
   MACRODIAG(); // expected-warning{{REACHABLE}}
 }
Index: clang/test/Analysis/ctu-on-demand-parsing.c
===================================================================
--- clang/test/Analysis/ctu-on-demand-parsing.c
+++ clang/test/Analysis/ctu-on-demand-parsing.c
@@ -13,12 +13,16 @@
 //
 // RUN: cd "%t" && %clang_cc1 -fsyntax-only -std=c89 -analyze \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
-// RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=. \
 // RUN:   -analyzer-config ctu-invocation-list=invocations.yaml \
+// RUN:   -analyzer-config ctu-phase1-inlining=all \
 // RUN:   -verify ctu-on-demand-parsing.c
 //
+// FIXME On-demand ctu should be tested in the very same file that we have for
+// the PCH version, but with a different a different verify prefix (e.g.
+// -verfiy=on-demanc-ctu)
+//
 // FIXME: Path handling should work on all platforms.
 // REQUIRES: system-linux
 
@@ -33,7 +37,6 @@
 int f(int);
 void testGlobalVariable() {
   clang_analyzer_eval(f(5) == 1); // expected-warning{{TRUE}}
-                                  // expected-warning@-1{{UNKNOWN}} stu
 }
 
 // Test enums.
@@ -44,7 +47,6 @@
 void testEnum() {
   clang_analyzer_eval(x == 0);            // expected-warning{{TRUE}}
   clang_analyzer_eval(enumCheck() == 42); // expected-warning{{TRUE}}
-                                          // expected-warning@-1{{UNKNOWN}} stu
 }
 
 // Test that asm import does not fail.
@@ -64,7 +66,6 @@
 void testImplicit() {
   int res = identImplicit(6);    // external implicit functions are not inlined
   clang_analyzer_eval(res == 6); // expected-warning{{TRUE}}
-                                 // expected-warning@-1{{UNKNOWN}} stu
   // Call something with uninitialized from the same function in which the
   // implicit was called. This is necessary to reproduce a special bug in
   // NoStoreFuncVisitor.
@@ -83,6 +84,5 @@
   struct DataType d;
   d.a = 1;
   d.b = 0;
-  // Not imported, thus remains unknown both in stu and ctu.
-  clang_analyzer_eval(structInProto(&d) == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(structInProto(&d) == 0); // expected-warning{{TRUE}} expected-warning{{FALSE}}
 }
Index: clang/test/Analysis/ctu-main.cpp
===================================================================
--- clang/test/Analysis/ctu-main.cpp
+++ clang/test/Analysis/ctu-main.cpp
@@ -5,12 +5,25 @@
 // RUN: %clang_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
 // RUN:   -emit-pch -o %t/ctudir/ctu-chain.cpp.ast %S/Inputs/ctu-chain.cpp
 // RUN: cp %S/Inputs/ctu-other.cpp.externalDefMap.ast-dump.txt %t/ctudir/externalDefMap.txt
+
+// RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
+// RUN:   -verify=newctu %s
+
+// Simulate the behavior of the previous CTU implementation by inlining all
+// functions during the first phase. This way, the second phase is a noop.
 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
 // RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=%t/ctudir \
-// RUN:   -verify %s
+// RUN:   -analyzer-config ctu-phase1-inlining=all \
+// RUN:   -verify=oldctu %s
+
 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-pc-linux-gnu \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
@@ -114,13 +127,17 @@
 
 void test_virtual_functions(mycls* obj) {
   // The dynamic type is known.
-  clang_analyzer_eval(mycls().fvcl(1) == 8);   // expected-warning{{TRUE}} ctu
-                                               // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(derived().fvcl(1) == 9); // expected-warning{{TRUE}} ctu
-                                               // expected-warning@-1{{UNKNOWN}} stu
+  clang_analyzer_eval(mycls().fvcl(1) == 8);   // newctu-warning{{TRUE}} ctu
+                                               // newctu-warning@-1{{UNKNOWN}} stu
+                                               // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(derived().fvcl(1) == 9); // newctu-warning{{TRUE}} ctu
+                                               // newctu-warning@-1{{UNKNOWN}} stu
+                                               // oldctu-warning@-2{{TRUE}}
   // We cannot decide about the dynamic type.
-  clang_analyzer_eval(obj->fvcl(1) == 8);      // expected-warning{{TRUE}} ctu
-                                               // expected-warning@-1{{UNKNOWN}} ctu, stu
+  clang_analyzer_eval(obj->fvcl(1) == 8);      // newctu-warning{{TRUE}} ctu
+                                               // newctu-warning@-1{{UNKNOWN}} ctu, stu
+                                               // oldctu-warning@-2{{TRUE}}
+                                               // oldctu-warning@-3{{UNKNOWN}}
 }
 
 class TestAnonUnionUSR {
@@ -141,62 +158,92 @@
 extern int testImportOfDelegateConstructor(int);
 
 int main() {
-  clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(f(5) == 3); // expected-warning{{FALSE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(g(4) == 6); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(h(2) == 8); // expected-warning{{TRUE}} ctu
-                                  // expected-warning@-1{{UNKNOWN}} stu
-
-  clang_analyzer_eval(myns::fns(2) == 9);                   // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(myns::embed_ns::fens(2) == -1);       // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls().fcl(1) == 6);                 // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls::fscl(1) == 7);                 // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(myns::embed_cls().fecl(1) == -6);     // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(mycls::embed_cls2().fecl2(0) == -11); // expected-warning{{TRUE}} ctu
-                                                            // expected-warning@-1{{UNKNOWN}} stu
-
-  clang_analyzer_eval(chns::chf1(4) == 12); // expected-warning{{TRUE}} ctu
-                                            // expected-warning@-1{{UNKNOWN}} stu
-  clang_analyzer_eval(fun_using_anon_struct(8) == 8); // expected-warning{{TRUE}} ctu
-                                                      // expected-warning@-1{{UNKNOWN}} stu
-
-  clang_analyzer_eval(other_macro_diag(1) == 1); // expected-warning{{TRUE}} ctu
-                                                 // expected-warning@-1{{UNKNOWN}} stu
-  // expected-warning@Inputs/ctu-other.cpp:93{{REACHABLE}}
-  MACRODIAG(); // expected-warning{{REACHABLE}}
+  clang_analyzer_eval(f(3) == 2); // newctu-warning{{TRUE}} ctu
+                                  // newctu-warning@-1{{UNKNOWN}} stu
+                                  // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(f(4) == 3); // newctu-warning{{TRUE}} ctu
+                                  // newctu-warning@-1{{UNKNOWN}} stu
+                                  // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(f(5) == 3); // newctu-warning{{FALSE}} ctu
+                                  // newctu-warning@-1{{UNKNOWN}} stu
+                                  // oldctu-warning@-2{{FALSE}}
+  clang_analyzer_eval(g(4) == 6); // newctu-warning{{TRUE}} ctu
+                                  // newctu-warning@-1{{UNKNOWN}} stu
+                                  // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(h(2) == 8); // newctu-warning{{TRUE}} ctu
+                                  // newctu-warning@-1{{UNKNOWN}} stu
+                                  // oldctu-warning@-2{{TRUE}}
+
+  clang_analyzer_eval(myns::fns(2) == 9);                   // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(myns::embed_ns::fens(2) == -1);       // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(mycls().fcl(1) == 6);                 // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(mycls::fscl(1) == 7);                 // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(myns::embed_cls().fecl(1) == -6);     // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(mycls::embed_cls2().fecl2(0) == -11); // newctu-warning{{TRUE}} ctu
+                                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                                            // oldctu-warning@-2{{TRUE}}
+
+  clang_analyzer_eval(chns::chf1(4) == 12); // newctu-warning{{TRUE}} ctu
+                                            // newctu-warning@-1{{UNKNOWN}} stu
+                                            // oldctu-warning@-2{{TRUE}}
+  clang_analyzer_eval(fun_using_anon_struct(8) == 8); // newctu-warning{{TRUE}} ctu
+                                                      // newctu-warning@-1{{UNKNOWN}} stu
+                                                      // oldctu-warning@-2{{TRUE}}
+
+  clang_analyzer_eval(other_macro_diag(1) == 1); // newctu-warning{{TRUE}} ctu
+                                                 // newctu-warning@-1{{UNKNOWN}} stu
+                                                 // oldctu-warning@-2{{TRUE}}
+  // newctu-warning@Inputs/ctu-other.cpp:93{{REACHABLE}}
+  // oldctu-warning@Inputs/ctu-other.cpp:93{{REACHABLE}}
+  MACRODIAG(); // newctu-warning{{REACHABLE}}
+               // oldctu-warning@-1{{REACHABLE}}
 
   // FIXME we should report an UNKNOWN as well for all external variables!
-  clang_analyzer_eval(extInt == 2); // expected-warning{{TRUE}}
-  clang_analyzer_eval(intns::extInt == 3); // expected-warning{{TRUE}}
-  clang_analyzer_eval(extS.a == 4); // expected-warning{{TRUE}}
-  clang_analyzer_eval(extNonConstS.a == 4); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(extInt == 2); // newctu-warning{{TRUE}}
+                                    // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(intns::extInt == 3); // newctu-warning{{TRUE}}
+                                           // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(extS.a == 4); // newctu-warning{{TRUE}}
+                                    // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(extNonConstS.a == 4); // newctu-warning{{UNKNOWN}}
+                                            // oldctu-warning@-1{{UNKNOWN}}
   // Do not import non-trivial classes' initializers.
-  clang_analyzer_eval(extNTS.a == 4); // expected-warning{{UNKNOWN}}
-  clang_analyzer_eval(extHere == 6); // expected-warning{{TRUE}}
-  clang_analyzer_eval(A::a == 3); // expected-warning{{TRUE}}
-  clang_analyzer_eval(extSC.a == 8); // expected-warning{{TRUE}}
-  clang_analyzer_eval(ST::sc.a == 2); // expected-warning{{TRUE}}
+  clang_analyzer_eval(extNTS.a == 4); // newctu-warning{{UNKNOWN}}
+                                      // oldctu-warning@-1{{UNKNOWN}}
+  clang_analyzer_eval(extHere == 6); // newctu-warning{{TRUE}}
+                                     // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(A::a == 3); // newctu-warning{{TRUE}}
+                                  // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(extSC.a == 8); // newctu-warning{{TRUE}}
+                                     // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(ST::sc.a == 2); // newctu-warning{{TRUE}}
+                                      // oldctu-warning@-1{{TRUE}}
   // clang_analyzer_eval(extSCN.scn.a == 9); // TODO
-  clang_analyzer_eval(extSubSCN.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(extSubSCN.a == 1); // newctu-warning{{TRUE}}
+                                         // oldctu-warning@-1{{TRUE}}
   // clang_analyzer_eval(extSCC.a == 7); // TODO
-  clang_analyzer_eval(extU.a == 4); // expected-warning{{TRUE}}
-  clang_analyzer_eval(TestAnonUnionUSR::Test == 5); // expected-warning{{TRUE}}
+  clang_analyzer_eval(extU.a == 4); // newctu-warning{{TRUE}}
+                                    // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(TestAnonUnionUSR::Test == 5); // newctu-warning{{TRUE}}
+                                                    // oldctu-warning@-1{{TRUE}}
 
   clang_analyzer_eval(testImportOfIncompleteDefaultParmDuringImport(9) == 9);
-  // expected-warning@-1{{TRUE}} ctu
-  // expected-warning@-2{{UNKNOWN}} stu
+  // newctu-warning@-1{{TRUE}} ctu
+  // newctu-warning@-2{{UNKNOWN}} stu
+  // oldctu-warning@-3{{TRUE}}
 
   clang_analyzer_eval(testImportOfDelegateConstructor(10) == 10);
-  // expected-warning@-1{{TRUE}} ctu
-  // expected-warning@-2{{UNKNOWN}} stu
+  // newctu-warning@-1{{TRUE}} ctu
+  // newctu-warning@-2{{UNKNOWN}} stu
+  // oldctu-warning@-3{{TRUE}}
 }
Index: clang/test/Analysis/ctu-main.c
===================================================================
--- clang/test/Analysis/ctu-main.c
+++ clang/test/Analysis/ctu-main.c
@@ -3,12 +3,24 @@
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \
 // RUN:   -emit-pch -o %t/ctudir2/ctu-other.c.ast %S/Inputs/ctu-other.c
 // RUN: cp %S/Inputs/ctu-other.c.externalDefMap.ast-dump.txt %t/ctudir2/externalDefMap.txt
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -std=c89 -analyze \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config eagerly-assume=false \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir2 \
+// RUN:   -analyzer-config ctu-phase1-inlining=none \
+// RUN:   -verify=newctu %s
+
+// Simulate the behavior of the previous CTU implementation by inlining all
+// functions during the first phase. This way, the second phase is a noop.
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -std=c89 -analyze \
 // RUN:   -analyzer-checker=core,debug.ExprInspection \
 // RUN:   -analyzer-config eagerly-assume=false \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config ctu-dir=%t/ctudir2 \
-// RUN:   -verify %s
+// RUN:   -analyzer-config ctu-phase1-inlining=all \
+// RUN:   -verify=oldctu %s
 
 void clang_analyzer_eval(int);
 
@@ -17,7 +29,8 @@
 int unknown(int);
 void test_unknown() {
   int res = unknown(6);
-  clang_analyzer_eval(res == 6); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(res == 6); // newctu-warning{{UNKNOWN}}
+                                 // oldctu-warning@-1{{UNKNOWN}}
 }
 
 // Test typedef and global variable in function.
@@ -28,8 +41,9 @@
 extern FooBar fb;
 int f(int);
 void testGlobalVariable() {
-  clang_analyzer_eval(f(5) == 1);         // expected-warning{{TRUE}} ctu
-                                          // expected-warning@-1{{UNKNOWN}} stu
+  clang_analyzer_eval(f(5) == 1);         // newctu-warning{{TRUE}} ctu
+                                          // newctu-warning@-1{{UNKNOWN}} stu
+                                          // oldctu-warning@-2{{TRUE}}
 }
 
 // Test enums.
@@ -38,9 +52,11 @@
          y,
          z };
 void testEnum(void) {
-  clang_analyzer_eval(x == 0);            // expected-warning{{TRUE}}
-  clang_analyzer_eval(enumCheck() == 42); // expected-warning{{TRUE}} ctu
-                                          // expected-warning@-1{{UNKNOWN}} stu
+  clang_analyzer_eval(x == 0);            // newctu-warning{{TRUE}}
+                                          // oldctu-warning@-1{{TRUE}}
+  clang_analyzer_eval(enumCheck() == 42); // newctu-warning{{TRUE}} ctu
+                                          // newctu-warning@-1{{UNKNOWN}} stu
+                                          // oldctu-warning@-2{{TRUE}}
 }
 
 // Test that asm import does not fail.
@@ -53,19 +69,22 @@
 struct S;
 int g(struct S *);
 void testMacro(void) {
-  g(0); // expected-warning@Inputs/ctu-other.c:29 {{Access to field 'a' results in a dereference of a null pointer (loaded from variable 'ctx')}}
+  g(0); // newctu-warning@Inputs/ctu-other.c:29 {{Access to field 'a' results in a dereference of a null pointer (loaded from variable 'ctx')}}
+        // oldctu-warning@Inputs/ctu-other.c:29 {{Access to field 'a' results in a dereference of a null pointer (loaded from variable 'ctx')}}
 }
 
 // The external function prototype is incomplete.
 // warning:implicit functions are prohibited by c99
 void testImplicit(void) {
   int res = identImplicit(6);   // external implicit functions are not inlined
-  clang_analyzer_eval(res == 6); // expected-warning{{TRUE}} ctu
-                                 // expected-warning@-1{{UNKNOWN}} stu
+  clang_analyzer_eval(res == 6); // newctu-warning{{TRUE}} ctu
+                                 // newctu-warning@-1{{UNKNOWN}} stu
+                                 // oldctu-warning@-2{{TRUE}}
   // Call something with uninitialized from the same function in which the implicit was called.
   // This is necessary to reproduce a special bug in NoStoreFuncVisitor.
   int uninitialized;
-  h(uninitialized); // expected-warning{{1st function call argument is an uninitialized value}}
+  h(uninitialized); // newctu-warning{{1st function call argument is an uninitialized value}}
+                    // oldctu-warning@-1{{1st function call argument is an uninitialized value}}
 }
 
 // Tests the import of functions that have a struct parameter
@@ -80,7 +99,8 @@
   d.a = 1;
   d.b = 0;
   // Not imported, thus remains unknown both in stu and ctu.
-  clang_analyzer_eval(structInProto(&d) == 0); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(structInProto(&d) == 0); // newctu-warning{{UNKNOWN}}
+                                               // oldctu-warning@-1{{UNKNOWN}}
 }
 
 int switchWithoutCases(int);
Index: clang/test/Analysis/analyzer-config.c
===================================================================
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -51,6 +51,7 @@
 // CHECK-NEXT: ctu-invocation-list = invocations.yaml
 // CHECK-NEXT: ctu-max-nodes-min = 1000
 // CHECK-NEXT: ctu-max-nodes-mul = 100
+// CHECK-NEXT: ctu-phase1-inlining = small
 // CHECK-NEXT: deadcode.DeadStores:ShowFixIts = false
 // CHECK-NEXT: deadcode.DeadStores:WarnForDeadNestedAssignments = true
 // CHECK-NEXT: debug.AnalysisOrder:* = false
Index: clang/test/Analysis/Inputs/ctu-onego-small-other.cpp.externalDefMap.ast-dump.txt
===================================================================
--- /dev/null
+++ clang/test/Analysis/Inputs/ctu-onego-small-other.cpp.externalDefMap.ast-dump.txt
@@ -0,0 +1 @@
+9:c:@F@bar# ctu-onego-small-other.cpp.ast
Index: clang/test/Analysis/Inputs/ctu-onego-small-other.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/Inputs/ctu-onego-small-other.cpp
@@ -0,0 +1,3 @@
+int bar() {
+  return 0;
+}
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -435,6 +435,14 @@
   ProgramStateRef ConservativeEvalState = nullptr;
   WorkList *CTUWList = Engine.getCTUWorkList();
   if (Call.isForeign() && CTUWList) {
+    const auto IK = AMgr.options.getCTUPhase1Inlining();
+    const bool DoInline = IK == CTUPhase1InliningKind::All ||
+                          (IK == CTUPhase1InliningKind::Small &&
+                           isSmall(AMgr.getAnalysisDeclContext(D)));
+    if (DoInline) {
+      inlineCall(Engine.getWorkList(), Call, D, Bldr, Pred, State);
+      return true;
+    }
     const bool BState = State->contains<CTUDispatchBifurcationSet>(D);
     if (!BState) { // This is the first time we see this foreign function.
       // Enqueue it to be analyzed in the second (ctu) phase.
Index: clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -81,6 +81,17 @@
   return K.getValue();
 }
 
+CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
+  auto K = llvm::StringSwitch<llvm::Optional<CTUPhase1InliningKind>>(
+               CTUPhase1InliningMode)
+               .Case("none", CTUPhase1InliningKind::None)
+               .Case("small", CTUPhase1InliningKind::Small)
+               .Case("all", CTUPhase1InliningKind::All)
+               .Default(None);
+  assert(K.hasValue() && "CTU inlining mode is invalid.");
+  return K.getValue();
+}
+
 IPAKind AnalyzerOptions::getIPAMode() const {
   auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
           .Case("none", IPAK_None)
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -138,6 +138,8 @@
   UMK_Deep = 2
 };
 
+enum class CTUPhase1InliningKind { None, Small, All };
+
 /// Stores options for the analyzer from the command line.
 ///
 /// Some options are frontend flags (e.g.: -analyzer-output), but some are
@@ -379,6 +381,7 @@
   UserModeKind getUserMode() const;
 
   ExplorationStrategyKind getExplorationStrategy() const;
+  CTUPhase1InliningKind getCTUPhase1Inlining() const;
 
   /// Returns the inter-procedural analysis mode.
   IPAKind getIPAMode() const;
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -425,6 +425,13 @@
     "is too low, it is meaningful to provide a minimum value that serves as an "
     "upper bound instead.", 1000)
 
+ANALYZER_OPTION(
+    StringRef, CTUPhase1InliningMode, "ctu-phase1-inlining",
+    "Controls which functions will be inlined during the first phase of the ctu "
+    "analysis."
+    "Value: \"none\", \"small\", \"all\".",
+    "small")
+
 ANALYZER_OPTION(
     unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit",
     "The largest number of fields a struct can have and still be considered "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to