diff --git a/clang/include/clang/CrossTU/CrossTranslationUnit.h b/clang/include/clang/CrossTU/CrossTranslationUnit.h --- a/clang/include/clang/CrossTU/CrossTranslationUnit.h +++ b/clang/include/clang/CrossTU/CrossTranslationUnit.h @@ -109,8 +109,10 @@ StringRef FileContent, llvm::sys::path::Style PathStyle = llvm::sys::path::Style::posix); -// Returns true if the variable or any field of a record variable is const. -bool containsConst(const VarDecl *VD, const ASTContext &ACtx); +/// Returns true if it makes sense to import a foreign variable definition. +/// For instance, we don't want to import variables that have non-trivial types +/// because the constructor might have side-effects. +bool shouldImport(const VarDecl *VD, const ASTContext &ACtx); /// This class is used for tools that requires cross translation /// unit capability. diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -220,14 +220,9 @@ return Result.str(); } -bool containsConst(const VarDecl *VD, const ASTContext &ACtx) { +bool shouldImport(const VarDecl *VD, const ASTContext &ACtx) { CanQualType CT = ACtx.getCanonicalType(VD->getType()); - if (!CT.isConstQualified()) { - const RecordType *RTy = CT->getAs(); - if (!RTy || !RTy->hasConstFields()) - return false; - } - return true; + return CT.isConstQualified() && VD->getType().isTrivialType(ACtx); } static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) { diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -289,7 +289,7 @@ return true; if (VD->hasExternalStorage() || VD->isStaticDataMember()) { - if (!cross_tu::containsConst(VD, *Ctx)) + if (!cross_tu::shouldImport(VD, *Ctx)) return true; } else { // Cannot be initialized in another TU. diff --git a/clang/test/Analysis/Inputs/ctu-other.cpp b/clang/test/Analysis/Inputs/ctu-other.cpp --- a/clang/test/Analysis/Inputs/ctu-other.cpp +++ b/clang/test/Analysis/Inputs/ctu-other.cpp @@ -102,6 +102,12 @@ int a; }; extern const S extS = {.a = 4}; +extern S extNonConstS = {.a = 4}; +struct NonTrivialS { + int a; + ~NonTrivialS(); +}; +extern const NonTrivialS extNTS = {.a = 4}; struct A { static const int a; }; @@ -109,18 +115,18 @@ struct SC { const int a; }; -SC extSC = {.a = 8}; +extern const SC extSC = {.a = 8}; struct ST { - static struct SC sc; + static const struct SC sc; }; -struct SC ST::sc = {.a = 2}; +const struct SC ST::sc = {.a = 2}; struct SCNest { struct SCN { const int a; } scn; }; SCNest extSCN = {.scn = {.a = 9}}; -SCNest::SCN extSubSCN = {.a = 1}; +extern SCNest::SCN const extSubSCN = {.a = 1}; struct SCC { SCC(int c) : a(c) {} const int a; @@ -130,7 +136,7 @@ const int a; const unsigned int b; }; -U extU = {.a = 4}; +extern const U extU = {.a = 4}; class TestAnonUnionUSR { public: diff --git a/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.ast-dump.txt b/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.ast-dump.txt --- a/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.ast-dump.txt +++ b/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.ast-dump.txt @@ -18,6 +18,7 @@ 9:c:@extInt ctu-other.cpp.ast 17:c:@N@intns@extInt ctu-other.cpp.ast 7:c:@extS ctu-other.cpp.ast +9:c:@extNTS ctu-other.cpp.ast 8:c:@S@A@a ctu-other.cpp.ast 8:c:@extSC ctu-other.cpp.ast 10:c:@S@ST@sc ctu-other.cpp.ast diff --git a/clang/test/Analysis/ctu-main.cpp b/clang/test/Analysis/ctu-main.cpp --- a/clang/test/Analysis/ctu-main.cpp +++ b/clang/test/Analysis/ctu-main.cpp @@ -74,6 +74,13 @@ int a; }; extern const S extS; +extern S extNonConstS; +struct NonTrivialS { + int a; + // User declaring a dtor makes it non-trivial. + ~NonTrivialS(); +}; +extern const NonTrivialS extNTS; extern const int extHere; const int extHere = 6; struct A { @@ -82,9 +89,9 @@ struct SC { const int a; }; -extern SC extSC; +extern const SC extSC; struct ST { - static struct SC sc; + static const struct SC sc; }; struct SCNest { struct SCN { @@ -92,7 +99,7 @@ } scn; }; extern SCNest extSCN; -extern SCNest::SCN extSubSCN; +extern const SCNest::SCN extSubSCN; struct SCC { SCC(int c); const int a; @@ -102,7 +109,7 @@ const int a; const unsigned int b; }; -extern U extU; +extern const U extU; void test_virtual_functions(mycls* obj) { // The dynamic type is known. @@ -153,6 +160,9 @@ 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{{TRUE}} expected-warning{{FALSE}} + // Do not import non-trivial classes' initializers. + clang_analyzer_eval(extNTS.a == 4); // expected-warning{{TRUE}} expected-warning{{FALSE}} 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}} diff --git a/clang/test/Analysis/func-mapping-test.cpp b/clang/test/Analysis/func-mapping-test.cpp --- a/clang/test/Analysis/func-mapping-test.cpp +++ b/clang/test/Analysis/func-mapping-test.cpp @@ -23,7 +23,7 @@ struct SF { const int a; }; -SF sf = {.a = 2}; +extern const SF sf = {.a = 2}; // CHECK-DAG: 5:c:@sf struct SStatic { @@ -39,7 +39,7 @@ const int a; const unsigned int b; }; -U u = {.a = 6}; +extern const U u = {.a = 6}; // CHECK-DAG: 4:c:@u // No USR can be generated for this. diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp --- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp +++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp @@ -64,7 +64,7 @@ if (const Stmt *Body = FD->getBody()) addIfInMain(FD, Body->getBeginLoc()); } else if (const auto *VD = dyn_cast(D)) { - if (cross_tu::containsConst(VD, Ctx) && VD->hasInit()) + if (cross_tu::shouldImport(VD, Ctx) && VD->hasInit()) if (const Expr *Init = VD->getInit()) addIfInMain(VD, Init->getBeginLoc()); }