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 @@ -17,6 +17,7 @@ #include "clang/AST/ASTImporterSharedState.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Error.h" @@ -159,7 +160,7 @@ ASTUnit *Unit); /// Get a name to identify a named decl. - static std::string getLookupName(const NamedDecl *ND); + static llvm::Optional getLookupName(const NamedDecl *ND); /// Emit diagnostics for the user for potential configuration errors. void emitCrossTUDiagnostics(const IndexError &IE); 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 @@ -193,12 +193,13 @@ CrossTranslationUnitContext::~CrossTranslationUnitContext() {} -std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { +llvm::Optional +CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { SmallString<128> DeclUSR; bool Ret = index::generateUSRForDecl(ND, DeclUSR); - (void)Ret; - assert(!Ret && "Unable to generate USR"); - return DeclUSR.str(); + if (Ret) + return {}; + return std::string(DeclUSR.str()); } /// Recursively visits the decls of a DeclContext, and returns one with the @@ -218,7 +219,8 @@ const T *ResultDecl; if (!ND || !hasBodyOrInit(ND, ResultDecl)) continue; - if (getLookupName(ResultDecl) != LookupName) + llvm::Optional ResultLookupName = getLookupName(ResultDecl); + if (!ResultLookupName || *ResultLookupName != LookupName) continue; return ResultDecl; } @@ -233,12 +235,12 @@ assert(!hasBodyOrInit(D) && "D has a body or init in current translation unit!"); ++NumGetCTUCalled; - const std::string LookupName = getLookupName(D); - if (LookupName.empty()) + const llvm::Optional LookupName = getLookupName(D); + if (!LookupName) return llvm::make_error( index_error_code::failed_to_generate_usr); llvm::Expected ASTUnitOrError = - loadExternalAST(LookupName, CrossTUDir, IndexName, DisplayCTUProgress); + loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress); if (!ASTUnitOrError) return ASTUnitOrError.takeError(); ASTUnit *Unit = *ASTUnitOrError; @@ -294,7 +296,7 @@ } TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); - if (const T *ResultDecl = findDefInDeclContext(TU, LookupName)) + if (const T *ResultDecl = findDefInDeclContext(TU, *LookupName)) return importDefinition(ResultDecl, Unit); return llvm::make_error(index_error_code::failed_import); } 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 @@ -131,3 +131,17 @@ const unsigned int b; }; U extU = {.a = 4}; + +class TestAnonUnionUSR { +public: + inline float f(int value) { + union { + float f; + int i; + }; + i = value; + return f; + } + static const int Test; +}; +const int TestAnonUnionUSR::Test = 5; diff --git a/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt b/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt --- a/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt +++ b/clang/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt @@ -25,3 +25,4 @@ c:@extSubSCN ctu-other.cpp.ast c:@extSCC ctu-other.cpp.ast c:@extU ctu-other.cpp.ast +c:@S@TestAnonUnionUSR@Test 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 @@ -112,6 +112,19 @@ clang_analyzer_eval(obj->fvcl(1) == 8); // expected-warning{{FALSE}} expected-warning{{TRUE}} } +class TestAnonUnionUSR { +public: + inline float f(int value) { + union { + float f; + int i; + }; + i = value; + return f; + } + static const int Test; +}; + int main() { clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}} clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}} @@ -144,4 +157,5 @@ clang_analyzer_eval(extSubSCN.a == 1); // expected-warning{{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}} } 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 @@ -41,3 +41,10 @@ }; U u = {.a = 6}; // CHECK-DAG: c:@u + +// No USR can be generated for this. +// Check for no crash in this case. +static union { + float uf; + const int ui; +}; 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 @@ -76,7 +76,12 @@ void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart) { - std::string LookupName = CrossTranslationUnitContext::getLookupName(DD); + llvm::Optional LookupName = + CrossTranslationUnitContext::getLookupName(DD); + if (!LookupName) + return; + assert(!LookupName->empty() && "Lookup name should be non-empty."); + if (CurrentFileName.empty()) { CurrentFileName = SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName(); @@ -89,7 +94,7 @@ case VisibleNoLinkage: case UniqueExternalLinkage: if (SM.isInMainFile(defStart)) - Index[LookupName] = CurrentFileName; + Index[*LookupName] = CurrentFileName; break; default: break;